annotate yetilab/matrix/matrix.yeti @ 249:1ea5bf6e76b6 sparse

A reasonable sparse multiply, and a bit quicker dense one
author Chris Cannam
date Mon, 20 May 2013 22:17:19 +0100
parents 58e98d146dc1
children 9fe3192cce38
rev   line source
Chris@5 1
Chris@94 2 module yetilab.matrix.matrix;
Chris@94 3
Chris@214 4 // A matrix is an array of vectors.
Chris@94 5
Chris@101 6 // A matrix can be stored in either column-major (the default) or
Chris@101 7 // row-major format. Storage order is an efficiency concern only:
Chris@101 8 // every API function operating on matrix objects will return the same
Chris@101 9 // result regardless of storage order. (The transpose function just
Chris@101 10 // switches the row/column order without moving the elements.)
Chris@18 11
Chris@214 12 //!!! check that we are not unnecessarily copying in the transform functions
Chris@214 13
Chris@222 14 vec = load yetilab.vector.vector;
Chris@222 15 bf = load yetilab.vector.blockfuncs;
Chris@9 16
Chris@222 17 load yetilab.vector.vectortype;
Chris@195 18 load yetilab.matrix.matrixtype;
Chris@195 19
Chris@208 20 size m =
Chris@208 21 case m of
Chris@234 22 DenseRows r:
Chris@208 23 major = length r;
Chris@208 24 {
Chris@208 25 rows = major,
Chris@214 26 columns = if major > 0 then vec.length r[0] else 0 fi,
Chris@208 27 };
Chris@234 28 DenseCols c:
Chris@208 29 major = length c;
Chris@208 30 {
Chris@214 31 rows = if major > 0 then vec.length c[0] else 0 fi,
Chris@208 32 columns = major,
Chris@208 33 };
Chris@237 34 SparseCSR { values, indices, pointers, extent }:
Chris@234 35 {
Chris@236 36 rows = (length pointers) - 1,
Chris@237 37 columns = extent
Chris@234 38 };
Chris@237 39 SparseCSC { values, indices, pointers, extent }:
Chris@234 40 {
Chris@237 41 rows = extent,
Chris@236 42 columns = (length pointers) - 1
Chris@234 43 };
Chris@208 44 esac;
Chris@208 45
Chris@208 46 width m = (size m).columns;
Chris@208 47 height m = (size m).rows;
Chris@208 48
Chris@249 49 nonZeroValues m =
Chris@249 50 (nz d =
Chris@242 51 sum
Chris@242 52 (map do v:
Chris@242 53 sum (map do n: if n == 0 then 0 else 1 fi done (vec.list v))
Chris@242 54 done d);
Chris@242 55 case m of
Chris@249 56 DenseRows d: nz d;
Chris@249 57 DenseCols d: nz d;
Chris@249 58 SparseCSR d: vec.length d.values;
Chris@249 59 SparseCSC d: vec.length d.values;
Chris@242 60 esac);
Chris@242 61
Chris@249 62 density m =
Chris@249 63 ({ rows, columns } = size m;
Chris@249 64 cells = rows * columns;
Chris@249 65 (nonZeroValues m) / cells);
Chris@249 66
Chris@236 67 sparseSlice n d =
Chris@236 68 (start = d.pointers[n];
Chris@236 69 end = d.pointers[n+1];
Chris@236 70 {
Chris@236 71 values = vec.slice d.values start end,
Chris@239 72 indices = slice d.indices start end,
Chris@236 73 });
Chris@236 74
Chris@236 75 fromSlice n m d =
Chris@236 76 (slice = sparseSlice n d;
Chris@236 77 var v = 0;
Chris@236 78 for [0..length slice.indices - 1] do i:
Chris@236 79 if slice.indices[i] == m then
Chris@236 80 v := vec.at i slice.values;
Chris@236 81 fi
Chris@236 82 done;
Chris@236 83 v);
Chris@236 84
Chris@236 85 filledSlice n d =
Chris@236 86 (slice = sparseSlice n d;
Chris@236 87 dslice = new double[d.extent];
Chris@239 88 for [0..length slice.indices - 1] do i:
Chris@239 89 dslice[slice.indices[i]] := vec.at i slice.values;
Chris@239 90 done;
Chris@236 91 vec.vector dslice);
Chris@236 92
Chris@208 93 getAt row col m =
Chris@208 94 case m of
Chris@234 95 DenseRows rows: r = rows[row]; vec.at col r;
Chris@234 96 DenseCols cols: c = cols[col]; vec.at row c;
Chris@236 97 SparseCSR data: fromSlice row col data;
Chris@236 98 SparseCSC data: fromSlice col row data;
Chris@208 99 esac;
Chris@208 100
Chris@208 101 getColumn j m =
Chris@208 102 case m of
Chris@234 103 DenseCols cols: cols[j];
Chris@236 104 SparseCSC data: filledSlice j data;
Chris@236 105 _: vec.fromList (map do i: getAt i j m done [0..height m - 1]);
Chris@208 106 esac;
Chris@208 107
Chris@208 108 getRow i m =
Chris@208 109 case m of
Chris@234 110 DenseRows rows: rows[i];
Chris@236 111 SparseCSR data: filledSlice i data;
Chris@236 112 _: vec.fromList (map do j: getAt i j m done [0..width m - 1]);
Chris@208 113 esac;
Chris@208 114
Chris@208 115 isRowMajor? m =
Chris@208 116 case m of
Chris@234 117 DenseRows _: true;
Chris@234 118 DenseCols _: false;
Chris@234 119 SparseCSR _: true;
Chris@234 120 SparseCSC _: false;
Chris@234 121 esac;
Chris@234 122
Chris@234 123 isSparse? m =
Chris@234 124 case m of
Chris@234 125 DenseRows _: false;
Chris@234 126 DenseCols _: false;
Chris@234 127 SparseCSR _: true;
Chris@234 128 SparseCSC _: true;
Chris@208 129 esac;
Chris@94 130
Chris@244 131 newColumnMajorStorage { rows, columns } =
Chris@97 132 if rows < 1 then array []
Chris@214 133 else array (map \(vec.zeros rows) [1..columns])
Chris@97 134 fi;
Chris@94 135
Chris@98 136 zeroMatrix { rows, columns } =
Chris@244 137 DenseCols (newColumnMajorStorage { rows, columns });
Chris@201 138
Chris@201 139 zeroMatrixWithTypeOf m { rows, columns } =
Chris@208 140 if isRowMajor? m then
Chris@244 141 DenseRows (newColumnMajorStorage { rows = columns, columns = rows });
Chris@201 142 else
Chris@244 143 DenseCols (newColumnMajorStorage { rows, columns });
Chris@201 144 fi;
Chris@5 145
Chris@214 146 zeroSizeMatrix () = zeroMatrix { rows = 0, columns = 0 };
Chris@214 147
Chris@98 148 generate f { rows, columns } =
Chris@214 149 if rows < 1 or columns < 1 then zeroSizeMatrix ()
Chris@214 150 else
Chris@214 151 m = array (map \(new double[rows]) [1..columns]);
Chris@214 152 for [0..columns-1] do col:
Chris@214 153 for [0..rows-1] do row:
Chris@214 154 m[col][row] := f row col;
Chris@214 155 done;
Chris@5 156 done;
Chris@234 157 DenseCols (array (map vec.vector m))
Chris@214 158 fi;
Chris@5 159
Chris@235 160 enumerateSparse m =
Chris@240 161 (enumerate { values, indices, pointers } =
Chris@240 162 concat
Chris@240 163 (map do i:
Chris@240 164 start = pointers[i];
Chris@240 165 end = pointers[i+1];
Chris@240 166 map2 do j v: { i, j, v } done
Chris@240 167 (slice indices start end)
Chris@240 168 (vec.list (vec.slice values start end))
Chris@240 169 done [0..length pointers - 2]);
Chris@235 170 case m of
Chris@240 171 SparseCSC d:
Chris@240 172 map do { i, j, v }: { i = j, j = i, v } done (enumerate d);
Chris@240 173 SparseCSR d:
Chris@240 174 enumerate d;
Chris@237 175 _: [];
Chris@235 176 esac);
Chris@235 177
Chris@238 178 makeSparse type size data =
Chris@244 179 (isRow = case type of RowMajor (): true; ColumnMajor (): false esac;
Chris@238 180 ordered =
Chris@238 181 sortBy do a b:
Chris@238 182 if a.maj == b.maj then a.min < b.min else a.maj < b.maj fi
Chris@238 183 done
Chris@238 184 (map
Chris@238 185 if isRow then
Chris@238 186 do { i, j, v }: { maj = i, min = j, v } done;
Chris@238 187 else
Chris@238 188 do { i, j, v }: { maj = j, min = i, v } done;
Chris@238 189 fi
Chris@238 190 data);
Chris@238 191 tagger = if isRow then SparseCSR else SparseCSC fi;
Chris@238 192 majorSize = if isRow then size.rows else size.columns fi;
Chris@238 193 minorSize = if isRow then size.columns else size.rows fi;
Chris@238 194 majorPointers acc nn n i data =
Chris@238 195 if n < nn then
Chris@238 196 case data of
Chris@238 197 d::rest:
Chris@238 198 majorPointers (acc ++ (map \(i) [n..d-1])) nn d (i+1) rest;
Chris@238 199 _:
Chris@238 200 majorPointers (acc ++ [i]) nn (n+1) i [];
Chris@238 201 esac;
Chris@238 202 else
Chris@238 203 acc
Chris@238 204 fi;
Chris@238 205 tagger {
Chris@238 206 values = vec.fromList (map (.v) ordered),
Chris@238 207 indices = array (map (.min) ordered),
Chris@239 208 pointers = array (majorPointers [0] majorSize 0 0 (map (.maj) ordered)),
Chris@238 209 extent = minorSize,
Chris@238 210 });
Chris@238 211
Chris@243 212 toSparse m =
Chris@238 213 if isSparse? m then m
Chris@238 214 else
Chris@238 215 { rows, columns } = size m;
Chris@243 216 enumerate m ii jj =
Chris@238 217 case ii of
Chris@238 218 i::irest:
Chris@238 219 case jj of
Chris@238 220 j::rest:
Chris@238 221 v = getAt i j m;
Chris@243 222 if v != 0 then { i, j, v } :. \(enumerate m ii rest)
Chris@243 223 else enumerate m ii rest
Chris@238 224 fi;
Chris@243 225 _: enumerate m irest [0..columns-1];
Chris@238 226 esac;
Chris@238 227 _: [];
Chris@238 228 esac;
Chris@238 229 makeSparse
Chris@244 230 if isRowMajor? m then RowMajor () else ColumnMajor () fi
Chris@238 231 (size m)
Chris@243 232 (enumerate m [0..rows-1] [0..columns-1]);
Chris@238 233 fi;
Chris@238 234
Chris@238 235 toDense m =
Chris@238 236 if not (isSparse? m) then m
Chris@238 237 elif isRowMajor? m then
Chris@238 238 DenseRows (array (map do row: getRow row m done [0..height m - 1]));
Chris@238 239 else
Chris@238 240 DenseCols (array (map do col: getColumn col m done [0..width m - 1]));
Chris@238 241 fi;
Chris@235 242
Chris@20 243 constMatrix n = generate do row col: n done;
Chris@20 244 randomMatrix = generate do row col: Math#random() done;
Chris@5 245 identityMatrix = constMatrix 1;
Chris@5 246
Chris@100 247 transposed m =
Chris@208 248 case m of
Chris@234 249 DenseRows d: DenseCols d;
Chris@234 250 DenseCols d: DenseRows d;
Chris@236 251 SparseCSR d: SparseCSC d;
Chris@236 252 SparseCSC d: SparseCSR d;
Chris@208 253 esac;
Chris@100 254
Chris@100 255 flipped m =
Chris@235 256 if isSparse? m then
Chris@235 257 if isRowMajor? m then
Chris@244 258 makeSparse (ColumnMajor ()) (size m) (enumerateSparse m)
Chris@235 259 else
Chris@238 260 makeSparse (RowMajor ()) (size m) (enumerateSparse m)
Chris@235 261 fi
Chris@100 262 else
Chris@235 263 if isRowMajor? m then
Chris@235 264 generate do row col: getAt row col m done (size m);
Chris@235 265 else
Chris@235 266 transposed
Chris@235 267 (generate do row col: getAt col row m done
Chris@235 268 { rows = (width m), columns = (height m) });
Chris@235 269 fi
Chris@100 270 fi;
Chris@100 271
Chris@161 272 toRowMajor m =
Chris@208 273 if isRowMajor? m then m else flipped m fi;
Chris@161 274
Chris@161 275 toColumnMajor m =
Chris@208 276 if not isRowMajor? m then m else flipped m fi;
Chris@161 277
Chris@238 278 equal'' comparator vecComparator m1 m2 =
Chris@238 279 // Prerequisite: m1 and m2 have same sparse-p and storage order
Chris@241 280 (compareVecLists vv1 vv2 = all id (map2 vecComparator vv1 vv2);
Chris@238 281 compareSparse d1 d2 =
Chris@238 282 d1.extent == d2.extent and
Chris@238 283 vecComparator d1.values d2.values and
Chris@241 284 d1.indices == d2.indices and
Chris@241 285 d1.pointers == d2.pointers;
Chris@238 286 case m1 of
Chris@238 287 DenseRows d1:
Chris@238 288 case m2 of DenseRows d2: compareVecLists d1 d2; _: false; esac;
Chris@238 289 DenseCols d1:
Chris@238 290 case m2 of DenseCols d2: compareVecLists d1 d2; _: false; esac;
Chris@238 291 SparseCSR d1:
Chris@238 292 case m2 of SparseCSR d2: compareSparse d1 d2; _: false; esac;
Chris@238 293 SparseCSC d1:
Chris@238 294 case m2 of SparseCSC d2: compareSparse d1 d2; _: false; esac;
Chris@238 295 esac);
Chris@238 296
Chris@238 297 equal' comparator vecComparator m1 m2 =
Chris@226 298 if size m1 != size m2 then
Chris@226 299 false
Chris@226 300 elif isRowMajor? m1 != isRowMajor? m2 then
Chris@238 301 equal' comparator vecComparator (flipped m1) m2;
Chris@238 302 elif isSparse? m1 != isSparse? m2 then
Chris@238 303 if isSparse? m1 then
Chris@243 304 equal' comparator vecComparator m1 (toSparse m2)
Chris@238 305 else
Chris@243 306 equal' comparator vecComparator (toSparse m1) m2
Chris@238 307 fi
Chris@100 308 else
Chris@238 309 equal'' comparator vecComparator m1 m2
Chris@100 310 fi;
Chris@97 311
Chris@228 312 // Compare matrices using the given comparator for individual cells.
Chris@228 313 // Note that matrices with different storage order but the same
Chris@228 314 // contents are equal, although comparing them is slow.
Chris@249 315 //!!! Document the fact that sparse matrices can only be equal if they
Chris@249 316 // have the same set of non-zero cells (regardless of comparator used)
Chris@228 317 equalUnder comparator =
Chris@238 318 equal' comparator (vec.equalUnder comparator);
Chris@228 319
Chris@228 320 equal =
Chris@238 321 equal' (==) vec.equal;
Chris@226 322
Chris@163 323 newMatrix type data = //!!! NB does not copy data
Chris@238 324 (tagger = case type of RowMajor (): DenseRows; ColumnMajor (): DenseCols esac;
Chris@214 325 if empty? data or vec.empty? (head data)
Chris@201 326 then zeroSizeMatrix ()
Chris@208 327 else tagger (array data)
Chris@96 328 fi);
Chris@96 329
Chris@163 330 newRowVector data = //!!! NB does not copy data
Chris@234 331 DenseRows (array [data]);
Chris@96 332
Chris@163 333 newColumnVector data = //!!! NB does not copy data
Chris@234 334 DenseCols (array [data]);
Chris@8 335
Chris@195 336 scaled factor m = //!!! v inefficient
Chris@208 337 generate do row col: factor * (getAt row col m) done (size m);
Chris@98 338
Chris@243 339 thresholded threshold m = //!!! v inefficient; and should take a threshold function?
Chris@243 340 generate do row col:
Chris@243 341 v = getAt row col m; if (abs v) > threshold then v else 0 fi
Chris@243 342 done (size m);
Chris@243 343
Chris@98 344 sum' m1 m2 =
Chris@208 345 if (size m1) != (size m2)
Chris@208 346 then failWith "Matrices are not the same size: \(size m1), \(size m2)";
Chris@98 347 else
Chris@208 348 generate do row col: getAt row col m1 + getAt row col m2 done (size m1);
Chris@98 349 fi;
Chris@98 350
Chris@229 351 difference m1 m2 = //!!! doc: m1 - m2, not m2 - m1
Chris@229 352 if (size m1) != (size m2)
Chris@229 353 then failWith "Matrices are not the same size: \(size m1), \(size m2)";
Chris@229 354 else
Chris@229 355 generate do row col: getAt row col m1 - getAt row col m2 done (size m1);
Chris@229 356 fi;
Chris@229 357
Chris@229 358 abs' m =
Chris@229 359 generate do row col: abs (getAt row col m) done (size m);
Chris@229 360
Chris@249 361 sparseProductLeft size m1 m2 =
Chris@249 362 (e = enumerateSparse m1;
Chris@249 363 data = array (map \(new double[size.rows]) [1..size.columns]);
Chris@249 364 for [0..size.columns - 1] do j':
Chris@249 365 c = getColumn j' m2;
Chris@249 366 for e do { v, i, j }:
Chris@249 367 data[j'][i] := data[j'][i] + v * (vec.at j c);
Chris@249 368 done;
Chris@249 369 done;
Chris@249 370 DenseCols (array (map vec.vector (list data))));
Chris@249 371
Chris@249 372 sparseProductRight size m1 m2 =
Chris@249 373 (e = enumerateSparse m2;
Chris@249 374 data = array (map \(new double[size.columns]) [1..size.rows]);
Chris@249 375 for [0..size.rows - 1] do i':
Chris@249 376 r = getRow i' m1;
Chris@249 377 for e do { v, i, j }:
Chris@249 378 data[i'][j] := data[i'][j] + v * (vec.at i r);
Chris@249 379 done;
Chris@249 380 done;
Chris@249 381 DenseRows (array (map vec.vector (list data))));
Chris@249 382
Chris@249 383 denseProduct size m1 m2 =
Chris@249 384 (data = array (map \(new double[size.rows]) [1..size.columns]);
Chris@249 385 for [0..size.rows - 1] do i:
Chris@249 386 row = getRow i m1;
Chris@249 387 for [0..size.columns - 1] do j:
Chris@249 388 data[j][i] := bf.sum (bf.multiply row (getColumn j m2));
Chris@249 389 done;
Chris@249 390 done;
Chris@249 391 DenseCols (array (map vec.vector (list data))));
Chris@249 392
Chris@98 393 product m1 m2 =
Chris@208 394 if (size m1).columns != (size m2).rows
Chris@246 395 then failWith "Matrix dimensions incompatible: \(size m1), \(size m2) (\((size m1).columns) != \((size m2).rows))";
Chris@249 396 else
Chris@249 397 size = { rows = (size m1).rows, columns = (size m2).columns };
Chris@249 398 if isSparse? m1 then
Chris@249 399 sparseProductLeft size m1 m2
Chris@249 400 elif isSparse? m2 then
Chris@249 401 sparseProductRight size m1 m2
Chris@249 402 else
Chris@249 403 denseProduct size m1 m2
Chris@249 404 fi;
Chris@98 405 fi;
Chris@98 406
Chris@161 407 asRows m =
Chris@208 408 map do i: getRow i m done [0 .. (height m) - 1];
Chris@161 409
Chris@161 410 asColumns m =
Chris@208 411 map do i: getColumn i m done [0 .. (width m) - 1];
Chris@161 412
Chris@178 413 concatAgainstGrain tagger getter counter mm =
Chris@208 414 (n = counter (size (head mm));
Chris@208 415 tagger (array
Chris@177 416 (map do i:
Chris@214 417 vec.concat (map (getter i) mm)
Chris@208 418 done [0..n-1])));
Chris@177 419
Chris@178 420 concatWithGrain tagger getter counter mm =
Chris@208 421 tagger (array
Chris@177 422 (concat
Chris@177 423 (map do m:
Chris@208 424 n = counter (size m);
Chris@208 425 map do i: getter i m done [0..n-1]
Chris@208 426 done mm)));
Chris@177 427
Chris@178 428 checkDimensionsFor direction first mm =
Chris@178 429 (counter = if direction == Horizontal () then (.rows) else (.columns) fi;
Chris@208 430 n = counter (size first);
Chris@208 431 if not (all id (map do m: counter (size m) == n done mm)) then
Chris@208 432 failWith "Matrix dimensions incompatible for concat (found \(map do m: counter (size m) done mm) not all of which are \(n))";
Chris@178 433 fi);
Chris@178 434
Chris@187 435 concat direction mm = //!!! doc: storage order is taken from first matrix in sequence
Chris@187 436 //!!! would this be better as separate concatHorizontal/concatVertical functions?
Chris@190 437 case mm of
Chris@190 438 first::rest:
Chris@178 439 checkDimensionsFor direction first mm;
Chris@208 440 row = isRowMajor? first;
Chris@178 441 // horizontal, row-major: against grain with rows
Chris@178 442 // horizontal, col-major: with grain with cols
Chris@178 443 // vertical, row-major: with grain with rows
Chris@178 444 // vertical, col-major: against grain with cols
Chris@178 445 case direction of
Chris@178 446 Horizontal ():
Chris@234 447 if row then concatAgainstGrain DenseRows getRow (.rows) mm;
Chris@234 448 else concatWithGrain DenseCols getColumn (.columns) mm;
Chris@178 449 fi;
Chris@178 450 Vertical ():
Chris@234 451 if row then concatWithGrain DenseRows getRow (.rows) mm;
Chris@234 452 else concatAgainstGrain DenseCols getColumn (.columns) mm;
Chris@178 453 fi;
Chris@178 454 esac;
Chris@190 455 [single]: single;
Chris@190 456 _: zeroSizeMatrix ();
Chris@190 457 esac;
Chris@177 458
Chris@240 459 //!!! inconsistent with std.slice which has start..end not start+count (see also vec.slice/rangeOf)
Chris@187 460 rowSlice start count m = //!!! doc: storage order same as input
Chris@208 461 if isRowMajor? m then
Chris@234 462 DenseRows (array (map ((flip getRow) m) [start .. start + count - 1]))
Chris@187 463 else
Chris@234 464 DenseCols (array (map (vec.rangeOf start count) (asColumns m)))
Chris@187 465 fi;
Chris@187 466
Chris@187 467 columnSlice start count m = //!!! doc: storage order same as input
Chris@208 468 if not isRowMajor? m then
Chris@234 469 DenseCols (array (map ((flip getColumn) m) [start .. start + count - 1]))
Chris@187 470 else
Chris@234 471 DenseRows (array (map (vec.rangeOf start count) (asRows m)))
Chris@187 472 fi;
Chris@187 473
Chris@201 474 resizedTo newsize m =
Chris@208 475 (if newsize == (size m) then
Chris@201 476 m
Chris@208 477 elif (height m) == 0 or (width m) == 0 then
Chris@202 478 zeroMatrixWithTypeOf m newsize;
Chris@201 479 else
Chris@208 480 growrows = newsize.rows - (height m);
Chris@208 481 growcols = newsize.columns - (width m);
Chris@208 482 rowm = isRowMajor? m;
Chris@201 483 resizedTo newsize
Chris@201 484 if rowm and growrows < 0 then
Chris@201 485 rowSlice 0 newsize.rows m
Chris@201 486 elif (not rowm) and growcols < 0 then
Chris@201 487 columnSlice 0 newsize.columns m
Chris@201 488 elif growrows < 0 then
Chris@201 489 rowSlice 0 newsize.rows m
Chris@201 490 elif growcols < 0 then
Chris@201 491 columnSlice 0 newsize.columns m
Chris@201 492 else
Chris@201 493 if growrows > 0 then
Chris@201 494 concat (Vertical ())
Chris@208 495 [m, zeroMatrixWithTypeOf m ((size m) with { rows = growrows })]
Chris@201 496 else
Chris@201 497 concat (Horizontal ())
Chris@208 498 [m, zeroMatrixWithTypeOf m ((size m) with { columns = growcols })]
Chris@201 499 fi
Chris@201 500 fi
Chris@202 501 fi);
Chris@201 502
Chris@5 503 {
Chris@208 504 size,
Chris@208 505 width,
Chris@208 506 height,
Chris@246 507 density,
Chris@249 508 nonZeroValues,
Chris@208 509 getAt,
Chris@208 510 getColumn,
Chris@208 511 getRow,
Chris@208 512 isRowMajor?,
Chris@234 513 isSparse?,
Chris@208 514 generate,
Chris@208 515 constMatrix,
Chris@208 516 randomMatrix,
Chris@208 517 zeroMatrix,
Chris@208 518 identityMatrix,
Chris@208 519 zeroSizeMatrix,
Chris@208 520 equal,
Chris@226 521 equalUnder,
Chris@208 522 transposed,
Chris@208 523 flipped,
Chris@208 524 toRowMajor,
Chris@208 525 toColumnMajor,
Chris@238 526 toSparse,
Chris@238 527 toDense,
Chris@208 528 scaled,
Chris@243 529 thresholded,
Chris@208 530 resizedTo,
Chris@208 531 asRows,
Chris@208 532 asColumns,
Chris@208 533 sum = sum',
Chris@229 534 difference,
Chris@229 535 abs = abs',
Chris@208 536 product,
Chris@208 537 concat,
Chris@208 538 rowSlice,
Chris@208 539 columnSlice,
Chris@208 540 newMatrix,
Chris@208 541 newRowVector,
Chris@208 542 newColumnVector,
Chris@245 543 newSparseMatrix = makeSparse
Chris@208 544 }
Chris@208 545 as
Chris@208 546 {
Chris@208 547 //!!! check whether these are right to be .selector rather than just selector
Chris@208 548
Chris@208 549 size is matrix -> { .rows is number, .columns is number },
Chris@208 550 width is matrix -> number,
Chris@208 551 height is matrix -> number,
Chris@246 552 density is matrix -> number,
Chris@249 553 nonZeroValues is matrix -> number,
Chris@208 554 getAt is number -> number -> matrix -> number,
Chris@214 555 getColumn is number -> matrix -> vector,
Chris@214 556 getRow is number -> matrix -> vector,
Chris@208 557 isRowMajor? is matrix -> boolean,
Chris@234 558 isSparse? is matrix -> boolean,
Chris@195 559 generate is (number -> number -> number) -> { .rows is number, .columns is number } -> matrix,
Chris@195 560 constMatrix is number -> { .rows is number, .columns is number } -> matrix,
Chris@195 561 randomMatrix is { .rows is number, .columns is number } -> matrix,
Chris@195 562 zeroMatrix is { .rows is number, .columns is number } -> matrix,
Chris@195 563 identityMatrix is { .rows is number, .columns is number } -> matrix,
Chris@195 564 zeroSizeMatrix is () -> matrix,
Chris@195 565 equal is matrix -> matrix -> boolean,
Chris@226 566 equalUnder is (number -> number -> boolean) -> matrix -> matrix -> boolean,
Chris@195 567 transposed is matrix -> matrix,
Chris@195 568 flipped is matrix -> matrix,
Chris@195 569 toRowMajor is matrix -> matrix,
Chris@195 570 toColumnMajor is matrix -> matrix,
Chris@243 571 toSparse is matrix -> matrix,
Chris@238 572 toDense is matrix -> matrix,
Chris@195 573 scaled is number -> matrix -> matrix,
Chris@243 574 thresholded is number -> matrix -> matrix,
Chris@195 575 resizedTo is { .rows is number, .columns is number } -> matrix -> matrix,
Chris@214 576 asRows is matrix -> list<vector>,
Chris@214 577 asColumns is matrix -> list<vector>,
Chris@208 578 sum is matrix -> matrix -> matrix,
Chris@229 579 difference is matrix -> matrix -> matrix,
Chris@229 580 abs is matrix -> matrix,
Chris@195 581 product is matrix -> matrix -> matrix,
Chris@195 582 concat is (Horizontal () | Vertical ()) -> list<matrix> -> matrix,
Chris@195 583 rowSlice is number -> number -> matrix -> matrix,
Chris@195 584 columnSlice is number -> number -> matrix -> matrix,
Chris@214 585 newMatrix is (ColumnMajor () | RowMajor ()) -> list<vector> -> matrix,
Chris@214 586 newRowVector is vector -> matrix,
Chris@214 587 newColumnVector is vector -> matrix,
Chris@245 588 newSparseMatrix is (ColumnMajor () | RowMajor ()) -> { .rows is number, .columns is number } -> list<{ .i is number, .j is number, .v is number }> -> matrix
Chris@5 589 }
Chris@5 590