1% ----------------------------------------------------------------------
2% BEGIN LICENSE BLOCK
3% Version: CMPL 1.1
4%
5% The contents of this file are subject to the Cisco-style Mozilla Public
6% License Version 1.1 (the "License"); you may not use this file except
7% in compliance with the License.  You may obtain a copy of the License
8% at www.eclipse-clp.org/license.
9%
10% Software distributed under the License is distributed on an "AS IS"
11% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
12% the License for the specific language governing rights and limitations
13% under the License.
14%
15% The Original Code is  The ECLiPSe Constraint Logic Programming System.
16% The Initial Developer of the Original Code is  Cisco Systems, Inc.
17% Portions created by the Initial Developer are
18% Copyright (C) 1995-2006 Cisco Systems, Inc.  All Rights Reserved.
19%
20% Contributor(s): IC-Parc, Imperal College London
21%
22% END LICENSE BLOCK
23%
24% System:	ECLiPSe Constraint Logic Programming System
25% Version:	$Id: matrix_util.pl,v 1.3 2015/01/14 01:31:09 jschimpf Exp $
26% ----------------------------------------------------------------------
27
28:- module(matrix_util).
29
30:- comment(categories, ["Data Structures","Programming Utilities"]).
31:- comment(summary, "Predicates to build matrices from lists").
32:- comment(author, "Joachim Schimpf, IC-Parc").
33:- comment(copyright, "Cisco Systems, Inc").
34:- comment(date, "$Date: 2015/01/14 01:31:09 $").
35:- comment(desc, html(
36	"<p>This library contains predicates for representing and manipulating "
37	"matrices as nested lists.  Both list of rows and list of columns "
38	"can be created and mapped into each other."
39	"</p><p>"
40	"Note that newer versions of ECLiPSe have good support for representing "
41	"matrices as multi-dimensional arrays, which is often preferrable to "
42	"the list representation used here.</p>"
43    )).
44
45:- comment(matrix/3, [
46    summary:"Create a matrix as a list of rows",
47    template:"matrix(+NRow, +NCols, -Rows)",
48    eg:"
49    ?- matrix(2,3,M).
50    M = [[_175, _177, _179], [_183, _185, _187]]
51    Yes (0.00s cpu)
52    "]).
53:- comment(matrix/4, [
54    summary:"Create a matrix as both a list of rows and a list of columns",
55    template:"matrix(+NRows, +NCols, -Rows, -Cols)",
56    eg:"
57    ?- matrix(2,3,Rows,Cols).
58    Rows = [[_183, _185, _187], [_191, _193, _195]]
59    Cols = [[_183, _191], [_185, _193], [_187, _195]]
60    Yes (0.00s cpu)
61    "]).
62:- comment(list2rows/4, [
63    summary:"Create a matrix from a flat list of row-wise listed elements",
64    template:"list2rows(+List, +NRows, +NCols, -Rows)",
65    eg:"
66    ?- list2rows([1,2,3,4,5,6],2,3,Rows).
67    Rows = [[1, 2, 3], [4, 5, 6]]
68    Yes (0.00s cpu)
69    "]).
70:- comment(list2cols/4, [
71    summary:"Create a matrix from a flat list of row-wise listed elements",
72    template:"list2cols(+List, +NRows, +NCols, -Cols)",
73    eg:"
74    ?- list2cols([1,2,3,4,5,6],2,3,Cols).
75    Cols = [[1, 4], [2, 5], [3, 6]]
76    Yes (0.00s cpu)
77    "]).
78:- comment(transpose/2, [
79    summary:"Transpose a matrix (list of rows or list of columns)",
80    template:"transpose(+Matrix, -Transposed)",
81    eg:"
82    ?- list2rows([1,2,3,4,5,6],2,3,Rows), transpose(Rows,Cols).
83    Rows = [[1, 2, 3], [4, 5, 6]]
84    Cols = [[1, 4], [2, 5], [3, 6]]
85    Yes (0.00s cpu)
86    "]).
87:- comment(concat/2, [
88    summary:"Concatenate all the rows (or columns) into a flat list",
89    template:"concat(+RowsOrCols, -List)",
90    see_also:[list2rows/4,list2cols/4,transpose/2],
91    eg:"
92    ?- list2rows([1,2,3,4,5,6],2,3,Rows), concat(Rows,Xs).
93    Rows = [[1, 2, 3], [4, 5, 6]]
94    Xs = [1, 2, 3, 4, 5, 6]
95    Yes (0.00s cpu)
96    "]).
97:- comment(read_data/3, [
98    summary:"Read numbers from a file into List",
99    desc:html("Read numbers from a file into List until either the list is full or
100    the end of file has been reached. In the first case, not all numbers in the
101    file may be read, in the second, the list may not be fully instantiated.
102    The count of numbers that have actually been read is returned in Length.
103    "),
104    template:"read_data(+File, ?List, -Length)",
105    see_also:[list2rows/4,list2cols/4,transpose/2]
106    ]).
107
108:- export
109	matrix/3,	% matrix(+NRow, +NCol, -Rows)
110	matrix/4,	% matrix(+NRow, +NCol, -Rows, -Cols)
111	list2rows/4,	% list2rows(+List, +NRows, +NCols, -Rows)
112	list2cols/4,	% list2cols(+List, +NRows, +NCols, -Cols)
113	transpose/2,	% transpose(+Rows, -Cols) or transpose(+Cols, -Rows)
114	concat/2,	% concat(+RowsOrCols, -List)
115	read_data/3.	% read_data(+File, ?List, -Length)
116
117
118
119matrix(NRow, NCol, Rows, Cols) :-
120	matrix(NRow, NCol, Rows),
121	transpose(Rows, Cols).
122
123matrix(0, _NCol, LoL) :- !, LoL=[].
124matrix(NRow, NCol, [L|LoL1]) :-
125	integer(NRow), NRow > 0,
126	NRow1 is NRow-1,
127	length(L, NCol),
128	matrix(NRow1, NCol, LoL1).
129
130list2matrix([], 0, _NCol, []) :- !.
131list2matrix(List, NRow, NCol, [Row|Rows]) :-
132	integer(NRow), NRow > 0,
133	NRow1 is NRow-1,
134	first_n(NCol, List, Row, Rest),
135	list2matrix(Rest, NRow1, NCol, Rows).
136
137first_n(0, L, [], L) :- !.
138first_n(N, [X|Xs], [X|Fs], Rest) :-
139	N1 is N-1,
140	first_n(N1, Xs, Fs, Rest).
141
142list2rows([], 0, _, []) :- !.
143list2rows(List, NRow, NCol, [Row|Rows]) :-
144	plus(NRow1,1,NRow),
145	first_n(NCol, List, Row, Rest),
146	list2rows(Rest, NRow1, NCol, Rows).
147
148list2cols(List, NRow, NCol, Cols) :-
149	list2rows(List, NRow, NCol, Rows),
150	transpose(Rows, Cols).
151
152transpose([], []).
153transpose(LoL, Cols) :-
154	heads_and_tails(LoL, Col, LoL1),
155	( Col == [] ->
156	    Cols = []
157	;
158	    Cols = [Col|Cols0],
159	    transpose(LoL1, Cols0)
160	).
161
162heads_and_tails([], [], []).
163heads_and_tails([L|Ls], Hs, Ts) :-
164	( L == [] ->
165	    Hs = Hs0, Ts = Ts0
166	;
167	    L = [H|T], Hs = [H|Hs0], Ts = [T|Ts0]
168	),
169	heads_and_tails(Ls, Hs0, Ts0).
170
171concat([], []).
172concat([L|Ls], C) :-
173	concat(L, C, C0),
174	concat(Ls, C0).
175
176concat([], L, L).
177concat([X|Xs], [X|Ys], L) :-
178	concat(Xs, Ys, L).
179
180% read numbers until list is full or end of file.
181
182read_data(File, L, N) :-
183	open(File, read, Stream),
184	read_floats(Stream, L, 0, N),
185	close(Stream).
186
187read_floats(Stream, [X|Xs], N0, N) :-
188	read_token(Stream, Token, _),
189	( number(Token) ->
190	    !,	% if called with a variable
191	    X is float(Token),
192	    N1 is N0+1,
193	    read_floats(Stream, Xs, N1, N)
194	;
195	    Token \= end_of_file,
196	    get_stream_info(Stream, name, Name),
197	    get_stream_info(Stream, line, Line),
198	    printf(error, "Syntax error in file \"%w\", line %d: %w\n",
199	    		[Name, Line, Token]),
200	    close(Stream),
201	    abort
202	).
203read_floats(_Stream, [], N, N).
204
205
206