annotate yetilab/matrix/matrix.yeti @ 100:4e52d04887a5

Fix flipped
author Chris Cannam
date Thu, 21 Mar 2013 17:13:09 +0000
parents 9832210dc42c
children 2bc6534248fe
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@99 16 bf = load yetilab.block.blockfuncs;
Chris@9 17
Chris@96 18 make d = {
Chris@96 19 get data () = d,
Chris@96 20 get size () =
Chris@96 21 case d of
Chris@96 22 RowM r:
Chris@96 23 major = length r;
Chris@96 24 {
Chris@96 25 rows = major,
Chris@96 26 columns = if major > 0 then vec.length r[0] else 0 fi,
Chris@96 27 };
Chris@96 28 ColM c:
Chris@96 29 major = length c;
Chris@96 30 {
Chris@96 31 rows = if major > 0 then vec.length c[0] else 0 fi,
Chris@96 32 columns = major,
Chris@96 33 };
Chris@94 34 esac,
Chris@96 35 getColumn j =
Chris@96 36 case d of
Chris@96 37 RowM rows: block.fromList (map do i: getAt i j done [0..length rows-1]);
Chris@96 38 ColM cols: block.block cols[j];
Chris@94 39 esac,
Chris@96 40 getRow i =
Chris@96 41 case d of
Chris@96 42 RowM rows: block.block rows[i];
Chris@96 43 ColM cols: block.fromList (map do j: getAt i j done [0..length cols-1]);
Chris@94 44 esac,
Chris@96 45 getAt row col =
Chris@96 46 case d of
Chris@96 47 RowM rows: r = rows[row]; (r is ~double[])[col];
Chris@96 48 ColM cols: c = cols[col]; (c is ~double[])[row];
Chris@94 49 esac,
Chris@96 50 setAt row col n =
Chris@96 51 case d of
Chris@96 52 RowM rows: r = rows[row]; (r is ~double[])[col] := n;
Chris@96 53 ColM cols: c = cols[col]; (c is ~double[])[row] := n;
Chris@95 54 esac,
Chris@95 55 get isRowMajor? () =
Chris@96 56 case d of
Chris@96 57 RowM _: true;
Chris@96 58 ColM _: false;
Chris@95 59 esac,
Chris@94 60 };
Chris@94 61
Chris@98 62 newStorage { rows, columns } =
Chris@97 63 if rows < 1 then array []
Chris@98 64 else array (map \(vec.zeros rows) [1..columns])
Chris@97 65 fi;
Chris@94 66
Chris@98 67 zeroMatrix { rows, columns } =
Chris@98 68 make (ColM (newStorage { rows, columns }));
Chris@5 69
Chris@98 70 generate f { rows, columns } =
Chris@98 71 (m = newStorage { rows, columns };
Chris@98 72 for [0..columns-1] do col:
Chris@94 73 for [0..rows-1] do row:
Chris@94 74 m[col][row] := f row col;
Chris@5 75 done;
Chris@5 76 done;
Chris@96 77 make (ColM m));
Chris@5 78
Chris@20 79 constMatrix n = generate do row col: n done;
Chris@20 80 randomMatrix = generate do row col: Math#random() done;
Chris@5 81 identityMatrix = constMatrix 1;
Chris@5 82
Chris@96 83 width m = m.size.columns;
Chris@96 84 height m = m.size.rows;
Chris@6 85
Chris@100 86 transposed m =
Chris@100 87 make
Chris@100 88 (case m.data of
Chris@100 89 RowM d: ColM d;
Chris@100 90 ColM d: RowM d;
Chris@100 91 esac);
Chris@100 92
Chris@100 93 flipped m =
Chris@100 94 if m.isRowMajor? then
Chris@100 95 generate do row col: m.getAt row col done m.size;
Chris@100 96 else
Chris@100 97 transposed
Chris@100 98 (generate do row col: m.getAt col row done
Chris@100 99 { rows = m.size.columns, columns = m.size.rows });
Chris@100 100 fi;
Chris@100 101
Chris@100 102 // Matrices with different storage order but the same contents are
Chris@100 103 // equal (but comparing them is slow)
Chris@97 104 equal m1 m2 =
Chris@100 105 if m1.isRowMajor? != m2.isRowMajor?
Chris@100 106 then equal (flipped m1) m2;
Chris@100 107 else
Chris@100 108 compare d1 d2 = all id (map2 vec.equal d1 d2);
Chris@100 109 case m1.data of
Chris@100 110 RowM d1: case m2.data of RowM d2: compare d1 d2; _: false; esac;
Chris@100 111 ColM d1: case m2.data of ColM d2: compare d1 d2; _: false; esac;
Chris@100 112 esac
Chris@100 113 fi;
Chris@97 114
Chris@95 115 copyOf m =
Chris@95 116 (copyOfData d = (array (map vec.copyOf d));
Chris@96 117 make
Chris@95 118 (case m.data of
Chris@96 119 RowM d: RowM (copyOfData d);
Chris@96 120 ColM d: ColM (copyOfData d);
Chris@95 121 esac));
Chris@6 122
Chris@96 123 newMatrix type data is RowMajor () | ColumnMajor () -> list?<list?<number>> -> 'a =
Chris@96 124 (tagger = case type of RowMajor (): RowM; ColumnMajor (): ColM esac;
Chris@97 125 if empty? data or empty? (head data)
Chris@98 126 then zeroMatrix { rows = 0, columns = 0 }
Chris@96 127 else make (tagger (array (map vec.vector data)))
Chris@96 128 fi);
Chris@96 129
Chris@96 130 newRowVector data =
Chris@96 131 newMatrix (RowMajor ()) [data];
Chris@96 132
Chris@96 133 newColumnVector data =
Chris@96 134 newMatrix (ColumnMajor ()) [data];
Chris@8 135
Chris@98 136 scaled factor m =
Chris@98 137 generate do row col: factor * m.getAt row col done m.size;
Chris@98 138
Chris@98 139 sum' m1 m2 =
Chris@98 140 if m1.size != m2.size
Chris@98 141 then failWith "Matrices are not the same size: \(m1.size), \(m2.size)";
Chris@98 142 else
Chris@98 143 generate do row col: m1.getAt row col + m2.getAt row col done m1.size;
Chris@98 144 fi;
Chris@98 145
Chris@98 146 product m1 m2 =
Chris@98 147 if m1.size.columns != m2.size.rows
Chris@98 148 then failWith "Matrix dimensions incompatible: \(m1.size), \(m2.size) (\(m1.size.columns != m2.size.rows)";
Chris@98 149 else
Chris@98 150 //!!! super-slow!
Chris@98 151 generate do row col:
Chris@99 152 bf.sum (bf.multiply (m1.getRow row) (m2.getColumn col))
Chris@98 153 done { rows = m1.size.rows, columns = m2.size.columns }
Chris@98 154 fi;
Chris@98 155
Chris@5 156 {
Chris@97 157 constMatrix, randomMatrix, zeroMatrix, identityMatrix,
Chris@96 158 generate,
Chris@96 159 width, height,
Chris@97 160 equal,
Chris@20 161 copyOf,
Chris@15 162 transposed,
Chris@96 163 flipped,
Chris@98 164 scaled,
Chris@98 165 sum = sum', product,
Chris@98 166 newMatrix, newRowVector, newColumnVector,
Chris@5 167 }
Chris@5 168