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@95
|
62 array (map \(vec.zeros rows) [1..cols]);
|
Chris@94
|
63
|
Chris@94
|
64 zeroMatrix rows cols =
|
Chris@96
|
65 make (ColM (newStorage rows cols));
|
Chris@5
|
66
|
Chris@20
|
67 generate f rows cols =
|
Chris@94
|
68 (m = newStorage rows cols;
|
Chris@94
|
69 for [0..cols-1] do col:
|
Chris@94
|
70 for [0..rows-1] do row:
|
Chris@94
|
71 m[col][row] := f row col;
|
Chris@5
|
72 done;
|
Chris@5
|
73 done;
|
Chris@96
|
74 make (ColM m));
|
Chris@5
|
75
|
Chris@20
|
76 constMatrix n = generate do row col: n done;
|
Chris@20
|
77 randomMatrix = generate do row col: Math#random() done;
|
Chris@5
|
78 identityMatrix = constMatrix 1;
|
Chris@5
|
79
|
Chris@96
|
80 width m = m.size.columns;
|
Chris@96
|
81 height m = m.size.rows;
|
Chris@6
|
82
|
Chris@95
|
83 copyOf m =
|
Chris@95
|
84 (copyOfData d = (array (map vec.copyOf d));
|
Chris@96
|
85 make
|
Chris@95
|
86 (case m.data of
|
Chris@96
|
87 RowM d: RowM (copyOfData d);
|
Chris@96
|
88 ColM d: ColM (copyOfData d);
|
Chris@95
|
89 esac));
|
Chris@6
|
90
|
Chris@95
|
91 transposed m =
|
Chris@96
|
92 make
|
Chris@95
|
93 (case m.data of
|
Chris@96
|
94 RowM d: ColM d;
|
Chris@96
|
95 ColM d: RowM d;
|
Chris@95
|
96 esac);
|
Chris@5
|
97
|
Chris@96
|
98 //!!! Change storage from column to row major order (or back
|
Chris@96
|
99 //again). Is there a word for this?
|
Chris@96
|
100 flipped m =
|
Chris@96
|
101 if m.isRowMajor? then id else transposed fi
|
Chris@96
|
102 (generate do row col: m.getAt col row done m.size.columns m.size.rows);
|
Chris@96
|
103
|
Chris@96
|
104 newMatrix type data is RowMajor () | ColumnMajor () -> list?<list?<number>> -> 'a =
|
Chris@96
|
105 (tagger = case type of RowMajor (): RowM; ColumnMajor (): ColM esac;
|
Chris@96
|
106 if empty? data
|
Chris@96
|
107 then zeroMatrix 0 0
|
Chris@96
|
108 else make (tagger (array (map vec.vector data)))
|
Chris@96
|
109 fi);
|
Chris@96
|
110
|
Chris@96
|
111 newRowVector data =
|
Chris@96
|
112 newMatrix (RowMajor ()) [data];
|
Chris@96
|
113
|
Chris@96
|
114 newColumnVector data =
|
Chris@96
|
115 newMatrix (ColumnMajor ()) [data];
|
Chris@8
|
116
|
Chris@5
|
117 {
|
Chris@96
|
118 generate,
|
Chris@96
|
119 constMatrix, randomMatrix, zeroMatrix, identityMatrix,
|
Chris@96
|
120 width, height,
|
Chris@20
|
121 copyOf,
|
Chris@15
|
122 transposed,
|
Chris@96
|
123 flipped,
|
Chris@96
|
124 newMatrix, newRowVector, newColumnVector
|
Chris@5
|
125 }
|
Chris@5
|
126
|