Mercurial > hg > may
changeset 273:197d23954a4e
Move some of the most commonly loaded modules up a level
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/complex.yeti Thu May 23 19:33:06 2013 +0100 @@ -0,0 +1,98 @@ + +module yetilab.complex; + +load yetilab.vector.type; +load yetilab.complex.type; + +vec = load yetilab.vector; + +import java.lang: ClassCastException; + +class Cplx(double real, double imag) + int getReal() + real, + int getImag() + imag, + double getMagnitude() + sqrt (real * real + imag * imag), + double getAngle() + Math#atan2(imag, real), + String toString() + if real == int real and imag == int imag then + if imag < 0 then + " \(int real) - \(int (-imag))i" + else + " \(int real) + \(int imag)i" + fi + else + if imag < 0 then + " \(real) - \((-imag))i" + else + " \(real) + \(imag)i" + fi + fi, + int hashCode() + Double#valueOf(real)#hashCode() + Double#valueOf(imag)#hashCode(), + boolean equals(Object other) + try + c = other unsafely_as ~Cplx; + c#getReal() == real and c#getImag() == imag + catch ClassCastException: + false + yrt, +end; + +real c1 is ~Cplx -> number = + c1#getReal(); + +imaginary c1 is ~Cplx -> number = + c1#getImag(); + +complex re im is number -> number -> ~Cplx = + new Cplx(re, im); + +magnitude c is ~Cplx -> number = + c#getMagnitude(); + +angle c is ~Cplx -> number = + c#getAngle(); + +add c1 c2 is ~Cplx -> ~Cplx -> ~Cplx = + complex (real c1 + real c2) (imaginary c1 + imaginary c2); + +scale r c is number -> ~Cplx -> ~Cplx = + complex (r * real c) (r * imaginary c); + +zeros n is number -> array<~Cplx> = + array (map \(complex 0 0) [1..n]); + +magnitudes cc is list?<~Cplx> -> vector = + vec.fromList (map magnitude cc); + +angles cc is list?<~Cplx> -> vector = + vec.fromList (map angle cc); + +{ + real, + imaginary, + complex, + magnitude, + angle, + add, + scale, + zeros, + magnitudes, + angles, +} as { + real is cplx -> number, + imaginary is cplx -> number, + complex is number -> number -> cplx, + magnitude is cplx -> number, + angle is cplx -> number, + add is cplx -> cplx -> cplx, + scale is number -> cplx -> cplx, + zeros is number -> array<cplx>, + magnitudes is list?<cplx> -> vector, + angles is list?<cplx> -> vector, +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/complex/type.yeti Thu May 23 19:33:06 2013 +0100 @@ -0,0 +1,7 @@ + +module yetilab.complex.type; + +typedef opaque cplx = ~yetilab.Cplx; + +(); +
--- a/yetilab/feature/feature.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/feature/feature.yeti Thu May 23 19:33:06 2013 +0100 @@ -1,7 +1,7 @@ module yetilab.feature.feature; -vec = load yetilab.vector.vector; +vec = load yetilab.vector; fr = load yetilab.stream.framer; // Utility functions for feature extractors
--- a/yetilab/feature/specdiff.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/feature/specdiff.yeti Thu May 23 19:33:06 2013 +0100 @@ -1,9 +1,9 @@ module yetilab.feature.specdiff; -vec = load yetilab.vector.vector; +vec = load yetilab.vector; fr = load yetilab.stream.framer; -cplx = load yetilab.vector.complex; +cplx = load yetilab.complex; load yetilab.feature.feature;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/matrix.yeti Thu May 23 19:33:06 2013 +0100 @@ -0,0 +1,770 @@ + +module yetilab.matrix; + +// A matrix is an array of vectors. + +// A matrix can be stored in either column-major (the default) or +// row-major format. Storage order is an efficiency concern only: +// every API function operating on matrix objects will return the same +// result regardless of storage order. (The transpose function just +// switches the row/column order without moving the elements.) + +vec = load yetilab.vector; +bf = load yetilab.vector.blockfuncs; + +load yetilab.vector.type; +load yetilab.matrix.type; + +size m = + case m of + DenseRows r: + major = length r; + { + rows = major, + columns = if major > 0 then vec.length r[0] else 0 fi, + }; + DenseCols c: + major = length c; + { + rows = if major > 0 then vec.length c[0] else 0 fi, + columns = major, + }; + SparseCSR { values, indices, pointers, extent }: + { + rows = (length pointers) - 1, + columns = extent + }; + SparseCSC { values, indices, pointers, extent }: + { + rows = extent, + columns = (length pointers) - 1 + }; + esac; + +width m = (size m).columns; +height m = (size m).rows; + +nonZeroValues m = + (nz d = + sum + (map do v: + sum (map do n: if n == 0 then 0 else 1 fi done (vec.list v)) + done d); + case m of + DenseRows d: nz d; + DenseCols d: nz d; + SparseCSR d: vec.length d.values; + SparseCSC d: vec.length d.values; + esac); + +density m = + ({ rows, columns } = size m; + cells = rows * columns; + (nonZeroValues m) / cells); + +sparseSlice n d = + (start = d.pointers[n]; + end = d.pointers[n+1]; + { + values = vec.slice d.values start end, + indices = slice d.indices start end, + }); + +nonEmptySlices d = + (ne = array []; + for [0..length d.pointers - 2] do i: + if d.pointers[i] != d.pointers[i+1] then + push ne i + fi + done; + ne); + +fromSlice n m d = + (slice = sparseSlice n d; + var v = 0; + for [0..length slice.indices - 1] do i: + if slice.indices[i] == m then + v := vec.at slice.values i; + fi + done; + v); + +filledSlice n d = + (slice = sparseSlice n d; + dslice = new double[d.extent]; + for [0..length slice.indices - 1] do i: + dslice[slice.indices[i]] := vec.at slice.values i; + done; + vec.vector dslice); + +at' m row col = + case m of + DenseRows rows: r = rows[row]; vec.at r col; + DenseCols cols: c = cols[col]; vec.at c row; + SparseCSR data: fromSlice row col data; + SparseCSC data: fromSlice col row data; + esac; + +getColumn j m = + case m of + DenseCols cols: cols[j]; + SparseCSC data: filledSlice j data; + _: vec.fromList (map do i: at' m i j done [0..height m - 1]); + esac; + +getRow i m = + case m of + DenseRows rows: rows[i]; + SparseCSR data: filledSlice i data; + _: vec.fromList (map do j: at' m i j done [0..width m - 1]); + esac; + +asRows m = + map do i: getRow i m done [0 .. (height m) - 1]; + +asColumns m = + map do i: getColumn i m done [0 .. (width m) - 1]; + +isRowMajor? m = + case m of + DenseRows _: true; + DenseCols _: false; + SparseCSR _: true; + SparseCSC _: false; + esac; + +isSparse? m = + case m of + DenseRows _: false; + DenseCols _: false; + SparseCSR _: true; + SparseCSC _: true; + esac; + +typeOf m = + if isRowMajor? m then RowMajor () + else ColumnMajor () + fi; + +flippedTypeOf m = + if isRowMajor? m then ColumnMajor () + else RowMajor () + fi; + +newColumnMajorStorage { rows, columns } = + if rows < 1 then array [] + else array (map \(vec.zeros rows) [1..columns]) + fi; + +zeroMatrix { rows, columns } = + DenseCols (newColumnMajorStorage { rows, columns }); + +zeroMatrixWithTypeOf m { rows, columns } = + if isRowMajor? m then + DenseRows (newColumnMajorStorage { rows = columns, columns = rows }); + else + DenseCols (newColumnMajorStorage { rows, columns }); + fi; + +zeroSizeMatrix () = zeroMatrix { rows = 0, columns = 0 }; + +generate f { rows, columns } = + if rows < 1 or columns < 1 then zeroSizeMatrix () + else + m = array (map \(new double[rows]) [1..columns]); + for [0..columns-1] do col: + for [0..rows-1] do row: + m[col][row] := f row col; + done; + done; + DenseCols (array (map vec.vector m)) + fi; + +swapij = + map do { i, j, v }: { i = j, j = i, v } done; + +//!!! should use { row = , column = , value = } instead of i, j, v? +enumerateSparse m = + (enumerate { values, indices, pointers } = + concat + (map do i: + start = pointers[i]; + end = pointers[i+1]; + map2 do j v: { i, j, v } done + (slice indices start end) + (vec.list (vec.slice values start end)) + done [0..length pointers - 2]); + case m of + SparseCSC d: swapij (enumerate d); + SparseCSR d: enumerate d; + _: []; + esac); + +enumerateDense m = + (enumerate d = + concat + (map do i: + vv = d[i]; + map2 do j v: { i, j, v } done + [0..vec.length vv - 1] + (vec.list vv); + done [0..length d - 1]); + case m of + DenseCols c: swapij (enumerate c); + DenseRows r: enumerate r; + _: []; + esac); + +enumerate m = + if isSparse? m then enumerateSparse m else enumerateDense m fi; + +// Make a sparse matrix from entries whose i, j values are known to be +// within range +makeSparse type size data = + (isRow = case type of RowMajor (): true; ColumnMajor (): false esac; + ordered = + sortBy do a b: + if a.maj == b.maj then a.min < b.min else a.maj < b.maj fi + done + (map + if isRow then + do { i, j, v }: { maj = i, min = j, v } done; + else + do { i, j, v }: { maj = j, min = i, v } done; + fi + (filter do d: d.v != 0 done data)); + tagger = if isRow then SparseCSR else SparseCSC fi; + majorSize = if isRow then size.rows else size.columns fi; + minorSize = if isRow then size.columns else size.rows fi; + pointers = array [0]; + setArrayCapacity pointers (size.rows + 1); + fillPointers n i data = + if n < majorSize then + case data of + d::rest: + (for [n..d-1] \(push pointers i); + fillPointers d (i+1) rest); + _: + for [n..majorSize-1] \(push pointers i); + esac; + fi; + fillPointers 0 0 (map (.maj) ordered); + tagger { + values = vec.fromList (map (.v) ordered), + indices = array (map (.min) ordered), + pointers, + extent = minorSize, + }); + +// Make a sparse matrix from entries that may contain out-of-range +// cells which need to be filtered out. This is the public API for +// makeSparse and is also used to discard out-of-range cells from +// resizedTo. +newSparseMatrix type size data = + makeSparse type size + (filter + do { i, j, v }: + i == int i and i >= 0 and i < size.rows and + j == int j and j >= 0 and j < size.columns + done data); + +toSparse m = + if isSparse? m then m + else + makeSparse (typeOf m) (size m) (enumerateDense m); + fi; + +toDense m = + if not (isSparse? m) then m + elif isRowMajor? m then + DenseRows (array (map do row: getRow row m done [0..height m - 1])); + else + DenseCols (array (map do col: getColumn col m done [0..width m - 1])); + fi; + +constMatrix n = generate do row col: n done; +randomMatrix = generate do row col: Math#random() done; +identityMatrix = constMatrix 1; + +transposed m = + case m of + DenseRows d: DenseCols d; + DenseCols d: DenseRows d; + SparseCSR d: SparseCSC d; + SparseCSC d: SparseCSR d; + esac; + +flipped m = + if isSparse? m then + makeSparse (flippedTypeOf m) (size m) (enumerateSparse m) + else + if isRowMajor? m then + generate do row col: at' m row col done (size m); + else + transposed + (generate do row col: at' m col row done + { rows = (width m), columns = (height m) }); + fi + fi; + +toRowMajor m = + if isRowMajor? m then m else flipped m fi; + +toColumnMajor m = + if not isRowMajor? m then m else flipped m fi; + +equal'' comparator vecComparator m1 m2 = + // Prerequisite: m1 and m2 have same sparse-p and storage order + (compareVecLists vv1 vv2 = all id (map2 vecComparator vv1 vv2); + compareSparse d1 d2 = + d1.extent == d2.extent and + vecComparator d1.values d2.values and + d1.indices == d2.indices and + d1.pointers == d2.pointers; + case m1 of + DenseRows d1: + case m2 of DenseRows d2: compareVecLists d1 d2; _: false; esac; + DenseCols d1: + case m2 of DenseCols d2: compareVecLists d1 d2; _: false; esac; + SparseCSR d1: + case m2 of SparseCSR d2: compareSparse d1 d2; _: false; esac; + SparseCSC d1: + case m2 of SparseCSC d2: compareSparse d1 d2; _: false; esac; + esac); + +equal' comparator vecComparator m1 m2 = + if size m1 != size m2 then + false + elif isRowMajor? m1 != isRowMajor? m2 then + equal' comparator vecComparator (flipped m1) m2; + elif isSparse? m1 != isSparse? m2 then + if isSparse? m1 then + equal' comparator vecComparator m1 (toSparse m2) + else + equal' comparator vecComparator (toSparse m1) m2 + fi + else + equal'' comparator vecComparator m1 m2 + fi; + +// Compare matrices using the given comparator for individual cells. +// Note that matrices with different storage order but the same +// contents are equal, although comparing them is slow. +//!!! Document the fact that sparse matrices can only be equal if they +// have the same set of non-zero cells (regardless of comparator used) +equalUnder comparator = + equal' comparator (vec.equalUnder comparator); + +equal = + equal' (==) vec.equal; + +newMatrix type data = //!!! NB does not copy data + (tagger = case type of RowMajor (): DenseRows; ColumnMajor (): DenseCols esac; + if empty? data or vec.empty? (head data) + then zeroSizeMatrix () + else tagger (array data) + fi); + +newRowVector data = //!!! NB does not copy data + DenseRows (array [data]); + +newColumnVector data = //!!! NB does not copy data + DenseCols (array [data]); + +denseLinearOp op m1 m2 = + if isRowMajor? m1 then + newMatrix (typeOf m1) + (map2 do c1 c2: op c1 c2 done (asRows m1) (asRows m2)); + else + newMatrix (typeOf m1) + (map2 do c1 c2: op c1 c2 done (asColumns m1) (asColumns m2)); + fi; + +sparseSumOrDifference op m1 m2 = + (h = [:]; + for (enumerate m1) do { i, j, v }: + if not (i in h) then h[i] := [:] fi; + h[i][j] := v; + done; + for (enumerate m2) do { i, j, v }: + if not (i in h) then h[i] := [:] fi; + if j in h[i] then h[i][j] := op h[i][j] v; + else h[i][j] := op 0 v; + fi; + done; + entries = concat + (map do i: + kk = keys h[i]; + map2 do j v: { i, j, v } done kk (map (at h[i]) kk) + done (keys h)); + makeSparse (typeOf m1) (size m1) entries); + +sum' m1 m2 = + if (size m1) != (size m2) + then failWith "Matrices are not the same size: \(size m1), \(size m2)"; + elif isSparse? m1 and isSparse? m2 then + sparseSumOrDifference (+) m1 m2; + else + denseLinearOp bf.add m1 m2; + fi; + +difference m1 m2 = + if (size m1) != (size m2) + then failWith "Matrices are not the same size: \(size m1), \(size m2)"; + elif isSparse? m1 and isSparse? m2 then + sparseSumOrDifference (-) m1 m2; + else + denseLinearOp bf.subtract m1 m2; + fi; + +scaled factor m = + if isSparse? m then + makeSparse (typeOf m) (size m) + (map do { i, j, v }: { i, j, v = factor * v } done (enumerate m)) + elif isRowMajor? m then + newMatrix (typeOf m) (map (bf.scaled factor) (asRows m)); + else + newMatrix (typeOf m) (map (bf.scaled factor) (asColumns m)); + fi; + +abs' m = + if isSparse? m then + makeSparse (typeOf m) (size m) + (map do { i, j, v }: { i, j, v = abs v } done (enumerate m)) + elif isRowMajor? m then + newMatrix (typeOf m) (map bf.abs (asRows m)); + else + newMatrix (typeOf m) (map bf.abs (asColumns m)); + fi; + +filter f m = + if isSparse? m then + makeSparse (typeOf m) (size m) + (map do { i, j, v }: { i, j, v = if f v then v else 0 fi } done + (enumerate m)) + else + vfilter = vec.fromList . (map do i: if f i then i else 0 fi done) . vec.list; + if isRowMajor? m then + newMatrix (typeOf m) (map vfilter (asRows m)); + else + newMatrix (typeOf m) (map vfilter (asColumns m)); + fi; + fi; + +sparseProductLeft size m1 m2 = + ({ values, indices, pointers } = case m1 of + SparseCSR d: d; + SparseCSC d: d; + _: failWith "sparseProductLeft called for non-sparse m1"; + esac; + rows = isRowMajor? m1; + data = array (map \(new double[size.rows]) [1..size.columns]); + for [0..size.columns - 1] do j': + c = getColumn j' m2; + var p = 0; + for [0..length indices - 1] do ix: + ix == pointers[p+1] loop (p := p + 1); + i = if rows then p else indices[ix] fi; + j = if rows then indices[ix] else p fi; + data[j'][i] := data[j'][i] + (vec.at values ix) * (vec.at c j); + done; + done; + DenseCols (array (map vec.vector (list data)))); + +sparseProductRight size m1 m2 = + ({ values, indices, pointers } = case m2 of + SparseCSR d: d; + SparseCSC d: d; + _: failWith "sparseProductLeft called for non-sparse m1"; + esac; + rows = isRowMajor? m2; + data = array (map \(new double[size.columns]) [1..size.rows]); + for [0..size.rows - 1] do i': + r = getRow i' m1; + var p = 0; + for [0..length indices - 1] do ix: + ix == pointers[p+1] loop (p := p + 1); + i = if rows then p else indices[ix] fi; + j = if rows then indices[ix] else p fi; + data[i'][j] := data[i'][j] + (vec.at values ix) * (vec.at r i); + done; + done; + DenseRows (array (map vec.vector (list data)))); + +sparseProduct size m1 m2 = + case m2 of + SparseCSC d: + ({ values, indices, pointers } = case m1 of + SparseCSR d1: d1; + SparseCSC d1: d1; + _: failWith "sparseProduct called for non-sparse matrices"; + esac; + rows = isRowMajor? m1; + var p = 0; + pindices = new int[length indices]; + for [0..length indices - 1] do ix: + ix == pointers[p+1] loop (p := p + 1); + pindices[ix] := p; + done; + entries = + (map do j': + cs = sparseSlice j' d; + hin = mapIntoHash + (at cs.indices) (vec.at cs.values) + [0..length cs.indices - 1]; + hout = [:]; + for [0..length indices - 1] do ix: + i = if rows then pindices[ix] else indices[ix] fi; + j = if rows then indices[ix] else pindices[ix] fi; + if j in hin then + p = (vec.at values ix) * hin[j]; + hout[i] := p + (if i in hout then hout[i] else 0 fi); + fi; + done; + map do i: + { i, j = j', v = hout[i] } + done (keys hout); + done (nonEmptySlices d)); + makeSparse (ColumnMajor ()) size (concat entries)); + SparseCSR _: + sparseProduct size m1 (flipped m2); + _: failWith "sparseProduct called for non-sparse matrices"; + esac; + +denseProduct size m1 m2 = + (data = array (map \(new double[size.rows]) [1..size.columns]); + for [0..size.rows - 1] do i: + row = getRow i m1; + for [0..size.columns - 1] do j: + data[j][i] := bf.sum (bf.multiply row (getColumn j m2)); + done; + done; + DenseCols (array (map vec.vector (list data)))); + +product m1 m2 = + if (size m1).columns != (size m2).rows + then failWith "Matrix dimensions incompatible: \(size m1), \(size m2) (\((size m1).columns) != \((size m2).rows))"; + else + size = { rows = (size m1).rows, columns = (size m2).columns }; + if isSparse? m1 then + if isSparse? m2 then + sparseProduct size m1 m2 + else + sparseProductLeft size m1 m2 + fi + elif isSparse? m2 then + sparseProductRight size m1 m2 + else + denseProduct size m1 m2 + fi; + fi; + +concatAgainstGrain tagger getter counter mm = + (n = counter (size (head mm)); + tagger (array + (map do i: + vec.concat (map (getter i) mm) + done [0..n-1]))); + +concatWithGrain tagger getter counter mm = + tagger (array + (concat + (map do m: + n = counter (size m); + map do i: getter i m done [0..n-1] + done mm))); + +sparseConcat direction first mm = + (dimension d f = if direction == d then sum (map f mm) else f first fi; + rows = dimension (Vertical ()) height; + columns = dimension (Horizontal ()) width; + entries ioff joff ui uj mm = + case mm of + m::rest: + (map do { i, j, v }: { i = i + ioff, j = j + joff, v } + done (enumerate m)) ++ + (entries + (ioff + ui * height m) + (joff + uj * width m) + ui uj rest); + _: [] + esac; + makeSparse (typeOf first) { rows, columns } + if direction == Vertical () then entries 0 0 1 0 mm + else entries 0 0 0 1 mm fi); + +checkDimensionsFor direction first mm = + (counter = if direction == Horizontal () then (.rows) else (.columns) fi; + n = counter (size first); + if not (all id (map do m: counter (size m) == n done mm)) then + failWith "Matrix dimensions incompatible for concat (found \(map do m: counter (size m) done mm) not all of which are \(n))"; + fi); + +concat direction mm = //!!! doc: storage order is taken from first matrix in sequence + case length mm of + 0: zeroSizeMatrix (); + 1: head mm; + _: + first = head mm; + checkDimensionsFor direction first mm; + if all isSparse? mm then + sparseConcat direction first mm + else + row = isRowMajor? first; + // horizontal, row-major: against grain with rows + // horizontal, col-major: with grain with cols + // vertical, row-major: with grain with rows + // vertical, col-major: against grain with cols + case direction of + Horizontal (): + if row then concatAgainstGrain DenseRows getRow (.rows) mm; + else concatWithGrain DenseCols getColumn (.columns) mm; + fi; + Vertical (): + if row then concatWithGrain DenseRows getRow (.rows) mm; + else concatAgainstGrain DenseCols getColumn (.columns) mm; + fi; + esac; + fi; + esac; + +//!!! doc note: argument order chosen for consistency with std module slice +rowSlice m start end = //!!! doc: storage order same as input + if isRowMajor? m then + DenseRows (array (map ((flip getRow) m) [start .. end - 1])) + else + DenseCols (array (map do v: vec.slice v start end done (asColumns m))) + fi; + +//!!! doc note: argument order chosen for consistency with std module slice +columnSlice m start end = //!!! doc: storage order same as input + if not isRowMajor? m then + DenseCols (array (map ((flip getColumn) m) [start .. end - 1])) + else + DenseRows (array (map do v: vec.slice v start end done (asRows m))) + fi; + +resizedTo newsize m = + (if newsize == (size m) then + m + elif isSparse? m then + // don't call makeSparse directly: want to discard + // out-of-range cells + newSparseMatrix (typeOf m) newsize (enumerateSparse m) + elif (height m) == 0 or (width m) == 0 then + zeroMatrixWithTypeOf m newsize; + else + growrows = newsize.rows - (height m); + growcols = newsize.columns - (width m); + rowm = isRowMajor? m; + resizedTo newsize + if rowm and growrows < 0 then + rowSlice m 0 newsize.rows + elif (not rowm) and growcols < 0 then + columnSlice m 0 newsize.columns + elif growrows < 0 then + rowSlice m 0 newsize.rows + elif growcols < 0 then + columnSlice m 0 newsize.columns + else + if growrows > 0 then + concat (Vertical ()) + [m, zeroMatrixWithTypeOf m ((size m) with { rows = growrows })] + else + concat (Horizontal ()) + [m, zeroMatrixWithTypeOf m ((size m) with { columns = growcols })] + fi + fi + fi); + +{ + size, + width, + height, + density, + nonZeroValues, + at = at', + getColumn, + getRow, + isRowMajor?, + isSparse?, + generate, + constMatrix, + randomMatrix, + zeroMatrix, + identityMatrix, + zeroSizeMatrix, + equal, + equalUnder, + transposed, + flipped, + toRowMajor, + toColumnMajor, + toSparse, + toDense, + scaled, + resizedTo, + asRows, + asColumns, + sum = sum', + difference, + abs = abs', + filter, + product, + concat, + rowSlice, + columnSlice, + newMatrix, + newRowVector, + newColumnVector, + newSparseMatrix, + enumerate +} +as +{ +//!!! check whether these are right to be .selector rather than just selector + + size is matrix -> { .rows is number, .columns is number }, + width is matrix -> number, + height is matrix -> number, + density is matrix -> number, + nonZeroValues is matrix -> number, + at is matrix -> number -> number -> number, + getColumn is number -> matrix -> vector, + getRow is number -> matrix -> vector, + isRowMajor? is matrix -> boolean, + isSparse? is matrix -> boolean, + generate is (number -> number -> number) -> { .rows is number, .columns is number } -> matrix, + constMatrix is number -> { .rows is number, .columns is number } -> matrix, + randomMatrix is { .rows is number, .columns is number } -> matrix, + zeroMatrix is { .rows is number, .columns is number } -> matrix, + identityMatrix is { .rows is number, .columns is number } -> matrix, + zeroSizeMatrix is () -> matrix, + equal is matrix -> matrix -> boolean, + equalUnder is (number -> number -> boolean) -> matrix -> matrix -> boolean, + transposed is matrix -> matrix, + flipped is matrix -> matrix, + toRowMajor is matrix -> matrix, + toColumnMajor is matrix -> matrix, + toSparse is matrix -> matrix, + toDense is matrix -> matrix, + scaled is number -> matrix -> matrix, + thresholded is number -> matrix -> matrix, + resizedTo is { .rows is number, .columns is number } -> matrix -> matrix, + asRows is matrix -> list<vector>, + asColumns is matrix -> list<vector>, + sum is matrix -> matrix -> matrix, + difference is matrix -> matrix -> matrix, + abs is matrix -> matrix, + filter is (number -> boolean) -> matrix -> matrix, + product is matrix -> matrix -> matrix, + concat is (Horizontal () | Vertical ()) -> list<matrix> -> matrix, + rowSlice is matrix -> number -> number -> matrix, + columnSlice is matrix -> number -> number -> matrix, + newMatrix is (ColumnMajor () | RowMajor ()) -> list<vector> -> matrix, + newRowVector is vector -> matrix, + newColumnVector is vector -> matrix, + newSparseMatrix is (ColumnMajor () | RowMajor ()) -> { .rows is number, .columns is number } -> list<{ .i is number, .j is number, .v is number }> -> matrix, + enumerate is matrix -> list<{ .i is number, .j is number, .v is number }> +} +
--- a/yetilab/matrix/matrix.yeti Thu May 23 17:15:27 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,770 +0,0 @@ - -module yetilab.matrix.matrix; - -// A matrix is an array of vectors. - -// A matrix can be stored in either column-major (the default) or -// row-major format. Storage order is an efficiency concern only: -// every API function operating on matrix objects will return the same -// result regardless of storage order. (The transpose function just -// switches the row/column order without moving the elements.) - -vec = load yetilab.vector.vector; -bf = load yetilab.vector.blockfuncs; - -load yetilab.vector.vectortype; -load yetilab.matrix.matrixtype; - -size m = - case m of - DenseRows r: - major = length r; - { - rows = major, - columns = if major > 0 then vec.length r[0] else 0 fi, - }; - DenseCols c: - major = length c; - { - rows = if major > 0 then vec.length c[0] else 0 fi, - columns = major, - }; - SparseCSR { values, indices, pointers, extent }: - { - rows = (length pointers) - 1, - columns = extent - }; - SparseCSC { values, indices, pointers, extent }: - { - rows = extent, - columns = (length pointers) - 1 - }; - esac; - -width m = (size m).columns; -height m = (size m).rows; - -nonZeroValues m = - (nz d = - sum - (map do v: - sum (map do n: if n == 0 then 0 else 1 fi done (vec.list v)) - done d); - case m of - DenseRows d: nz d; - DenseCols d: nz d; - SparseCSR d: vec.length d.values; - SparseCSC d: vec.length d.values; - esac); - -density m = - ({ rows, columns } = size m; - cells = rows * columns; - (nonZeroValues m) / cells); - -sparseSlice n d = - (start = d.pointers[n]; - end = d.pointers[n+1]; - { - values = vec.slice d.values start end, - indices = slice d.indices start end, - }); - -nonEmptySlices d = - (ne = array []; - for [0..length d.pointers - 2] do i: - if d.pointers[i] != d.pointers[i+1] then - push ne i - fi - done; - ne); - -fromSlice n m d = - (slice = sparseSlice n d; - var v = 0; - for [0..length slice.indices - 1] do i: - if slice.indices[i] == m then - v := vec.at slice.values i; - fi - done; - v); - -filledSlice n d = - (slice = sparseSlice n d; - dslice = new double[d.extent]; - for [0..length slice.indices - 1] do i: - dslice[slice.indices[i]] := vec.at slice.values i; - done; - vec.vector dslice); - -at' m row col = - case m of - DenseRows rows: r = rows[row]; vec.at r col; - DenseCols cols: c = cols[col]; vec.at c row; - SparseCSR data: fromSlice row col data; - SparseCSC data: fromSlice col row data; - esac; - -getColumn j m = - case m of - DenseCols cols: cols[j]; - SparseCSC data: filledSlice j data; - _: vec.fromList (map do i: at' m i j done [0..height m - 1]); - esac; - -getRow i m = - case m of - DenseRows rows: rows[i]; - SparseCSR data: filledSlice i data; - _: vec.fromList (map do j: at' m i j done [0..width m - 1]); - esac; - -asRows m = - map do i: getRow i m done [0 .. (height m) - 1]; - -asColumns m = - map do i: getColumn i m done [0 .. (width m) - 1]; - -isRowMajor? m = - case m of - DenseRows _: true; - DenseCols _: false; - SparseCSR _: true; - SparseCSC _: false; - esac; - -isSparse? m = - case m of - DenseRows _: false; - DenseCols _: false; - SparseCSR _: true; - SparseCSC _: true; - esac; - -typeOf m = - if isRowMajor? m then RowMajor () - else ColumnMajor () - fi; - -flippedTypeOf m = - if isRowMajor? m then ColumnMajor () - else RowMajor () - fi; - -newColumnMajorStorage { rows, columns } = - if rows < 1 then array [] - else array (map \(vec.zeros rows) [1..columns]) - fi; - -zeroMatrix { rows, columns } = - DenseCols (newColumnMajorStorage { rows, columns }); - -zeroMatrixWithTypeOf m { rows, columns } = - if isRowMajor? m then - DenseRows (newColumnMajorStorage { rows = columns, columns = rows }); - else - DenseCols (newColumnMajorStorage { rows, columns }); - fi; - -zeroSizeMatrix () = zeroMatrix { rows = 0, columns = 0 }; - -generate f { rows, columns } = - if rows < 1 or columns < 1 then zeroSizeMatrix () - else - m = array (map \(new double[rows]) [1..columns]); - for [0..columns-1] do col: - for [0..rows-1] do row: - m[col][row] := f row col; - done; - done; - DenseCols (array (map vec.vector m)) - fi; - -swapij = - map do { i, j, v }: { i = j, j = i, v } done; - -//!!! should use { row = , column = , value = } instead of i, j, v? -enumerateSparse m = - (enumerate { values, indices, pointers } = - concat - (map do i: - start = pointers[i]; - end = pointers[i+1]; - map2 do j v: { i, j, v } done - (slice indices start end) - (vec.list (vec.slice values start end)) - done [0..length pointers - 2]); - case m of - SparseCSC d: swapij (enumerate d); - SparseCSR d: enumerate d; - _: []; - esac); - -enumerateDense m = - (enumerate d = - concat - (map do i: - vv = d[i]; - map2 do j v: { i, j, v } done - [0..vec.length vv - 1] - (vec.list vv); - done [0..length d - 1]); - case m of - DenseCols c: swapij (enumerate c); - DenseRows r: enumerate r; - _: []; - esac); - -enumerate m = - if isSparse? m then enumerateSparse m else enumerateDense m fi; - -// Make a sparse matrix from entries whose i, j values are known to be -// within range -makeSparse type size data = - (isRow = case type of RowMajor (): true; ColumnMajor (): false esac; - ordered = - sortBy do a b: - if a.maj == b.maj then a.min < b.min else a.maj < b.maj fi - done - (map - if isRow then - do { i, j, v }: { maj = i, min = j, v } done; - else - do { i, j, v }: { maj = j, min = i, v } done; - fi - (filter do d: d.v != 0 done data)); - tagger = if isRow then SparseCSR else SparseCSC fi; - majorSize = if isRow then size.rows else size.columns fi; - minorSize = if isRow then size.columns else size.rows fi; - pointers = array [0]; - setArrayCapacity pointers (size.rows + 1); - fillPointers n i data = - if n < majorSize then - case data of - d::rest: - (for [n..d-1] \(push pointers i); - fillPointers d (i+1) rest); - _: - for [n..majorSize-1] \(push pointers i); - esac; - fi; - fillPointers 0 0 (map (.maj) ordered); - tagger { - values = vec.fromList (map (.v) ordered), - indices = array (map (.min) ordered), - pointers, - extent = minorSize, - }); - -// Make a sparse matrix from entries that may contain out-of-range -// cells which need to be filtered out. This is the public API for -// makeSparse and is also used to discard out-of-range cells from -// resizedTo. -newSparseMatrix type size data = - makeSparse type size - (filter - do { i, j, v }: - i == int i and i >= 0 and i < size.rows and - j == int j and j >= 0 and j < size.columns - done data); - -toSparse m = - if isSparse? m then m - else - makeSparse (typeOf m) (size m) (enumerateDense m); - fi; - -toDense m = - if not (isSparse? m) then m - elif isRowMajor? m then - DenseRows (array (map do row: getRow row m done [0..height m - 1])); - else - DenseCols (array (map do col: getColumn col m done [0..width m - 1])); - fi; - -constMatrix n = generate do row col: n done; -randomMatrix = generate do row col: Math#random() done; -identityMatrix = constMatrix 1; - -transposed m = - case m of - DenseRows d: DenseCols d; - DenseCols d: DenseRows d; - SparseCSR d: SparseCSC d; - SparseCSC d: SparseCSR d; - esac; - -flipped m = - if isSparse? m then - makeSparse (flippedTypeOf m) (size m) (enumerateSparse m) - else - if isRowMajor? m then - generate do row col: at' m row col done (size m); - else - transposed - (generate do row col: at' m col row done - { rows = (width m), columns = (height m) }); - fi - fi; - -toRowMajor m = - if isRowMajor? m then m else flipped m fi; - -toColumnMajor m = - if not isRowMajor? m then m else flipped m fi; - -equal'' comparator vecComparator m1 m2 = - // Prerequisite: m1 and m2 have same sparse-p and storage order - (compareVecLists vv1 vv2 = all id (map2 vecComparator vv1 vv2); - compareSparse d1 d2 = - d1.extent == d2.extent and - vecComparator d1.values d2.values and - d1.indices == d2.indices and - d1.pointers == d2.pointers; - case m1 of - DenseRows d1: - case m2 of DenseRows d2: compareVecLists d1 d2; _: false; esac; - DenseCols d1: - case m2 of DenseCols d2: compareVecLists d1 d2; _: false; esac; - SparseCSR d1: - case m2 of SparseCSR d2: compareSparse d1 d2; _: false; esac; - SparseCSC d1: - case m2 of SparseCSC d2: compareSparse d1 d2; _: false; esac; - esac); - -equal' comparator vecComparator m1 m2 = - if size m1 != size m2 then - false - elif isRowMajor? m1 != isRowMajor? m2 then - equal' comparator vecComparator (flipped m1) m2; - elif isSparse? m1 != isSparse? m2 then - if isSparse? m1 then - equal' comparator vecComparator m1 (toSparse m2) - else - equal' comparator vecComparator (toSparse m1) m2 - fi - else - equal'' comparator vecComparator m1 m2 - fi; - -// Compare matrices using the given comparator for individual cells. -// Note that matrices with different storage order but the same -// contents are equal, although comparing them is slow. -//!!! Document the fact that sparse matrices can only be equal if they -// have the same set of non-zero cells (regardless of comparator used) -equalUnder comparator = - equal' comparator (vec.equalUnder comparator); - -equal = - equal' (==) vec.equal; - -newMatrix type data = //!!! NB does not copy data - (tagger = case type of RowMajor (): DenseRows; ColumnMajor (): DenseCols esac; - if empty? data or vec.empty? (head data) - then zeroSizeMatrix () - else tagger (array data) - fi); - -newRowVector data = //!!! NB does not copy data - DenseRows (array [data]); - -newColumnVector data = //!!! NB does not copy data - DenseCols (array [data]); - -denseLinearOp op m1 m2 = - if isRowMajor? m1 then - newMatrix (typeOf m1) - (map2 do c1 c2: op c1 c2 done (asRows m1) (asRows m2)); - else - newMatrix (typeOf m1) - (map2 do c1 c2: op c1 c2 done (asColumns m1) (asColumns m2)); - fi; - -sparseSumOrDifference op m1 m2 = - (h = [:]; - for (enumerate m1) do { i, j, v }: - if not (i in h) then h[i] := [:] fi; - h[i][j] := v; - done; - for (enumerate m2) do { i, j, v }: - if not (i in h) then h[i] := [:] fi; - if j in h[i] then h[i][j] := op h[i][j] v; - else h[i][j] := op 0 v; - fi; - done; - entries = concat - (map do i: - kk = keys h[i]; - map2 do j v: { i, j, v } done kk (map (at h[i]) kk) - done (keys h)); - makeSparse (typeOf m1) (size m1) entries); - -sum' m1 m2 = - if (size m1) != (size m2) - then failWith "Matrices are not the same size: \(size m1), \(size m2)"; - elif isSparse? m1 and isSparse? m2 then - sparseSumOrDifference (+) m1 m2; - else - denseLinearOp bf.add m1 m2; - fi; - -difference m1 m2 = - if (size m1) != (size m2) - then failWith "Matrices are not the same size: \(size m1), \(size m2)"; - elif isSparse? m1 and isSparse? m2 then - sparseSumOrDifference (-) m1 m2; - else - denseLinearOp bf.subtract m1 m2; - fi; - -scaled factor m = - if isSparse? m then - makeSparse (typeOf m) (size m) - (map do { i, j, v }: { i, j, v = factor * v } done (enumerate m)) - elif isRowMajor? m then - newMatrix (typeOf m) (map (bf.scaled factor) (asRows m)); - else - newMatrix (typeOf m) (map (bf.scaled factor) (asColumns m)); - fi; - -abs' m = - if isSparse? m then - makeSparse (typeOf m) (size m) - (map do { i, j, v }: { i, j, v = abs v } done (enumerate m)) - elif isRowMajor? m then - newMatrix (typeOf m) (map bf.abs (asRows m)); - else - newMatrix (typeOf m) (map bf.abs (asColumns m)); - fi; - -filter f m = - if isSparse? m then - makeSparse (typeOf m) (size m) - (map do { i, j, v }: { i, j, v = if f v then v else 0 fi } done - (enumerate m)) - else - vfilter = vec.fromList . (map do i: if f i then i else 0 fi done) . vec.list; - if isRowMajor? m then - newMatrix (typeOf m) (map vfilter (asRows m)); - else - newMatrix (typeOf m) (map vfilter (asColumns m)); - fi; - fi; - -sparseProductLeft size m1 m2 = - ({ values, indices, pointers } = case m1 of - SparseCSR d: d; - SparseCSC d: d; - _: failWith "sparseProductLeft called for non-sparse m1"; - esac; - rows = isRowMajor? m1; - data = array (map \(new double[size.rows]) [1..size.columns]); - for [0..size.columns - 1] do j': - c = getColumn j' m2; - var p = 0; - for [0..length indices - 1] do ix: - ix == pointers[p+1] loop (p := p + 1); - i = if rows then p else indices[ix] fi; - j = if rows then indices[ix] else p fi; - data[j'][i] := data[j'][i] + (vec.at values ix) * (vec.at c j); - done; - done; - DenseCols (array (map vec.vector (list data)))); - -sparseProductRight size m1 m2 = - ({ values, indices, pointers } = case m2 of - SparseCSR d: d; - SparseCSC d: d; - _: failWith "sparseProductLeft called for non-sparse m1"; - esac; - rows = isRowMajor? m2; - data = array (map \(new double[size.columns]) [1..size.rows]); - for [0..size.rows - 1] do i': - r = getRow i' m1; - var p = 0; - for [0..length indices - 1] do ix: - ix == pointers[p+1] loop (p := p + 1); - i = if rows then p else indices[ix] fi; - j = if rows then indices[ix] else p fi; - data[i'][j] := data[i'][j] + (vec.at values ix) * (vec.at r i); - done; - done; - DenseRows (array (map vec.vector (list data)))); - -sparseProduct size m1 m2 = - case m2 of - SparseCSC d: - ({ values, indices, pointers } = case m1 of - SparseCSR d1: d1; - SparseCSC d1: d1; - _: failWith "sparseProduct called for non-sparse matrices"; - esac; - rows = isRowMajor? m1; - var p = 0; - pindices = new int[length indices]; - for [0..length indices - 1] do ix: - ix == pointers[p+1] loop (p := p + 1); - pindices[ix] := p; - done; - entries = - (map do j': - cs = sparseSlice j' d; - hin = mapIntoHash - (at cs.indices) (vec.at cs.values) - [0..length cs.indices - 1]; - hout = [:]; - for [0..length indices - 1] do ix: - i = if rows then pindices[ix] else indices[ix] fi; - j = if rows then indices[ix] else pindices[ix] fi; - if j in hin then - p = (vec.at values ix) * hin[j]; - hout[i] := p + (if i in hout then hout[i] else 0 fi); - fi; - done; - map do i: - { i, j = j', v = hout[i] } - done (keys hout); - done (nonEmptySlices d)); - makeSparse (ColumnMajor ()) size (concat entries)); - SparseCSR _: - sparseProduct size m1 (flipped m2); - _: failWith "sparseProduct called for non-sparse matrices"; - esac; - -denseProduct size m1 m2 = - (data = array (map \(new double[size.rows]) [1..size.columns]); - for [0..size.rows - 1] do i: - row = getRow i m1; - for [0..size.columns - 1] do j: - data[j][i] := bf.sum (bf.multiply row (getColumn j m2)); - done; - done; - DenseCols (array (map vec.vector (list data)))); - -product m1 m2 = - if (size m1).columns != (size m2).rows - then failWith "Matrix dimensions incompatible: \(size m1), \(size m2) (\((size m1).columns) != \((size m2).rows))"; - else - size = { rows = (size m1).rows, columns = (size m2).columns }; - if isSparse? m1 then - if isSparse? m2 then - sparseProduct size m1 m2 - else - sparseProductLeft size m1 m2 - fi - elif isSparse? m2 then - sparseProductRight size m1 m2 - else - denseProduct size m1 m2 - fi; - fi; - -concatAgainstGrain tagger getter counter mm = - (n = counter (size (head mm)); - tagger (array - (map do i: - vec.concat (map (getter i) mm) - done [0..n-1]))); - -concatWithGrain tagger getter counter mm = - tagger (array - (concat - (map do m: - n = counter (size m); - map do i: getter i m done [0..n-1] - done mm))); - -sparseConcat direction first mm = - (dimension d f = if direction == d then sum (map f mm) else f first fi; - rows = dimension (Vertical ()) height; - columns = dimension (Horizontal ()) width; - entries ioff joff ui uj mm = - case mm of - m::rest: - (map do { i, j, v }: { i = i + ioff, j = j + joff, v } - done (enumerate m)) ++ - (entries - (ioff + ui * height m) - (joff + uj * width m) - ui uj rest); - _: [] - esac; - makeSparse (typeOf first) { rows, columns } - if direction == Vertical () then entries 0 0 1 0 mm - else entries 0 0 0 1 mm fi); - -checkDimensionsFor direction first mm = - (counter = if direction == Horizontal () then (.rows) else (.columns) fi; - n = counter (size first); - if not (all id (map do m: counter (size m) == n done mm)) then - failWith "Matrix dimensions incompatible for concat (found \(map do m: counter (size m) done mm) not all of which are \(n))"; - fi); - -concat direction mm = //!!! doc: storage order is taken from first matrix in sequence - case length mm of - 0: zeroSizeMatrix (); - 1: head mm; - _: - first = head mm; - checkDimensionsFor direction first mm; - if all isSparse? mm then - sparseConcat direction first mm - else - row = isRowMajor? first; - // horizontal, row-major: against grain with rows - // horizontal, col-major: with grain with cols - // vertical, row-major: with grain with rows - // vertical, col-major: against grain with cols - case direction of - Horizontal (): - if row then concatAgainstGrain DenseRows getRow (.rows) mm; - else concatWithGrain DenseCols getColumn (.columns) mm; - fi; - Vertical (): - if row then concatWithGrain DenseRows getRow (.rows) mm; - else concatAgainstGrain DenseCols getColumn (.columns) mm; - fi; - esac; - fi; - esac; - -//!!! doc note: argument order chosen for consistency with std module slice -rowSlice m start end = //!!! doc: storage order same as input - if isRowMajor? m then - DenseRows (array (map ((flip getRow) m) [start .. end - 1])) - else - DenseCols (array (map do v: vec.slice v start end done (asColumns m))) - fi; - -//!!! doc note: argument order chosen for consistency with std module slice -columnSlice m start end = //!!! doc: storage order same as input - if not isRowMajor? m then - DenseCols (array (map ((flip getColumn) m) [start .. end - 1])) - else - DenseRows (array (map do v: vec.slice v start end done (asRows m))) - fi; - -resizedTo newsize m = - (if newsize == (size m) then - m - elif isSparse? m then - // don't call makeSparse directly: want to discard - // out-of-range cells - newSparseMatrix (typeOf m) newsize (enumerateSparse m) - elif (height m) == 0 or (width m) == 0 then - zeroMatrixWithTypeOf m newsize; - else - growrows = newsize.rows - (height m); - growcols = newsize.columns - (width m); - rowm = isRowMajor? m; - resizedTo newsize - if rowm and growrows < 0 then - rowSlice m 0 newsize.rows - elif (not rowm) and growcols < 0 then - columnSlice m 0 newsize.columns - elif growrows < 0 then - rowSlice m 0 newsize.rows - elif growcols < 0 then - columnSlice m 0 newsize.columns - else - if growrows > 0 then - concat (Vertical ()) - [m, zeroMatrixWithTypeOf m ((size m) with { rows = growrows })] - else - concat (Horizontal ()) - [m, zeroMatrixWithTypeOf m ((size m) with { columns = growcols })] - fi - fi - fi); - -{ - size, - width, - height, - density, - nonZeroValues, - at = at', - getColumn, - getRow, - isRowMajor?, - isSparse?, - generate, - constMatrix, - randomMatrix, - zeroMatrix, - identityMatrix, - zeroSizeMatrix, - equal, - equalUnder, - transposed, - flipped, - toRowMajor, - toColumnMajor, - toSparse, - toDense, - scaled, - resizedTo, - asRows, - asColumns, - sum = sum', - difference, - abs = abs', - filter, - product, - concat, - rowSlice, - columnSlice, - newMatrix, - newRowVector, - newColumnVector, - newSparseMatrix, - enumerate -} -as -{ -//!!! check whether these are right to be .selector rather than just selector - - size is matrix -> { .rows is number, .columns is number }, - width is matrix -> number, - height is matrix -> number, - density is matrix -> number, - nonZeroValues is matrix -> number, - at is matrix -> number -> number -> number, - getColumn is number -> matrix -> vector, - getRow is number -> matrix -> vector, - isRowMajor? is matrix -> boolean, - isSparse? is matrix -> boolean, - generate is (number -> number -> number) -> { .rows is number, .columns is number } -> matrix, - constMatrix is number -> { .rows is number, .columns is number } -> matrix, - randomMatrix is { .rows is number, .columns is number } -> matrix, - zeroMatrix is { .rows is number, .columns is number } -> matrix, - identityMatrix is { .rows is number, .columns is number } -> matrix, - zeroSizeMatrix is () -> matrix, - equal is matrix -> matrix -> boolean, - equalUnder is (number -> number -> boolean) -> matrix -> matrix -> boolean, - transposed is matrix -> matrix, - flipped is matrix -> matrix, - toRowMajor is matrix -> matrix, - toColumnMajor is matrix -> matrix, - toSparse is matrix -> matrix, - toDense is matrix -> matrix, - scaled is number -> matrix -> matrix, - thresholded is number -> matrix -> matrix, - resizedTo is { .rows is number, .columns is number } -> matrix -> matrix, - asRows is matrix -> list<vector>, - asColumns is matrix -> list<vector>, - sum is matrix -> matrix -> matrix, - difference is matrix -> matrix -> matrix, - abs is matrix -> matrix, - filter is (number -> boolean) -> matrix -> matrix, - product is matrix -> matrix -> matrix, - concat is (Horizontal () | Vertical ()) -> list<matrix> -> matrix, - rowSlice is matrix -> number -> number -> matrix, - columnSlice is matrix -> number -> number -> matrix, - newMatrix is (ColumnMajor () | RowMajor ()) -> list<vector> -> matrix, - newRowVector is vector -> matrix, - newColumnVector is vector -> matrix, - newSparseMatrix is (ColumnMajor () | RowMajor ()) -> { .rows is number, .columns is number } -> list<{ .i is number, .j is number, .v is number }> -> matrix, - enumerate is matrix -> list<{ .i is number, .j is number, .v is number }> -} -
--- a/yetilab/matrix/matrixtype.yeti Thu May 23 17:15:27 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ - -module yetilab.matrix.matrixtype; - -load yetilab.vector.vectortype; - -typedef opaque matrix = - DenseRows. array<vector> | // array of rows - DenseCols. array<vector> | // array of columns - SparseCSR. { - .values is vector, - .indices is array<number>, // column index of each value - .pointers is array<number>, // offset of first value in each row - .extent is number // max possible index + 1, i.e. number of columns - } | - SparseCSC. { - .values is vector, - .indices is array<number>, // row index of each value - .pointers is array<number>, // offset of first value in each column - .extent is number // max pointers index + 1, i.e. number of rows - }; - -(); -
--- a/yetilab/matrix/test/speedtest.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/matrix/test/speedtest.yeti Thu May 23 19:33:06 2013 +0100 @@ -1,8 +1,8 @@ program yetilab.matrix.test.speedtest; -mat = load yetilab.matrix.matrix; -vec = load yetilab.vector.vector; +mat = load yetilab.matrix; +vec = load yetilab.vector; { compare, compareUsing } = load yetilab.test.test;
--- a/yetilab/matrix/test/test_matrix.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/matrix/test/test_matrix.yeti Thu May 23 19:33:06 2013 +0100 @@ -1,11 +1,11 @@ module yetilab.matrix.test.test_matrix; -mat = load yetilab.matrix.matrix; -vec = load yetilab.vector.vector; +mat = load yetilab.matrix; +vec = load yetilab.vector; -load yetilab.vector.vectortype; -load yetilab.matrix.matrixtype; +load yetilab.vector.type; +load yetilab.matrix.type; import yeti.lang: FailureException;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/matrix/type.yeti Thu May 23 19:33:06 2013 +0100 @@ -0,0 +1,23 @@ + +module yetilab.matrix.type; + +load yetilab.vector.type; + +typedef opaque matrix = + DenseRows. array<vector> | // array of rows + DenseCols. array<vector> | // array of columns + SparseCSR. { + .values is vector, + .indices is array<number>, // column index of each value + .pointers is array<number>, // offset of first value in each row + .extent is number // max possible index + 1, i.e. number of columns + } | + SparseCSC. { + .values is vector, + .indices is array<number>, // row index of each value + .pointers is array<number>, // offset of first value in each column + .extent is number // max pointers index + 1, i.e. number of rows + }; + +(); +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/plot.yeti Thu May 23 19:33:06 2013 +0100 @@ -0,0 +1,127 @@ +module yetilab.plot; + +vec = load yetilab.vector; + +import org.jzy3d.plot3d.builder: Mapper; +import org.jzy3d.maths: Range, Coord3d; +import org.jzy3d.chart: Chart, ChartLauncher; +import org.jzy3d.plot3d.builder: Builder; +import org.jzy3d.plot3d.builder.concrete: OrthonormalGrid; +import org.jzy3d.colors.colormaps: ColorMapRainbow; +import org.jzy3d.colors: ColorMapper, Color; +import org.jzy3d.plot3d.rendering.canvas: Quality; +import org.jzy3d.plot3d.rendering.view.modes: ViewPositionMode; +import org.jzy3d.plot3d.primitives: FlatLine2d, Point; + +newMatrixMapper matrix = + (class MMapper extends Mapper + double f(double x, double y) + result = matrix.getAt y x; + println "f(\(x),\(y)) -> \(result)"; + result + end; + new MMapper()); + +newMatrixLogMapper matrix = + (class MMapper extends Mapper + double f(double x, double y) + ln (matrix.getAt y x) + end; + new MMapper()); + +newMapper mapFunction = + (class FMapper extends Mapper + double f(double x, double y) + mapFunction x y + end; + new FMapper()); + +plotMatrix chart matrix is ~Chart -> 'a -> () = + (mapper = newMatrixMapper matrix; + size = matrix.size; + xrange = new Range(0, size.columns - 1); + yrange = new Range(0, size.rows - 1); + grid = new OrthonormalGrid(xrange, size.columns, yrange, size.rows); + println "Matrix size: \(size)"; + surface = Builder#buildOrthonormal(grid, mapper); //??? big? + println "Z Bounds: \(surface#getBounds()#getZmin()) -> \(surface#getBounds()#getZmax())"; + surface#setFaceDisplayed(true); + surface#setWireframeDisplayed(true); + surface#setWireframeColor(Color#BLACK); + chart#getScene()#getGraph()#add(surface); + ()); + +plotCurve chart depth curve is ~Chart -> number -> 'a -> () = + (scene = chart#getScene(); + xx = map (.time) curve; + yy = map (.value) curve; + line = new FlatLine2d(xx as ~float[], yy as ~float[], depth); + line#setWireframeDisplayed(true); + line#setWireframeColor(Color#BLACK); + line#setWireframeWidth(2); + line#setFaceDisplayed(false); + scene#add(line); + chart#getView()#setViewPoint(new Coord3d(0, 0, 0)); +/* + axes = chart#getAxeLayout(); + axes#setXAxeLabelDisplayed(false); + axes#setYAxeLabelDisplayed(false); + axes#setZAxeLabelDisplayed(true); + axes#setZAxeLabel("unit goes here"); //!!! + axes#setYTickLabelDisplayed(false); +*/ + ()); + +plotSeries chart depth { start, step, values } is ~Chart -> number -> 'a -> () = + (scene = chart#getScene(); + xx = map do i: start + step * i done [0..length values - 1]; + yy = list values; + line = new FlatLine2d(xx as ~float[], yy as ~float[], depth); + line#setWireframeDisplayed(true); + line#setWireframeColor(Color#BLACK); + line#setWireframeWidth(2); + line#setFaceDisplayed(false); + scene#add(line); + chart#getView()#setViewPoint(new Coord3d(0, 0, 0)); +/* + axes = chart#getAxeLayout(); + axes#setXAxeLabelDisplayed(false); + axes#setYAxeLabelDisplayed(false); + axes#setZAxeLabelDisplayed(true); + axes#setZAxeLabel("unit goes here"); //!!! + axes#setYTickLabelDisplayed(false); +*/ + ()); + +plot structures = + (chart = new Chart(Quality#Nicest); + var depth = 0; + for structures do s: + case s of + Grid matrix: + plotMatrix chart matrix; + Curve curve: + plotCurve chart depth curve; + Series series: + plotSeries chart depth series; + Vector vector: + plotSeries chart depth + { start = 0, step = 1, values = vec.list vector }; + other: + failWith "Unable to plot \(other)"; + esac; + depth := depth + 1; + done; + ChartLauncher#openChart(chart); + chart); + +{ + newMatrixMapper, + newMatrixLogMapper, + newMapper, + plotMatrix, + plotCurve, + plotSeries, + plot, +} +
--- a/yetilab/plot/plot.yeti Thu May 23 17:15:27 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -module yetilab.plot.plot; - -vec = load yetilab.vector.vector; - -import org.jzy3d.plot3d.builder: Mapper; -import org.jzy3d.maths: Range, Coord3d; -import org.jzy3d.chart: Chart, ChartLauncher; -import org.jzy3d.plot3d.builder: Builder; -import org.jzy3d.plot3d.builder.concrete: OrthonormalGrid; -import org.jzy3d.colors.colormaps: ColorMapRainbow; -import org.jzy3d.colors: ColorMapper, Color; -import org.jzy3d.plot3d.rendering.canvas: Quality; -import org.jzy3d.plot3d.rendering.view.modes: ViewPositionMode; -import org.jzy3d.plot3d.primitives: FlatLine2d, Point; - -newMatrixMapper matrix = - (class MMapper extends Mapper - double f(double x, double y) - result = matrix.getAt y x; - println "f(\(x),\(y)) -> \(result)"; - result - end; - new MMapper()); - -newMatrixLogMapper matrix = - (class MMapper extends Mapper - double f(double x, double y) - ln (matrix.getAt y x) - end; - new MMapper()); - -newMapper mapFunction = - (class FMapper extends Mapper - double f(double x, double y) - mapFunction x y - end; - new FMapper()); - -plotMatrix chart matrix is ~Chart -> 'a -> () = - (mapper = newMatrixMapper matrix; - size = matrix.size; - xrange = new Range(0, size.columns - 1); - yrange = new Range(0, size.rows - 1); - grid = new OrthonormalGrid(xrange, size.columns, yrange, size.rows); - println "Matrix size: \(size)"; - surface = Builder#buildOrthonormal(grid, mapper); //??? big? - println "Z Bounds: \(surface#getBounds()#getZmin()) -> \(surface#getBounds()#getZmax())"; - surface#setFaceDisplayed(true); - surface#setWireframeDisplayed(true); - surface#setWireframeColor(Color#BLACK); - chart#getScene()#getGraph()#add(surface); - ()); - -plotCurve chart depth curve is ~Chart -> number -> 'a -> () = - (scene = chart#getScene(); - xx = map (.time) curve; - yy = map (.value) curve; - line = new FlatLine2d(xx as ~float[], yy as ~float[], depth); - line#setWireframeDisplayed(true); - line#setWireframeColor(Color#BLACK); - line#setWireframeWidth(2); - line#setFaceDisplayed(false); - scene#add(line); - chart#getView()#setViewPoint(new Coord3d(0, 0, 0)); -/* - axes = chart#getAxeLayout(); - axes#setXAxeLabelDisplayed(false); - axes#setYAxeLabelDisplayed(false); - axes#setZAxeLabelDisplayed(true); - axes#setZAxeLabel("unit goes here"); //!!! - axes#setYTickLabelDisplayed(false); -*/ - ()); - -plotSeries chart depth { start, step, values } is ~Chart -> number -> 'a -> () = - (scene = chart#getScene(); - xx = map do i: start + step * i done [0..length values - 1]; - yy = list values; - line = new FlatLine2d(xx as ~float[], yy as ~float[], depth); - line#setWireframeDisplayed(true); - line#setWireframeColor(Color#BLACK); - line#setWireframeWidth(2); - line#setFaceDisplayed(false); - scene#add(line); - chart#getView()#setViewPoint(new Coord3d(0, 0, 0)); -/* - axes = chart#getAxeLayout(); - axes#setXAxeLabelDisplayed(false); - axes#setYAxeLabelDisplayed(false); - axes#setZAxeLabelDisplayed(true); - axes#setZAxeLabel("unit goes here"); //!!! - axes#setYTickLabelDisplayed(false); -*/ - ()); - -plot structures = - (chart = new Chart(Quality#Nicest); - var depth = 0; - for structures do s: - case s of - Grid matrix: - plotMatrix chart matrix; - Curve curve: - plotCurve chart depth curve; - Series series: - plotSeries chart depth series; - Vector vector: - plotSeries chart depth - { start = 0, step = 1, values = vec.list vector }; - other: - failWith "Unable to plot \(other)"; - esac; - depth := depth + 1; - done; - ChartLauncher#openChart(chart); - chart); - -{ - newMatrixMapper, - newMatrixLogMapper, - newMapper, - plotMatrix, - plotCurve, - plotSeries, - plot, -} -
--- a/yetilab/signal/test/test_window.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/signal/test/test_window.yeti Thu May 23 19:33:06 2013 +0100 @@ -2,7 +2,7 @@ module yetilab.signal.test.test_window; win = load yetilab.signal.window; -vec = load yetilab.vector.vector; +vec = load yetilab.vector; { compare, compareUsing } = load yetilab.test.test;
--- a/yetilab/signal/window.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/signal/window.yeti Thu May 23 19:33:06 2013 +0100 @@ -1,7 +1,7 @@ module yetilab.signal.window; -vec = load yetilab.vector.vector; +vec = load yetilab.vector; bf = load yetilab.vector.blockfuncs; cosineWindowSymmetric a0 a1 a2 a3 n =
--- a/yetilab/stream/audiofile.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/stream/audiofile.yeti Thu May 23 19:33:06 2013 +0100 @@ -1,7 +1,7 @@ module yetilab.stream.audiofile; -load yetilab.stream.streamtype; +load yetilab.stream.type; import javax.sound.sampled: AudioSystem, AudioInputStream, AudioFormat, AudioFormat$Encoding, @@ -12,7 +12,7 @@ import java.nio: ByteBuffer, ByteOrder; ch = load yetilab.stream.channels; -vec = load yetilab.vector.vector; +vec = load yetilab.vector; decode8u bytes doubles n is ~byte[] -> ~double[] -> number -> () = (for [0..n-1] do i:
--- a/yetilab/stream/channels.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/stream/channels.yeti Thu May 23 19:33:06 2013 +0100 @@ -1,10 +1,10 @@ module yetilab.stream.channels; -vec = load yetilab.vector.vector; -mat = load yetilab.matrix.matrix; +vec = load yetilab.vector; +mat = load yetilab.matrix; -load yetilab.vector.vectortype; +load yetilab.vector.type; //!!! "internal" vector function to retrieve data for read-only // purposes without copying
--- a/yetilab/stream/filter.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/stream/filter.yeti Thu May 23 19:33:06 2013 +0100 @@ -1,10 +1,10 @@ module yetilab.stream.filter; -mat = load yetilab.matrix.matrix; +mat = load yetilab.matrix; ch = load yetilab.stream.channels; -load yetilab.stream.streamtype; +load yetilab.stream.type; minDurationOf d1 d2 = case d1 of
--- a/yetilab/stream/framer.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/stream/framer.yeti Thu May 23 19:33:06 2013 +0100 @@ -6,12 +6,12 @@ * overlapping) frames of data. */ -vec = load yetilab.vector.vector; +vec = load yetilab.vector; bf = load yetilab.vector.blockfuncs; af = load yetilab.stream.audiofile; win = load yetilab.signal.window; fft = load yetilab.transform.fft; -mat = load yetilab.matrix.matrix; +mat = load yetilab.matrix; ch = load yetilab.stream.channels; blockList framesize stream =
--- a/yetilab/stream/playback.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/stream/playback.yeti Thu May 23 19:33:06 2013 +0100 @@ -1,7 +1,7 @@ module yetilab.stream.playback; -vec = load yetilab.vector.vector; +vec = load yetilab.vector; af = load yetilab.stream.audiofile; ch = load yetilab.stream.channels;
--- a/yetilab/stream/streamtype.yeti Thu May 23 17:15:27 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ - -module yetilab.stream.streamtype; - -load yetilab.matrix.matrixtype; - -typedef stream = - { - position is number, - channels is number, - sampleRate is number, - available is Known number | Unknown () | Infinite (), - finished? is boolean, - read is number -> matrix, - close is () -> (), - }; - -(); -
--- a/yetilab/stream/syntheticstream.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/stream/syntheticstream.yeti Thu May 23 19:33:06 2013 +0100 @@ -2,10 +2,10 @@ module yetilab.stream.syntheticstream; ch = load yetilab.stream.channels; -vec = load yetilab.vector.vector; +vec = load yetilab.vector; -load yetilab.vector.vectortype; -load yetilab.stream.streamtype; +load yetilab.vector.type; +load yetilab.stream.type; generated sampleRate generator = (// generator takes sample number as arg, returns number in -1,+1 range
--- a/yetilab/stream/test/test_audiofile.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/stream/test/test_audiofile.yeti Thu May 23 19:33:06 2013 +0100 @@ -2,8 +2,8 @@ module yetilab.stream.test.test_audiofile; af = load yetilab.stream.audiofile; -vec = load yetilab.vector.vector; -mat = load yetilab.matrix.matrix; +vec = load yetilab.vector; +mat = load yetilab.matrix; bf = load yetilab.vector.blockfuncs; ref = load yetilab.stream.test.audiofile_reference;
--- a/yetilab/stream/test/test_channels.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/stream/test/test_channels.yeti Thu May 23 19:33:06 2013 +0100 @@ -2,8 +2,8 @@ module yetilab.stream.test.test_channels; ch = load yetilab.stream.channels; -mat = load yetilab.matrix.matrix; -vec = load yetilab.vector.vector; +mat = load yetilab.matrix; +vec = load yetilab.vector; { compare, compareUsing } = load yetilab.test.test;
--- a/yetilab/stream/test/test_filter.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/stream/test/test_filter.yeti Thu May 23 19:33:06 2013 +0100 @@ -1,8 +1,8 @@ module yetilab.stream.test.test_filter; -vec = load yetilab.vector.vector; -mat = load yetilab.matrix.matrix; +vec = load yetilab.vector; +mat = load yetilab.matrix; syn = load yetilab.stream.syntheticstream; filt = load yetilab.stream.filter;
--- a/yetilab/stream/test/test_framer.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/stream/test/test_framer.yeti Thu May 23 19:33:06 2013 +0100 @@ -2,8 +2,8 @@ module yetilab.stream.test.test_framer; fr = load yetilab.stream.framer; -vec = load yetilab.vector.vector; -mat = load yetilab.matrix.matrix; +vec = load yetilab.vector; +mat = load yetilab.matrix; syn = load yetilab.stream.syntheticstream; { compare, compareUsing } = load yetilab.test.test;
--- a/yetilab/stream/test/test_syntheticstream.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/stream/test/test_syntheticstream.yeti Thu May 23 19:33:06 2013 +0100 @@ -1,8 +1,8 @@ module yetilab.stream.test.test_syntheticstream; -vec = load yetilab.vector.vector; -mat = load yetilab.matrix.matrix; +vec = load yetilab.vector; +mat = load yetilab.matrix; syn = load yetilab.stream.syntheticstream; { compare, compareUsing } = load yetilab.test.test;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/stream/type.yeti Thu May 23 19:33:06 2013 +0100 @@ -0,0 +1,18 @@ + +module yetilab.stream.type; + +load yetilab.matrix.type; + +typedef stream = + { + position is number, + channels is number, + sampleRate is number, + available is Known number | Unknown () | Infinite (), + finished? is boolean, + read is number -> matrix, + close is () -> (), + }; + +(); +
--- a/yetilab/transform/fft.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/transform/fft.yeti Thu May 23 19:33:06 2013 +0100 @@ -3,10 +3,10 @@ import edu.emory.mathcs.jtransforms.fft: DoubleFFT_1D; -vec = load yetilab.vector.vector; -complex = load yetilab.vector.complex; +vec = load yetilab.vector; +complex = load yetilab.complex; -load yetilab.vector.complextype; +load yetilab.complex.type; packedToComplex len p is number -> ~double[] -> array<cplx> = (n = len / 2;
--- a/yetilab/transform/test/test_fft.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/transform/test/test_fft.yeti Thu May 23 19:33:06 2013 +0100 @@ -2,8 +2,8 @@ module yetilab.transform.test.test_fft; { realForward, realInverse } = load yetilab.transform.fft; -{ list, fromList } = load yetilab.vector.vector; -{ complex } = load yetilab.vector.complex; +{ list, fromList } = load yetilab.vector; +{ complex } = load yetilab.complex; { compare } = load yetilab.test.test;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/vamp.yeti Thu May 23 19:33:06 2013 +0100 @@ -0,0 +1,336 @@ +module yetilab.vamp; + +import org.vamp_plugins: + Plugin, Plugin$InputDomain, + PluginLoader, PluginLoader$AdapterFlags, PluginLoader$LoadFailedException, + ParameterDescriptor, OutputDescriptor, OutputDescriptor$SampleType, + RealTime, Feature; + +import java.lang: UnsatisfiedLinkError; + +import java.util: Map, List; + +vec = load yetilab.vector; +fr = load yetilab.stream.framer; +af = load yetilab.stream.audiofile; +mat = load yetilab.matrix; +vamprdf = load yetilab.vamp.vamprdf; +vamppost = load yetilab.vamp.vamppost; + +store = load yertle.store; + +realTime r is ~RealTime -> number = r#sec() + (r#nsec() / 1000000000); + +feature f is ~Feature -> 'a = { + timestamp = if f#hasTimestamp then Time (realTime f#timestamp) else Untimed () fi, + duration = if f#hasDuration then Time (realTime f#duration) else Untimed () fi, + values = vec.fromFloats f#values, + label = f#label, + }; + +featureList fl is ~Object -> 'a = + if nullptr? fl then [] + else + a = fl unsafely_as ~List; + result = array []; + itr = a#iterator(); + itr#hasNext() loop (push result (feature (itr#next() unsafely_as ~Feature))); + list result + fi; + +featureSet fs is ~Map -> 'a = + (numberOf n is ~Object -> number = (n unsafely_as ~Integer)#intValue(); + s = [:]; + kk = list fs#keySet()#toArray(); + for kk do k: s[numberOf k] := featureList fs#get(k) done; + s); + +stores = [:]; + +getSingletonStoreFor loader = + synchronized stores do: + if loader in stores then + stores[loader] + else + s = store.newRdfStore (); + loader s; + stores[loader] := s; + s; + fi + done; + +getSystemStore () = + getSingletonStoreFor vamprdf.loadSystemVampRdf; + +getGlobalStore () = + getSingletonStoreFor vamprdf.loadGlobalVampRdf; + +getPluginPath () = + (try + map string PluginLoader#getInstance()#getPluginPath(); + catch UnsatisfiedLinkError e: + eprintln "Warning: Unable to obtain plugin path:\n\(e)"; + []; + yrt); + +listPlugins () = + (try + map string PluginLoader#getInstance()#listPlugins(); + catch UnsatisfiedLinkError e: + eprintln "Warning: Unable to obtain plugin list:\n\(e)"; + []; + yrt); + +getKnownPluginKeys () = + (store = getGlobalStore (); + nodes = vamprdf.allPluginNodes store; + // ordering is random out of the store; might as well sort + sort (map do n: (vamprdf.pluginDataByNode store n).pluginKey done nodes)); + +getDataForKnownPlugin key = + vamprdf.pluginDataByKey (getGlobalStore ()) key; + +categoryOf key = + list PluginLoader#getInstance()#getPluginCategory(key); + +inputDomain d is ~Plugin$InputDomain -> 'a = + if d == Plugin$InputDomain#FREQUENCY_DOMAIN then + FrequencyDomain () + else + TimeDomain () + fi; + +parameterDescriptor pd is ~ParameterDescriptor -> 'a = { + identifier = pd#identifier, + name = pd#name, + description = pd#description, + unit = pd#unit, + minValue = pd#minValue, + maxValue = pd#maxValue, + defaultValue = pd#defaultValue, + get quantize () = if pd#isQuantized then QuantizeStep pd#quantizeStep else Unquantized () fi, + valueNames = map string pd#valueNames + }; + +sampleType t rate is ~OutputDescriptor$SampleType -> number -> 'a = + if t == OutputDescriptor$SampleType#OneSamplePerStep then + OneSamplePerStep () + elif t == OutputDescriptor$SampleType#FixedSampleRate then + FixedSampleRate rate + else + VariableSampleRate rate + fi; + +structureOf rdfOutputData od is 'a -> ~OutputDescriptor -> 'b = + (computes = case rdfOutputData of Some d: d.computes; None (): Unknown () esac; + s = getSystemStore (); + noteIRI = case s.expand "af:Note" of IRI iri: iri; _: "" esac; + if od#hasFixedBinCount and od#binCount == 0 then + Instants (); + elif od#hasDuration then + if computes != Unknown () then + if computes == Event noteIRI then Notes (); + else Regions (); + fi + elif od#hasFixedBinCount then + if od#binCount > 1 then Notes (); + elif od#unit == "Hz" or strIndexOf (strLower od#unit) "midi" 0 >= 0 then Notes (); + else Regions (); + fi + else + Unknown (); + fi + elif od#hasFixedBinCount and od#binCount == 1 then + case computes of + Event e: + if strEnds? e "Segment" + then Segmentation () + else Curve () + fi; + _: + if od#sampleType == OutputDescriptor$SampleType#OneSamplePerStep + then Series () + else Curve () + fi; + esac; + elif od#hasFixedBinCount and + od#sampleType != OutputDescriptor$SampleType#VariableSampleRate then + Grid (); + else + Unknown (); + fi); + +outputDescriptor rdfOutputData od is 'a -> ~OutputDescriptor -> 'b = { + identifier = od#identifier, + name = od#name, + description = od#description, + get binCount () = if od#hasFixedBinCount then Fixed od#binCount else Variable () fi, + get valueExtents () = if od#hasKnownExtents then Known { min = od#minValue, max = od#maxValue } else Unknown () fi, + get valueQuantize () = if od#isQuantized then QuantizeStep od#quantizeStep else Unquantized () fi, + valueUnit = od#unit, + binNames = array (map string od#binNames), + sampleType = sampleType od#sampleType od#sampleRate, + hasDuration = od#hasDuration, + get computes () = case rdfOutputData of Some data: data.computes; None (): Unknown () esac, + get inferredStructure () = structureOf rdfOutputData od, + }; + +plugin key p is string -> ~Plugin -> 'a = + (rdfData = vamprdf.pluginDataByKey (getSystemStore ()) key; + { + plugin = p, + key, + get apiVersion () = p#getVampApiVersion(), + get identifier () = p#getIdentifier(), + get name () = p#getName(), + get description () = p#getDescription(), + get maker () = p#getMaker(), + get copyright () = p#getCopyright(), + get version () = p#getPluginVersion(), + get category () = PluginLoader#getInstance()#getPluginCategory(key), + get hasRdfDescription () = (rdfData != None ()), + get infoURL () = case rdfData of Some data: data.infoURL; None (): "" esac, + get parameters () = array (map parameterDescriptor p#getParameterDescriptors()), + parameterValue identifier = p#getParameter(identifier), + setParameterValue identifier value = p#setParameter(identifier, value), + get programs () = array (map string p#getPrograms()), + get currentProgram () = p#getCurrentProgram(), + selectProgram pr = p#selectProgram(pr), + get inputDomain () = inputDomain p#getInputDomain(), + get preferredBlockSize () = p#getPreferredBlockSize(), + get preferredStepSize () = p#getPreferredStepSize(), + get minChannelCount () = p#getMinChannelCount(), + get maxChannelCount () = p#getMaxChannelCount(), + initialise { channels, hop, blockSize } = p#initialise(channels, hop, blockSize), + reset () = p#reset(), + get outputs () = + array case rdfData of + Some data: map2 outputDescriptor (map Some data.outputs) p#getOutputDescriptors(); + None (): map (outputDescriptor (None ())) p#getOutputDescriptors(); + esac, + process frame time is 'a -> ~RealTime -> 'b = + featureSet p#process((map vec.floats (mat.asRows frame)) as ~float[][], 0, time), + getRemainingFeatures () = featureSet p#getRemainingFeatures(), + dispose () = p#dispose(), + }); + +featuresFromSet outputNo f = if outputNo in f then f[outputNo] else [] fi; + +outputNumberByName p name = + (outputs = p.outputs; + case find ((== name) . (.identifier)) outputs of + first::rest: index first outputs; + _: -1; + esac); + +loadPlugin rate key = + try + OK (plugin key + PluginLoader#getInstance()#loadPlugin(key, rate, + PluginLoader$AdapterFlags#ADAPT_INPUT_DOMAIN + + PluginLoader$AdapterFlags#ADAPT_CHANNEL_COUNT)) + catch PluginLoader$LoadFailedException _: + Error "Failed to load Vamp plugin with key \(key)" + yrt; + +//!!! bring vector typedef into scope -- this shouldn't be necessary, +//but see comment in processed below +load yetilab.vector.type; + +processed { p, sampleRate, hop } frames count + // I don't know why this type declaration is necessary. Without + // it, yeti records the return type as 'a and can't do anything + // useful with it (giving IncompatibleClassChangeError when + // e.g. accessing the values array) + is 'a -> 'b -> 'c -> + list<hash<number, + list<{ timestamp is Time number | Untimed (), + duration is Time number | Untimed (), + label is string, + values is vector + }>>> = + case frames of + frame::rest: + p.process frame RealTime#frame2RealTime(count, sampleRate) + :. + \(processed { p, sampleRate, hop } rest (count + hop)); + _: + (rf = p.getRemainingFeatures (); + p.dispose (); + [rf]); + esac; + +converted { p, sampleRate, hop } outputNo fl = + map (featuresFromSet outputNo) fl; + +returnErrorFrom p stream text = (p.dispose (); stream.close (); failWith text); + +processWith key p outputNo stream = + (blockSize = + if p.preferredBlockSize == 0 then 2048 + else p.preferredBlockSize fi; + stepSize = + if p.preferredStepSize == 0 then + if p.inputDomain == FrequencyDomain () then blockSize / 2 + else blockSize fi; + else p.preferredStepSize fi; + channels = 1; + params = { + p, sampleRate = stream.sampleRate, channels = 1, + framesize = blockSize, blockSize, hop = stepSize + }; + if p.initialise params then + { + key = key, + output = p.outputs[outputNo], + parameters = mapIntoHash id p.parameterValue + (map (.identifier) p.parameters), + config = { + channels, blockSize, stepSize, + sampleRate = stream.sampleRate + }, + features = converted params outputNo + (processed params (fr.frames params stream) 0) + }; + // If processing completed successfully, then p is + // disposed by processed and stream is closed by the + // framer + else + returnErrorFrom p stream "Failed to initialise plugin \(key) with channels = \(channels), blockSize = \(blockSize), stepSize = \(stepSize)"; + fi); + +processStream key output stream = + case loadPlugin stream.sampleRate key of + OK p: + outputNo = outputNumberByName p output; + if outputNo >= 0 then + processWith key p outputNo stream + else + outputs = strJoin ", " (map (.identifier) p.outputs); + returnErrorFrom p stream "Plugin \(key) has no output named \(output) (outputs are: \(outputs))" + fi; + Error e: failWith e; + esac; + +processFile key output filename = + processStream key output (af.open filename); + +processStreamStructured key output filename = + vamppost.postprocess (processStream key output filename); + +processFileStructured key output filename = + vamppost.postprocess (processFile key output filename); + +{ +get pluginPath = getPluginPath, +get pluginKeys = listPlugins, +loadPlugin, +categoryOf, +processStream, +processFile, +processStreamStructured, +processFileStructured, +getKnownPluginKeys, +getDataForKnownPlugin, +} +
--- a/yetilab/vamp/test/test_vamp.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/vamp/test/test_vamp.yeti Thu May 23 19:33:06 2013 +0100 @@ -1,10 +1,10 @@ module yetilab.vamp.test.test_vamp; -v = load yetilab.vamp.vamp; +v = load yetilab.vamp; synthetic = load yetilab.stream.syntheticstream; filter = load yetilab.stream.filter; -mat = load yetilab.matrix.matrix; -vec = load yetilab.vector.vector; +mat = load yetilab.matrix; +vec = load yetilab.vector; { compare, compareUsing } = load yetilab.test.test;
--- a/yetilab/vamp/vamp.yeti Thu May 23 17:15:27 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,336 +0,0 @@ -module yetilab.vamp.vamp; - -import org.vamp_plugins: - Plugin, Plugin$InputDomain, - PluginLoader, PluginLoader$AdapterFlags, PluginLoader$LoadFailedException, - ParameterDescriptor, OutputDescriptor, OutputDescriptor$SampleType, - RealTime, Feature; - -import java.lang: UnsatisfiedLinkError; - -import java.util: Map, List; - -vec = load yetilab.vector.vector; -fr = load yetilab.stream.framer; -af = load yetilab.stream.audiofile; -mat = load yetilab.matrix.matrix; -vamprdf = load yetilab.vamp.vamprdf; -vamppost = load yetilab.vamp.vamppost; - -store = load yertle.store; - -realTime r is ~RealTime -> number = r#sec() + (r#nsec() / 1000000000); - -feature f is ~Feature -> 'a = { - timestamp = if f#hasTimestamp then Time (realTime f#timestamp) else Untimed () fi, - duration = if f#hasDuration then Time (realTime f#duration) else Untimed () fi, - values = vec.fromFloats f#values, - label = f#label, - }; - -featureList fl is ~Object -> 'a = - if nullptr? fl then [] - else - a = fl unsafely_as ~List; - result = array []; - itr = a#iterator(); - itr#hasNext() loop (push result (feature (itr#next() unsafely_as ~Feature))); - list result - fi; - -featureSet fs is ~Map -> 'a = - (numberOf n is ~Object -> number = (n unsafely_as ~Integer)#intValue(); - s = [:]; - kk = list fs#keySet()#toArray(); - for kk do k: s[numberOf k] := featureList fs#get(k) done; - s); - -stores = [:]; - -getSingletonStoreFor loader = - synchronized stores do: - if loader in stores then - stores[loader] - else - s = store.newRdfStore (); - loader s; - stores[loader] := s; - s; - fi - done; - -getSystemStore () = - getSingletonStoreFor vamprdf.loadSystemVampRdf; - -getGlobalStore () = - getSingletonStoreFor vamprdf.loadGlobalVampRdf; - -getPluginPath () = - (try - map string PluginLoader#getInstance()#getPluginPath(); - catch UnsatisfiedLinkError e: - eprintln "Warning: Unable to obtain plugin path:\n\(e)"; - []; - yrt); - -listPlugins () = - (try - map string PluginLoader#getInstance()#listPlugins(); - catch UnsatisfiedLinkError e: - eprintln "Warning: Unable to obtain plugin list:\n\(e)"; - []; - yrt); - -getKnownPluginKeys () = - (store = getGlobalStore (); - nodes = vamprdf.allPluginNodes store; - // ordering is random out of the store; might as well sort - sort (map do n: (vamprdf.pluginDataByNode store n).pluginKey done nodes)); - -getDataForKnownPlugin key = - vamprdf.pluginDataByKey (getGlobalStore ()) key; - -categoryOf key = - list PluginLoader#getInstance()#getPluginCategory(key); - -inputDomain d is ~Plugin$InputDomain -> 'a = - if d == Plugin$InputDomain#FREQUENCY_DOMAIN then - FrequencyDomain () - else - TimeDomain () - fi; - -parameterDescriptor pd is ~ParameterDescriptor -> 'a = { - identifier = pd#identifier, - name = pd#name, - description = pd#description, - unit = pd#unit, - minValue = pd#minValue, - maxValue = pd#maxValue, - defaultValue = pd#defaultValue, - get quantize () = if pd#isQuantized then QuantizeStep pd#quantizeStep else Unquantized () fi, - valueNames = map string pd#valueNames - }; - -sampleType t rate is ~OutputDescriptor$SampleType -> number -> 'a = - if t == OutputDescriptor$SampleType#OneSamplePerStep then - OneSamplePerStep () - elif t == OutputDescriptor$SampleType#FixedSampleRate then - FixedSampleRate rate - else - VariableSampleRate rate - fi; - -structureOf rdfOutputData od is 'a -> ~OutputDescriptor -> 'b = - (computes = case rdfOutputData of Some d: d.computes; None (): Unknown () esac; - s = getSystemStore (); - noteIRI = case s.expand "af:Note" of IRI iri: iri; _: "" esac; - if od#hasFixedBinCount and od#binCount == 0 then - Instants (); - elif od#hasDuration then - if computes != Unknown () then - if computes == Event noteIRI then Notes (); - else Regions (); - fi - elif od#hasFixedBinCount then - if od#binCount > 1 then Notes (); - elif od#unit == "Hz" or strIndexOf (strLower od#unit) "midi" 0 >= 0 then Notes (); - else Regions (); - fi - else - Unknown (); - fi - elif od#hasFixedBinCount and od#binCount == 1 then - case computes of - Event e: - if strEnds? e "Segment" - then Segmentation () - else Curve () - fi; - _: - if od#sampleType == OutputDescriptor$SampleType#OneSamplePerStep - then Series () - else Curve () - fi; - esac; - elif od#hasFixedBinCount and - od#sampleType != OutputDescriptor$SampleType#VariableSampleRate then - Grid (); - else - Unknown (); - fi); - -outputDescriptor rdfOutputData od is 'a -> ~OutputDescriptor -> 'b = { - identifier = od#identifier, - name = od#name, - description = od#description, - get binCount () = if od#hasFixedBinCount then Fixed od#binCount else Variable () fi, - get valueExtents () = if od#hasKnownExtents then Known { min = od#minValue, max = od#maxValue } else Unknown () fi, - get valueQuantize () = if od#isQuantized then QuantizeStep od#quantizeStep else Unquantized () fi, - valueUnit = od#unit, - binNames = array (map string od#binNames), - sampleType = sampleType od#sampleType od#sampleRate, - hasDuration = od#hasDuration, - get computes () = case rdfOutputData of Some data: data.computes; None (): Unknown () esac, - get inferredStructure () = structureOf rdfOutputData od, - }; - -plugin key p is string -> ~Plugin -> 'a = - (rdfData = vamprdf.pluginDataByKey (getSystemStore ()) key; - { - plugin = p, - key, - get apiVersion () = p#getVampApiVersion(), - get identifier () = p#getIdentifier(), - get name () = p#getName(), - get description () = p#getDescription(), - get maker () = p#getMaker(), - get copyright () = p#getCopyright(), - get version () = p#getPluginVersion(), - get category () = PluginLoader#getInstance()#getPluginCategory(key), - get hasRdfDescription () = (rdfData != None ()), - get infoURL () = case rdfData of Some data: data.infoURL; None (): "" esac, - get parameters () = array (map parameterDescriptor p#getParameterDescriptors()), - parameterValue identifier = p#getParameter(identifier), - setParameterValue identifier value = p#setParameter(identifier, value), - get programs () = array (map string p#getPrograms()), - get currentProgram () = p#getCurrentProgram(), - selectProgram pr = p#selectProgram(pr), - get inputDomain () = inputDomain p#getInputDomain(), - get preferredBlockSize () = p#getPreferredBlockSize(), - get preferredStepSize () = p#getPreferredStepSize(), - get minChannelCount () = p#getMinChannelCount(), - get maxChannelCount () = p#getMaxChannelCount(), - initialise { channels, hop, blockSize } = p#initialise(channels, hop, blockSize), - reset () = p#reset(), - get outputs () = - array case rdfData of - Some data: map2 outputDescriptor (map Some data.outputs) p#getOutputDescriptors(); - None (): map (outputDescriptor (None ())) p#getOutputDescriptors(); - esac, - process frame time is 'a -> ~RealTime -> 'b = - featureSet p#process((map vec.floats (mat.asRows frame)) as ~float[][], 0, time), - getRemainingFeatures () = featureSet p#getRemainingFeatures(), - dispose () = p#dispose(), - }); - -featuresFromSet outputNo f = if outputNo in f then f[outputNo] else [] fi; - -outputNumberByName p name = - (outputs = p.outputs; - case find ((== name) . (.identifier)) outputs of - first::rest: index first outputs; - _: -1; - esac); - -loadPlugin rate key = - try - OK (plugin key - PluginLoader#getInstance()#loadPlugin(key, rate, - PluginLoader$AdapterFlags#ADAPT_INPUT_DOMAIN + - PluginLoader$AdapterFlags#ADAPT_CHANNEL_COUNT)) - catch PluginLoader$LoadFailedException _: - Error "Failed to load Vamp plugin with key \(key)" - yrt; - -//!!! bring vector typedef into scope -- this shouldn't be necessary, -//but see comment in processed below -load yetilab.vector.vectortype; - -processed { p, sampleRate, hop } frames count - // I don't know why this type declaration is necessary. Without - // it, yeti records the return type as 'a and can't do anything - // useful with it (giving IncompatibleClassChangeError when - // e.g. accessing the values array) - is 'a -> 'b -> 'c -> - list<hash<number, - list<{ timestamp is Time number | Untimed (), - duration is Time number | Untimed (), - label is string, - values is vector - }>>> = - case frames of - frame::rest: - p.process frame RealTime#frame2RealTime(count, sampleRate) - :. - \(processed { p, sampleRate, hop } rest (count + hop)); - _: - (rf = p.getRemainingFeatures (); - p.dispose (); - [rf]); - esac; - -converted { p, sampleRate, hop } outputNo fl = - map (featuresFromSet outputNo) fl; - -returnErrorFrom p stream text = (p.dispose (); stream.close (); failWith text); - -processWith key p outputNo stream = - (blockSize = - if p.preferredBlockSize == 0 then 2048 - else p.preferredBlockSize fi; - stepSize = - if p.preferredStepSize == 0 then - if p.inputDomain == FrequencyDomain () then blockSize / 2 - else blockSize fi; - else p.preferredStepSize fi; - channels = 1; - params = { - p, sampleRate = stream.sampleRate, channels = 1, - framesize = blockSize, blockSize, hop = stepSize - }; - if p.initialise params then - { - key = key, - output = p.outputs[outputNo], - parameters = mapIntoHash id p.parameterValue - (map (.identifier) p.parameters), - config = { - channels, blockSize, stepSize, - sampleRate = stream.sampleRate - }, - features = converted params outputNo - (processed params (fr.frames params stream) 0) - }; - // If processing completed successfully, then p is - // disposed by processed and stream is closed by the - // framer - else - returnErrorFrom p stream "Failed to initialise plugin \(key) with channels = \(channels), blockSize = \(blockSize), stepSize = \(stepSize)"; - fi); - -processStream key output stream = - case loadPlugin stream.sampleRate key of - OK p: - outputNo = outputNumberByName p output; - if outputNo >= 0 then - processWith key p outputNo stream - else - outputs = strJoin ", " (map (.identifier) p.outputs); - returnErrorFrom p stream "Plugin \(key) has no output named \(output) (outputs are: \(outputs))" - fi; - Error e: failWith e; - esac; - -processFile key output filename = - processStream key output (af.open filename); - -processStreamStructured key output filename = - vamppost.postprocess (processStream key output filename); - -processFileStructured key output filename = - vamppost.postprocess (processFile key output filename); - -{ -get pluginPath = getPluginPath, -get pluginKeys = listPlugins, -loadPlugin, -categoryOf, -processStream, -processFile, -processStreamStructured, -processFileStructured, -getKnownPluginKeys, -getDataForKnownPlugin, -} -
--- a/yetilab/vamp/vamppost.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/vamp/vamppost.yeti Thu May 23 19:33:06 2013 +0100 @@ -1,7 +1,7 @@ module yetilab.vamp.vamppost; -mat = load yetilab.matrix.matrix; -vec = load yetilab.vector.vector; +mat = load yetilab.matrix; +vec = load yetilab.vector; fillOneSamplePerStep config features = (fill' n pending features =
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/vector.yeti Thu May 23 19:33:06 2013 +0100 @@ -0,0 +1,147 @@ + +module yetilab.vector; + +load yetilab.vector.type; + +import java.util: Arrays; + +//!!! This is supposed to be 100% immutable and without copying when duplicating for read only + +zeros n = + new double[n]; + +consts m n = + (a = zeros n; + for [0..n-1] do i: + a[i] := m; + done; + a); + +ones = consts 1.0; + +fromList l is list?<number> -> ~double[] = + (arr = array(l); + len = length arr; + v = zeros len; + for [0..len-1] do i: + v[i] := arr[i]; + done; + v); + +list' a is ~double[] -> list<number> = + list a; + +array' a is ~double[] -> array<number> = + array a; + +length' = + length . list'; + +empty?' = + empty? . list'; + +//!!! doc note: argument order chosen for consistency with std module function +at' v n is ~double[] -> number -> number = + v[n]; + +floats a is ~double[] -> ~float[] = + (len = length' a; + f = new float[len]; + for [0..len-1] do i: + f[i] := a[i]; + done; + f); + +fromFloats ff is ~float[] -> ~double[] = + (len = length (list ff); + a = new double[len]; + for [0..len-1] do i: + a[i] := ff[i]; + done; + a); + +equal v1 v2 = + list' v1 == list' v2; + +equalUnder comparator v1 v2 = + length' v1 == length' v2 and + all id (map2 comparator (list' v1) (list' v2)); + +copyOf v is ~double[] -> ~double[] = + Arrays#copyOf(v, list' v |> length); + +//!!! doc note: argument order chosen for consistency with std module function +slice v start end is ~double[] -> number -> number -> ~double[] = + Arrays#copyOfRange(v, start, end); + +resizedTo n v is number -> ~double[] -> ~double[] = + Arrays#copyOf(v, n); + +reversed v is ~double[] -> ~double[] = + (len = length (list v); + a = new double[len]; + for [0..len-1] do i: + a[len-i-1] := v[i]; + done; + a); + +concat vv is list?<~double[]> -> ~double[] = + (len = sum (map length' vv); + vout = zeros len; + var base = 0; + for vv do v: + vlen = length' v; + for [0..vlen-1] do i: vout[base + i] := v[i] done; + base := base + vlen; + done; + vout); + +repeated v n is ~double[] -> number -> ~double[] = + concat (map \(v) [1..n]); + +{ + zeros, + consts, + ones, + vector v = v, + primitive = copyOf, + floats, + fromFloats, + fromList, + list = list', + array = array', + length = length', + empty? = empty?', + at = at', + equal, + equalUnder, + slice, + resizedTo, + reversed, + repeated, + concat, +} as { + zeros is number -> vector, + consts is number -> number -> vector, + ones is number -> vector, + vector is ~double[] -> vector, + primitive is vector -> ~double[], + floats is vector -> ~float[], + fromFloats is ~float[] -> vector, + fromList is list?<number> -> vector, + list is vector -> list<number>, + array is vector -> array<number>, + length is vector -> number, + empty? is vector -> boolean, + at is vector -> number -> number, + equal is vector -> vector -> boolean, + equalUnder is (number -> number -> boolean) -> vector -> vector -> boolean, + slice is vector -> number -> number -> vector, + resizedTo is number -> vector -> vector, + reversed is vector -> vector, + repeated is vector -> number -> vector, + concat is list?<vector> -> vector, +} + + +
--- a/yetilab/vector/blockfuncs.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/vector/blockfuncs.yeti Thu May 23 19:33:06 2013 +0100 @@ -1,9 +1,9 @@ module yetilab.vector.blockfuncs; -vec = load yetilab.vector.vector; +vec = load yetilab.vector; -load yetilab.vector.vectortype; +load yetilab.vector.type; //!!! "internal" vector function to retrieve data for read-only // purposes without copying
--- a/yetilab/vector/complex.yeti Thu May 23 17:15:27 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ - -module yetilab.vector.complex; - -load yetilab.vector.vectortype; -load yetilab.vector.complextype; - -vec = load yetilab.vector.vector; - -import java.lang: ClassCastException; - -class Cplx(double real, double imag) - int getReal() - real, - int getImag() - imag, - double getMagnitude() - sqrt (real * real + imag * imag), - double getAngle() - Math#atan2(imag, real), - String toString() - if real == int real and imag == int imag then - if imag < 0 then - " \(int real) - \(int (-imag))i" - else - " \(int real) + \(int imag)i" - fi - else - if imag < 0 then - " \(real) - \((-imag))i" - else - " \(real) + \(imag)i" - fi - fi, - int hashCode() - Double#valueOf(real)#hashCode() + Double#valueOf(imag)#hashCode(), - boolean equals(Object other) - try - c = other unsafely_as ~Cplx; - c#getReal() == real and c#getImag() == imag - catch ClassCastException: - false - yrt, -end; - -real c1 is ~Cplx -> number = - c1#getReal(); - -imaginary c1 is ~Cplx -> number = - c1#getImag(); - -complex re im is number -> number -> ~Cplx = - new Cplx(re, im); - -magnitude c is ~Cplx -> number = - c#getMagnitude(); - -angle c is ~Cplx -> number = - c#getAngle(); - -add c1 c2 is ~Cplx -> ~Cplx -> ~Cplx = - complex (real c1 + real c2) (imaginary c1 + imaginary c2); - -scale r c is number -> ~Cplx -> ~Cplx = - complex (r * real c) (r * imaginary c); - -zeros n is number -> array<~Cplx> = - array (map \(complex 0 0) [1..n]); - -magnitudes cc is list?<~Cplx> -> vector = - vec.fromList (map magnitude cc); - -angles cc is list?<~Cplx> -> vector = - vec.fromList (map angle cc); - -{ - real, - imaginary, - complex, - magnitude, - angle, - add, - scale, - zeros, - magnitudes, - angles, -} as { - real is cplx -> number, - imaginary is cplx -> number, - complex is number -> number -> cplx, - magnitude is cplx -> number, - angle is cplx -> number, - add is cplx -> cplx -> cplx, - scale is number -> cplx -> cplx, - zeros is number -> array<cplx>, - magnitudes is list?<cplx> -> vector, - angles is list?<cplx> -> vector, -} -
--- a/yetilab/vector/complextype.yeti Thu May 23 17:15:27 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ - -module yetilab.vector.complextype; - -typedef opaque cplx = ~Cplx; - -(); -
--- a/yetilab/vector/test/test_blockfuncs.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/vector/test/test_blockfuncs.yeti Thu May 23 19:33:06 2013 +0100 @@ -3,7 +3,7 @@ stdSqrt = sqrt; -{ zeros, consts, ones, fromList, list } = load yetilab.vector.vector; +{ zeros, consts, ones, fromList, list } = load yetilab.vector; { sum, max, min, mean, add, subtract, multiply, divideBy, scaled, abs, sqr, sqrt, rms, fftshift, ifftshift } = load yetilab.vector.blockfuncs; { compare } = load yetilab.test.test;
--- a/yetilab/vector/test/test_complex.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/vector/test/test_complex.yeti Thu May 23 19:33:06 2013 +0100 @@ -1,11 +1,11 @@ module yetilab.vector.test.test_complex; { real, imaginary, complex, magnitude, angle, add, scale, zeros, magnitudes, angles } - = load yetilab.vector.complex; + = load yetilab.complex; { compare } = load yetilab.test.test; -vec = load yetilab.vector.vector; +vec = load yetilab.vector; [
--- a/yetilab/vector/test/test_vector.yeti Thu May 23 17:15:27 2013 +0100 +++ b/yetilab/vector/test/test_vector.yeti Thu May 23 19:33:06 2013 +0100 @@ -1,7 +1,7 @@ module yetilab.vector.test.test_vector; -vec = load yetilab.vector.vector; +vec = load yetilab.vector; { compare } = load yetilab.test.test;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yetilab/vector/type.yeti Thu May 23 19:33:06 2013 +0100 @@ -0,0 +1,7 @@ + +module yetilab.vector.type; + +typedef opaque vector = ~double[]; + +(); +
--- a/yetilab/vector/vector.yeti Thu May 23 17:15:27 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,147 +0,0 @@ - -module yetilab.vector.vector; - -load yetilab.vector.vectortype; - -import java.util: Arrays; - -//!!! This is supposed to be 100% immutable and without copying when duplicating for read only - -zeros n = - new double[n]; - -consts m n = - (a = zeros n; - for [0..n-1] do i: - a[i] := m; - done; - a); - -ones = consts 1.0; - -fromList l is list?<number> -> ~double[] = - (arr = array(l); - len = length arr; - v = zeros len; - for [0..len-1] do i: - v[i] := arr[i]; - done; - v); - -list' a is ~double[] -> list<number> = - list a; - -array' a is ~double[] -> array<number> = - array a; - -length' = - length . list'; - -empty?' = - empty? . list'; - -//!!! doc note: argument order chosen for consistency with std module function -at' v n is ~double[] -> number -> number = - v[n]; - -floats a is ~double[] -> ~float[] = - (len = length' a; - f = new float[len]; - for [0..len-1] do i: - f[i] := a[i]; - done; - f); - -fromFloats ff is ~float[] -> ~double[] = - (len = length (list ff); - a = new double[len]; - for [0..len-1] do i: - a[i] := ff[i]; - done; - a); - -equal v1 v2 = - list' v1 == list' v2; - -equalUnder comparator v1 v2 = - length' v1 == length' v2 and - all id (map2 comparator (list' v1) (list' v2)); - -copyOf v is ~double[] -> ~double[] = - Arrays#copyOf(v, list' v |> length); - -//!!! doc note: argument order chosen for consistency with std module function -slice v start end is ~double[] -> number -> number -> ~double[] = - Arrays#copyOfRange(v, start, end); - -resizedTo n v is number -> ~double[] -> ~double[] = - Arrays#copyOf(v, n); - -reversed v is ~double[] -> ~double[] = - (len = length (list v); - a = new double[len]; - for [0..len-1] do i: - a[len-i-1] := v[i]; - done; - a); - -concat vv is list?<~double[]> -> ~double[] = - (len = sum (map length' vv); - vout = zeros len; - var base = 0; - for vv do v: - vlen = length' v; - for [0..vlen-1] do i: vout[base + i] := v[i] done; - base := base + vlen; - done; - vout); - -repeated v n is ~double[] -> number -> ~double[] = - concat (map \(v) [1..n]); - -{ - zeros, - consts, - ones, - vector v = v, - primitive = copyOf, - floats, - fromFloats, - fromList, - list = list', - array = array', - length = length', - empty? = empty?', - at = at', - equal, - equalUnder, - slice, - resizedTo, - reversed, - repeated, - concat, -} as { - zeros is number -> vector, - consts is number -> number -> vector, - ones is number -> vector, - vector is ~double[] -> vector, - primitive is vector -> ~double[], - floats is vector -> ~float[], - fromFloats is ~float[] -> vector, - fromList is list?<number> -> vector, - list is vector -> list<number>, - array is vector -> array<number>, - length is vector -> number, - empty? is vector -> boolean, - at is vector -> number -> number, - equal is vector -> vector -> boolean, - equalUnder is (number -> number -> boolean) -> vector -> vector -> boolean, - slice is vector -> number -> number -> vector, - resizedTo is number -> vector -> vector, - reversed is vector -> vector, - repeated is vector -> number -> vector, - concat is list?<vector> -> vector, -} - - -