Chris@5
|
1
|
Chris@94
|
2 module yetilab.matrix.matrix;
|
Chris@94
|
3
|
Chris@94
|
4 // A matrix is an array of fvectors (i.e. primitive double[]s).
|
Chris@94
|
5
|
Chris@94
|
6 // A matrix can be either RowMajor, akin to a C multidimensional array
|
Chris@96
|
7 // in which each row is a separate fvector, or ColumnMajor, akin to a
|
Chris@94
|
8 // FORTAN multidimensional array in which each column is a separate
|
Chris@96
|
9 // fvector. The default is ColumnMajor. Storage order is an efficiency
|
Chris@94
|
10 // concern only, all operations behave identically regardless. (The
|
Chris@94
|
11 // transpose function just switches the row/column order without
|
Chris@94
|
12 // moving the elements.)
|
Chris@18
|
13
|
Chris@93
|
14 vec = load yetilab.block.fvector;
|
Chris@96
|
15 block = load yetilab.block.block;
|
Chris@9
|
16
|
Chris@96
|
17 make d = {
|
Chris@96
|
18 get data () = d,
|
Chris@96
|
19 get size () =
|
Chris@96
|
20 case d of
|
Chris@96
|
21 RowM r:
|
Chris@96
|
22 major = length r;
|
Chris@96
|
23 {
|
Chris@96
|
24 rows = major,
|
Chris@96
|
25 columns = if major > 0 then vec.length r[0] else 0 fi,
|
Chris@96
|
26 };
|
Chris@96
|
27 ColM c:
|
Chris@96
|
28 major = length c;
|
Chris@96
|
29 {
|
Chris@96
|
30 rows = if major > 0 then vec.length c[0] else 0 fi,
|
Chris@96
|
31 columns = major,
|
Chris@96
|
32 };
|
Chris@94
|
33 esac,
|
Chris@96
|
34 getColumn j =
|
Chris@96
|
35 case d of
|
Chris@96
|
36 RowM rows: block.fromList (map do i: getAt i j done [0..length rows-1]);
|
Chris@96
|
37 ColM cols: block.block cols[j];
|
Chris@94
|
38 esac,
|
Chris@96
|
39 getRow i =
|
Chris@96
|
40 case d of
|
Chris@96
|
41 RowM rows: block.block rows[i];
|
Chris@96
|
42 ColM cols: block.fromList (map do j: getAt i j done [0..length cols-1]);
|
Chris@94
|
43 esac,
|
Chris@96
|
44 getAt row col =
|
Chris@96
|
45 case d of
|
Chris@96
|
46 RowM rows: r = rows[row]; (r is ~double[])[col];
|
Chris@96
|
47 ColM cols: c = cols[col]; (c is ~double[])[row];
|
Chris@94
|
48 esac,
|
Chris@96
|
49 setAt row col n =
|
Chris@96
|
50 case d of
|
Chris@96
|
51 RowM rows: r = rows[row]; (r is ~double[])[col] := n;
|
Chris@96
|
52 ColM cols: c = cols[col]; (c is ~double[])[row] := n;
|
Chris@95
|
53 esac,
|
Chris@95
|
54 get isRowMajor? () =
|
Chris@96
|
55 case d of
|
Chris@96
|
56 RowM _: true;
|
Chris@96
|
57 ColM _: false;
|
Chris@95
|
58 esac,
|
Chris@94
|
59 };
|
Chris@94
|
60
|
Chris@94
|
61 newStorage rows cols =
|
Chris@97
|
62 if rows < 1 then array []
|
Chris@97
|
63 else array (map \(vec.zeros rows) [1..cols])
|
Chris@97
|
64 fi;
|
Chris@94
|
65
|
Chris@94
|
66 zeroMatrix rows cols =
|
Chris@96
|
67 make (ColM (newStorage rows cols));
|
Chris@5
|
68
|
Chris@20
|
69 generate f rows cols =
|
Chris@94
|
70 (m = newStorage rows cols;
|
Chris@94
|
71 for [0..cols-1] do col:
|
Chris@94
|
72 for [0..rows-1] do row:
|
Chris@94
|
73 m[col][row] := f row col;
|
Chris@5
|
74 done;
|
Chris@5
|
75 done;
|
Chris@96
|
76 make (ColM m));
|
Chris@5
|
77
|
Chris@20
|
78 constMatrix n = generate do row col: n done;
|
Chris@20
|
79 randomMatrix = generate do row col: Math#random() done;
|
Chris@5
|
80 identityMatrix = constMatrix 1;
|
Chris@5
|
81
|
Chris@96
|
82 width m = m.size.columns;
|
Chris@96
|
83 height m = m.size.rows;
|
Chris@6
|
84
|
Chris@97
|
85 equal m1 m2 =
|
Chris@97
|
86 (compare d1 d2 =
|
Chris@97
|
87 all id (map2 vec.equal d1 d2);
|
Chris@97
|
88 case m1.data of
|
Chris@97
|
89 RowM d1:
|
Chris@97
|
90 case m2.data of RowM d2: compare d1 d2; _: false; esac;
|
Chris@97
|
91 ColM d1:
|
Chris@97
|
92 case m2.data of ColM d2: compare d1 d2; _: false; esac;
|
Chris@97
|
93 esac);
|
Chris@97
|
94
|
Chris@95
|
95 copyOf m =
|
Chris@95
|
96 (copyOfData d = (array (map vec.copyOf d));
|
Chris@96
|
97 make
|
Chris@95
|
98 (case m.data of
|
Chris@96
|
99 RowM d: RowM (copyOfData d);
|
Chris@96
|
100 ColM d: ColM (copyOfData d);
|
Chris@95
|
101 esac));
|
Chris@6
|
102
|
Chris@95
|
103 transposed m =
|
Chris@96
|
104 make
|
Chris@95
|
105 (case m.data of
|
Chris@96
|
106 RowM d: ColM d;
|
Chris@96
|
107 ColM d: RowM d;
|
Chris@95
|
108 esac);
|
Chris@5
|
109
|
Chris@96
|
110 //!!! Change storage from column to row major order (or back
|
Chris@96
|
111 //again). Is there a word for this?
|
Chris@96
|
112 flipped m =
|
Chris@96
|
113 if m.isRowMajor? then id else transposed fi
|
Chris@96
|
114 (generate do row col: m.getAt col row done m.size.columns m.size.rows);
|
Chris@96
|
115
|
Chris@96
|
116 newMatrix type data is RowMajor () | ColumnMajor () -> list?<list?<number>> -> 'a =
|
Chris@96
|
117 (tagger = case type of RowMajor (): RowM; ColumnMajor (): ColM esac;
|
Chris@97
|
118 if empty? data or empty? (head data)
|
Chris@96
|
119 then zeroMatrix 0 0
|
Chris@96
|
120 else make (tagger (array (map vec.vector data)))
|
Chris@96
|
121 fi);
|
Chris@96
|
122
|
Chris@96
|
123 newRowVector data =
|
Chris@96
|
124 newMatrix (RowMajor ()) [data];
|
Chris@96
|
125
|
Chris@96
|
126 newColumnVector data =
|
Chris@96
|
127 newMatrix (ColumnMajor ()) [data];
|
Chris@8
|
128
|
Chris@5
|
129 {
|
Chris@97
|
130 constMatrix, randomMatrix, zeroMatrix, identityMatrix,
|
Chris@96
|
131 generate,
|
Chris@96
|
132 width, height,
|
Chris@97
|
133 equal,
|
Chris@20
|
134 copyOf,
|
Chris@15
|
135 transposed,
|
Chris@96
|
136 flipped,
|
Chris@96
|
137 newMatrix, newRowVector, newColumnVector
|
Chris@5
|
138 }
|
Chris@5
|
139
|