annotate yetilab/matrix/matrix.yeti @ 98:bd135a950af7

Scaled, sum, product
author Chris Cannam
date Thu, 21 Mar 2013 10:18:18 +0000
parents d5fc902dcc3f
children 9832210dc42c
rev   line source
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@98 61 newStorage { rows, columns } =
Chris@97 62 if rows < 1 then array []
Chris@98 63 else array (map \(vec.zeros rows) [1..columns])
Chris@97 64 fi;
Chris@94 65
Chris@98 66 zeroMatrix { rows, columns } =
Chris@98 67 make (ColM (newStorage { rows, columns }));
Chris@5 68
Chris@98 69 generate f { rows, columns } =
Chris@98 70 (m = newStorage { rows, columns };
Chris@98 71 for [0..columns-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@98 85 //!!! should matrices with the same content but different storage order be equal?
Chris@97 86 equal m1 m2 =
Chris@97 87 (compare d1 d2 =
Chris@97 88 all id (map2 vec.equal d1 d2);
Chris@97 89 case m1.data of
Chris@97 90 RowM d1:
Chris@97 91 case m2.data of RowM d2: compare d1 d2; _: false; esac;
Chris@97 92 ColM d1:
Chris@97 93 case m2.data of ColM d2: compare d1 d2; _: false; esac;
Chris@97 94 esac);
Chris@97 95
Chris@95 96 copyOf m =
Chris@95 97 (copyOfData d = (array (map vec.copyOf d));
Chris@96 98 make
Chris@95 99 (case m.data of
Chris@96 100 RowM d: RowM (copyOfData d);
Chris@96 101 ColM d: ColM (copyOfData d);
Chris@95 102 esac));
Chris@6 103
Chris@95 104 transposed m =
Chris@96 105 make
Chris@95 106 (case m.data of
Chris@96 107 RowM d: ColM d;
Chris@96 108 ColM d: RowM d;
Chris@95 109 esac);
Chris@5 110
Chris@96 111 //!!! Change storage from column to row major order (or back
Chris@96 112 //again). Is there a word for this?
Chris@96 113 flipped m =
Chris@96 114 if m.isRowMajor? then id else transposed fi
Chris@98 115 (generate do row col: m.getAt col row done m.size);
Chris@96 116
Chris@96 117 newMatrix type data is RowMajor () | ColumnMajor () -> list?<list?<number>> -> 'a =
Chris@96 118 (tagger = case type of RowMajor (): RowM; ColumnMajor (): ColM esac;
Chris@97 119 if empty? data or empty? (head data)
Chris@98 120 then zeroMatrix { rows = 0, columns = 0 }
Chris@96 121 else make (tagger (array (map vec.vector data)))
Chris@96 122 fi);
Chris@96 123
Chris@96 124 newRowVector data =
Chris@96 125 newMatrix (RowMajor ()) [data];
Chris@96 126
Chris@96 127 newColumnVector data =
Chris@96 128 newMatrix (ColumnMajor ()) [data];
Chris@8 129
Chris@98 130 scaled factor m =
Chris@98 131 generate do row col: factor * m.getAt row col done m.size;
Chris@98 132
Chris@98 133 sum' m1 m2 =
Chris@98 134 if m1.size != m2.size
Chris@98 135 then failWith "Matrices are not the same size: \(m1.size), \(m2.size)";
Chris@98 136 else
Chris@98 137 generate do row col: m1.getAt row col + m2.getAt row col done m1.size;
Chris@98 138 fi;
Chris@98 139
Chris@98 140 product m1 m2 =
Chris@98 141 if m1.size.columns != m2.size.rows
Chris@98 142 then failWith "Matrix dimensions incompatible: \(m1.size), \(m2.size) (\(m1.size.columns != m2.size.rows)";
Chris@98 143 else
Chris@98 144 //!!! super-slow!
Chris@98 145 generate do row col:
Chris@98 146 r = block.list (m1.getRow row);
Chris@98 147 c = block.list (m2.getColumn col);
Chris@98 148 sum (map2 (*) r c);
Chris@98 149 done { rows = m1.size.rows, columns = m2.size.columns }
Chris@98 150 fi;
Chris@98 151
Chris@5 152 {
Chris@97 153 constMatrix, randomMatrix, zeroMatrix, identityMatrix,
Chris@96 154 generate,
Chris@96 155 width, height,
Chris@97 156 equal,
Chris@20 157 copyOf,
Chris@15 158 transposed,
Chris@96 159 flipped,
Chris@98 160 scaled,
Chris@98 161 sum = sum', product,
Chris@98 162 newMatrix, newRowVector, newColumnVector,
Chris@5 163 }
Chris@5 164