annotate yetilab/matrix/matrix.yeti @ 254:5eb57c649de0 sparse

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