Mercurial > hg > may
changeset 283:e330ac62703b
Merge
author | Chris Cannam |
---|---|
date | Wed, 29 May 2013 17:32:58 +0100 |
parents | f3784641245f (diff) b432db0b2529 (current diff) |
children | 7932bbb7bacb |
files | |
diffstat | 8 files changed, 362 insertions(+), 43 deletions(-) [+] |
line wrap: on
line diff
--- a/yetilab/matrix.yeti Fri May 24 12:41:41 2013 +0100 +++ b/yetilab/matrix.yeti Wed May 29 17:32:58 2013 +0100 @@ -9,6 +9,11 @@ // result regardless of storage order. (The transpose function just // switches the row/column order without moving the elements.) +// The matrix representation does not take into account different +// forms of zero-width or zero-height matrix. That is, all matrices of +// zero width or height are equal to each other and to the zero-size +// matrix -- they can't be distinguished. + vec = load yetilab.vector; bf = load yetilab.vector.blockfuncs; @@ -168,6 +173,8 @@ zeroSizeMatrix () = zeroMatrix { rows = 0, columns = 0 }; +isZeroSize? m = (width m == 0 or height m == 0); + generate f { rows, columns } = if rows < 1 or columns < 1 then zeroSizeMatrix () else @@ -333,7 +340,9 @@ esac); equal' comparator vecComparator m1 m2 = - if size m1 != size m2 then + if isZeroSize? m1 and isZeroSize? m2 then + true + elif size m1 != size m2 then false elif isRowMajor? m1 != isRowMajor? m2 then equal' comparator vecComparator (flipped m1) m2; @@ -437,7 +446,7 @@ newMatrix (typeOf m) (map bf.abs (asColumns m)); fi; -filter f m = +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 @@ -600,7 +609,7 @@ 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 +concat' direction mm = //!!! doc: storage order is taken from first matrix in sequence case length mm of 0: zeroSizeMatrix (); 1: head mm; @@ -628,20 +637,44 @@ fi; esac; +//!!! doc this filter -- zero-size elts are ignored +concat direction mm = + concat' direction (filter do mat: not (isZeroSize? mat) done mm); + +//!!! next two v. clumsy + //!!! doc note: argument order chosen for consistency with std module slice +//!!! NB always returns dense matrix, should have sparse version 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))) + if start < 0 then rowSlice m 0 end + elif start > height m then rowSlice m (height m) end + else + if end < start then rowSlice m start start + elif end > height m then rowSlice m start (height m) + else + 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; + fi; fi; //!!! doc note: argument order chosen for consistency with std module slice +//!!! NB always returns dense matrix, should have sparse version 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))) + if start < 0 then columnSlice m 0 end + elif start > width m then columnSlice m (width m) end + else + if end < start then columnSlice m start start + elif end > width m then columnSlice m start (width m) + else + 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; + fi; fi; resizedTo newsize m = @@ -694,6 +727,7 @@ zeroMatrix, identityMatrix, zeroSizeMatrix, + isZeroSize?, equal, equalUnder, transposed, @@ -709,7 +743,7 @@ sum = sum', difference, abs = abs', - filter, + filter = filter', product, concat, rowSlice, @@ -740,6 +774,7 @@ zeroMatrix is { .rows is number, .columns is number } -> matrix, identityMatrix is { .rows is number, .columns is number } -> matrix, zeroSizeMatrix is () -> matrix, + isZeroSize? is matrix -> boolean, equal is matrix -> matrix -> boolean, equalUnder is (number -> number -> boolean) -> matrix -> matrix -> boolean, transposed is matrix -> matrix,
--- a/yetilab/matrix/test/test_matrix.yeti Fri May 24 12:41:41 2013 +0100 +++ b/yetilab/matrix/test/test_matrix.yeti Wed May 29 17:32:58 2013 +0100 @@ -360,7 +360,19 @@ "zeroSizeMatrix-\(name)": \( compareMatrices (mat.zeroSizeMatrix ()) - (newMatrix (ColumnMajor ()) []) + (newMatrix (ColumnMajor ()) []) and + compareMatrices + (mat.zeroSizeMatrix ()) + (newMatrix (ColumnMajor ()) [[]]) and + compareMatrices + (newMatrix (ColumnMajor ()) [[]]) + (newMatrix (RowMajor ()) [[]]) and + compareMatrices + (mat.zeroSizeMatrix ()) + (mat.newSparseMatrix (ColumnMajor ()) { rows = 0, columns = 1 } []) and + compareMatrices + (mat.zeroSizeMatrix ()) + (mat.newSparseMatrix (ColumnMajor ()) { rows = 1, columns = 0 } []) ), "asRows-\(name)": \( @@ -385,6 +397,15 @@ (newMatrix (ColumnMajor ()) [[1,4],[0,5],[3,6]]) ), +"concatEmpty-horiz-\(name)": \( + compareMatrices + (mat.concat (Horizontal ()) + [(newMatrix (ColumnMajor ()) [[]]), + (newMatrix (RowMajor ()) [[]]), + (mat.zeroSizeMatrix ())]) + (mat.zeroSizeMatrix ()); +), + "sparseConcat-horiz-\(name)": \( s = mat.concat (Horizontal ()) [mat.toSparse (newMatrix (ColumnMajor ()) [[1,4],[0,5]]), @@ -436,13 +457,19 @@ "rowSlice-\(name)": \( compareMatrices (mat.rowSlice (newMatrix (RowMajor ()) [[1,0],[3,4],[0,6],[7,8]]) 1 3) - (newMatrix (RowMajor ()) [[3,4],[0,6]]) + (newMatrix (RowMajor ()) [[3,4],[0,6]]) and + compareMatrices + (mat.rowSlice (newMatrix (RowMajor ()) [[1,0],[3,4],[0,6],[7,8]]) 3 6) + (newMatrix (RowMajor ()) [[7,8]]) ), "columnSlice-\(name)": \( compareMatrices (mat.columnSlice (newMatrix (RowMajor ()) [[1,0,3,4],[0,6,7,8]]) 1 3) - (newMatrix (RowMajor ()) [[0,3],[6,7]]) + (newMatrix (RowMajor ()) [[0,3],[6,7]]) and + compareMatrices + (mat.columnSlice (newMatrix (RowMajor ()) [[1,0,3,4],[0,6,7,8]]) 2 5) + (newMatrix (RowMajor ()) [[3,4],[7,8]]) ), "density-\(name)": \(
--- a/yetilab/stream/filter.yeti Fri May 24 12:41:41 2013 +0100 +++ b/yetilab/stream/filter.yeti Wed May 29 17:32:58 2013 +0100 @@ -3,8 +3,11 @@ mat = load yetilab.matrix; ch = load yetilab.stream.channels; +vec = load yetilab.vector; load yetilab.stream.type; +load yetilab.vector.type; +load yetilab.matrix.type; minDurationOf d1 d2 = case d1 of @@ -202,6 +205,117 @@ } fi; +duplicated copies s = +//!!! doc fact that original s cannot be used independently of this afterward +// (so maybe name is misleading?) + if copies < 2 then map \s [1..copies]; + else + pos = [:]; + lowtide () = head (sort (map (at pos) (keys pos))); + var hightide = 0; + var cache = mat.zeroSizeMatrix (); + syncd = synchronized pos; + advance i n = + (formerLow = lowtide (); + pos[i] := pos[i] + n; + encroachment = lowtide () - formerLow; + if encroachment > 0 then + cache := mat.columnSlice cache encroachment (mat.width cache); + fi); + map do instance: + pos[instance] := 0; + { + get position () = syncd \(pos[instance]), + get channels () = syncd \(s.channels), + get sampleRate () = syncd \(s.sampleRate), + get available () = syncd + \(case s.available of + Known av: Known (av + (hightide - pos[instance])); + other: other; + esac), + get finished? () = syncd + \(if not s.finished? then false + else pos[instance] >= hightide + fi), + read count = syncd + \(ready = hightide - pos[instance]; + if s.finished? and ready <= 0 + then mat.zeroSizeMatrix () + else + if count > ready then + more = s.read (count - ready); + cache := mat.concat (Horizontal ()) [cache, more]; + hightide := hightide + (mat.width more); + fi; + offset = pos[instance] - (lowtide ()); + chunk = mat.columnSlice cache offset (offset + count); + advance instance (mat.width chunk); + chunk; + fi), + close () = syncd + \(delete pos instance; + if empty? pos then + s.close () + fi), + } + done [1..copies]; + fi; + +convolvedWith ir s = + (if mat.height ir != s.channels then + failWith "Signal stream and IR must have same number of channels (\(s.channels) != \(mat.height ir))" + fi; + var history = mat.toRowMajor + (mat.zeroMatrix { rows = s.channels, columns = mat.width ir - 1 }); + s with + { + get finished? () = + s.finished? and (mat.isZeroSize? history), + get available () = + case s.available of + Known n: Known (n + mat.width history); + other: other; + esac, + read count = + (// Example: The IR is four samples long; we have three + // samples in history; two samples are available to read + // before the stream runs out. That means we can return + // up to five samples. Caller requests 6. + signal = s.read count; // -> two samples + siglen = mat.width signal; // -> 2 + histlen = mat.width history; // -> 3 + convlen = min count (siglen + histlen); // -> 5 + input = mat.resizedTo { rows = s.channels, columns = convlen } + signal; // example input now 5 samples, of which 2 are signal + output = array (map \(new double[convlen]) [1..s.channels]); + for [0..s.channels - 1] do ch: + for [0..mat.width input - 1] do i: + for [0..mat.width ir - 1] do j: + v = + if i >= j then + mat.at input ch (i - j) + else + ix = mat.width ir + i - j - 1; + if ix >= histlen then + 0 + else + mat.at history ch ix + fi + fi; + output[ch][i] := output[ch][i] + v * (mat.at ir ch j); + done; + done; + done; + // Remove from history a number of samples equal to the + // number returned; add to it a number equal to the number + // read from source + extended = mat.concat (Horizontal ()) [history, signal]; // -> 5 + newlen = (histlen + siglen) - convlen; // -> 0 + w = mat.width extended; + history := mat.columnSlice extended (w - newlen) w; + mat.newMatrix (RowMajor ()) (map vec.vector output)), + }); + { withDuration is number -> stream -> stream, delayedBy is number -> stream -> stream, @@ -209,7 +323,7 @@ mixed is list<stream> -> stream, multiplexed is list<stream> -> stream, repeated is stream -> stream, + duplicated is number -> stream -> list<stream>, + convolvedWith is matrix -> stream -> stream, } - -
--- a/yetilab/stream/framer.yeti Fri May 24 12:41:41 2013 +0100 +++ b/yetilab/stream/framer.yeti Wed May 29 17:32:58 2013 +0100 @@ -13,6 +13,7 @@ fft = load yetilab.transform.fft; mat = load yetilab.matrix; ch = load yetilab.stream.channels; +syn = load yetilab.stream.syntheticstream; blockList framesize stream = if stream.finished? then @@ -57,6 +58,35 @@ framesize (map \(vec.zeros framesize) [0..stream.channels-1]); fi; +streamContiguous rate framesize fr = + if empty? frames then + syn.empty rate 1 + else + var position = 0; + var frames = fr; + var fini = false; + channels = mat.height (head frames); // so we don't need to keep head ptr + { + get position () = position, + get channels () = channels, + get sampleRate () = rate, + get available () = if fini then Known 0 else Unknown () fi, + get finished? () = fini, + + + close = \(), + } + fi; + +//!!! doc: convert frames back to a stream +streamed rate { framesize, hop } frames = + if framesize == hop then + streamContiguous rate framesize frames + else + //!!! OLA + syn.empty rate 1; + fi; + monoFrames params stream = map ch.mixedDown (frames params stream);
--- a/yetilab/stream/syntheticstream.yeti Fri May 24 12:41:41 2013 +0100 +++ b/yetilab/stream/syntheticstream.yeti Wed May 29 17:32:58 2013 +0100 @@ -52,12 +52,24 @@ close = \(), }); +empty rate channels = // degenerate stream with no data in it, occasionally useful + { + get position () = 0, + get channels () = channels, + get sampleRate () = rate, + get available () = Known 0, + get finished? () = true, + read count = mat.zeroSizeMatrix (), + close = \(), + }; + { generated is number -> (number -> number) -> stream, precalculated is number -> vector -> stream, sinusoid is number -> number -> stream, whiteNoise is number -> stream, silent is number -> stream, + empty = number -> number -> stream, }
--- a/yetilab/stream/test/test_filter.yeti Fri May 24 12:41:41 2013 +0100 +++ b/yetilab/stream/test/test_filter.yeti Wed May 29 17:32:58 2013 +0100 @@ -9,7 +9,7 @@ { compare, compareUsing } = load yetilab.test.test; makeTests name withUnknown = - (withDuration n str = + (maybeDuration n str = // Truncate a stream, but if withUnknown is true, return it // with availability Unknown -- so as to test that other // filter functions behave correctly even if availability is @@ -68,7 +68,7 @@ // we're actually testing filt.withDuration here rather than just // generating a stream for use in another test. The inner call // does use the wrapper. - str = filt.withDuration 5 (withDuration 3 (syn.generated 2 id)); + str = filt.withDuration 5 (maybeDuration 3 (syn.generated 2 id)); compare str.position 0 and compare str.channels 1 and compare str.sampleRate 2 and @@ -86,7 +86,7 @@ ), "delayedBy-0-3-\(name)": \( - str = filt.delayedBy 0 (withDuration 3 (syn.generated 2 id)); + str = filt.delayedBy 0 (maybeDuration 3 (syn.generated 2 id)); compare str.position 0 and compare str.channels 1 and compare str.sampleRate 2 and @@ -114,7 +114,7 @@ ), "delayedBy-2-3-\(name)": \( - str = filt.delayedBy 2 (withDuration 3 (syn.generated 2 id)); + str = filt.delayedBy 2 (maybeDuration 3 (syn.generated 2 id)); compare str.position 0 and compare str.channels 1 and compare str.sampleRate 2 and @@ -132,7 +132,7 @@ ), "delayedBy-m2-3-\(name)": \( - str = filt.delayedBy (-2) (withDuration 3 (syn.generated 2 id)); + str = filt.delayedBy (-2) (maybeDuration 3 (syn.generated 2 id)); compare str.position 0 and compare str.channels 1 and compare str.sampleRate 2 and @@ -146,7 +146,7 @@ ), "delayedBy-m4-3-\(name)": \( - str = filt.delayedBy (-4) (withDuration 3 (syn.generated 2 id)); + str = filt.delayedBy (-4) (maybeDuration 3 (syn.generated 2 id)); compare str.position 0 and compare str.channels 1 and compare str.sampleRate 2 and @@ -157,7 +157,7 @@ ), "delayedBy-2-3b-\(name)": \( - str = filt.delayedBy 2 (withDuration 3 (syn.generated 2 id)); + str = filt.delayedBy 2 (maybeDuration 3 (syn.generated 2 id)); compare str.position 0 and compare str.channels 1 and compare str.sampleRate 2 and @@ -175,7 +175,7 @@ ), "delayedBy-2-3c-\(name)": \( - str = filt.delayedBy 2 (withDuration 3 (syn.generated 2 id)); + str = filt.delayedBy 2 (maybeDuration 3 (syn.generated 2 id)); compare str.position 0 and compare str.channels 1 and compare str.sampleRate 2 and @@ -221,7 +221,7 @@ ), "mixedTo-1-2-\(name)": \( - str = filt.mixedTo 2 (withDuration 3 (syn.generated 2 id)); + str = filt.mixedTo 2 (maybeDuration 3 (syn.generated 2 id)); compare str.position 0 and compare str.channels 2 and compare str.sampleRate 2 and @@ -237,8 +237,8 @@ "mixedTo-2-1-\(name)": \( str = filt.mixedTo 1 (filt.multiplexed - [withDuration 3 (syn.generated 2 id), - withDuration 3 (syn.generated 2 id)]); + [maybeDuration 3 (syn.generated 2 id), + maybeDuration 3 (syn.generated 2 id)]); compare str.position 0 and compare str.channels 1 and compare str.sampleRate 2 and @@ -254,8 +254,8 @@ "mixedTo-2-3-\(name)": \( str = filt.mixedTo 3 (filt.multiplexed - [withDuration 3 (syn.generated 2 id), - withDuration 3 (syn.generated 2 (+1))]); + [maybeDuration 3 (syn.generated 2 id), + maybeDuration 3 (syn.generated 2 (+1))]); compare str.position 0 and compare str.channels 3 and compare str.sampleRate 2 and @@ -269,7 +269,7 @@ ), "mixedTo-1-3-\(name)": \( - str = filt.mixedTo 3 (withDuration 3 (syn.generated 2 id)); + str = filt.mixedTo 3 (maybeDuration 3 (syn.generated 2 id)); compare str.position 0 and compare str.channels 3 and compare str.sampleRate 2 and @@ -296,7 +296,7 @@ ), "mixed-inf-trunc-\(name)": \( - str = filt.mixed [syn.generated 2 (2*), withDuration 3 (syn.generated 2 (0-))]; + str = filt.mixed [syn.generated 2 (2*), maybeDuration 3 (syn.generated 2 (0-))]; compare str.position 0 and compare str.channels 1 and compare str.sampleRate 2 and @@ -312,7 +312,7 @@ "mixed-precalc-trunc-\(name)": \( str = filt.mixed [syn.precalculated 2 (vec.fromList [1,2]), - withDuration 3 (syn.generated 2 (0-))]; + maybeDuration 3 (syn.generated 2 (0-))]; compare str.position 0 and compare str.channels 1 and compare str.sampleRate 2 and @@ -329,7 +329,7 @@ str = filt.mixed [syn.precalculated 2 (vec.fromList [1,2]), filt.multiplexed [syn.precalculated 2 (vec.fromList [3,4]), - withDuration 3 (syn.generated 2 (0-))]]; + maybeDuration 3 (syn.generated 2 (0-))]]; compare str.position 0 and compare str.channels 2 and compare str.sampleRate 2 and @@ -346,7 +346,7 @@ str = filt.mixed [syn.precalculated 2 (vec.fromList [1,2]), syn.precalculated 2 (vec.fromList [3,4]), - withDuration 3 (syn.generated 2 (0-))]; + maybeDuration 3 (syn.generated 2 (0-))]; compare str.position 0 and compare str.channels 1 and compare str.sampleRate 2 and @@ -374,7 +374,7 @@ ), "multiplexed-inf-trunc-\(name)": \( - str = filt.multiplexed [syn.generated 2 id, withDuration 3 (syn.generated 2 (0-))]; + str = filt.multiplexed [syn.generated 2 id, maybeDuration 3 (syn.generated 2 (0-))]; compare str.position 0 and compare str.channels 2 and compare str.sampleRate 2 and @@ -390,7 +390,7 @@ "multiplexed-precalc-trunc-\(name)": \( str = filt.multiplexed [syn.precalculated 2 (vec.fromList [1,2]), - withDuration 3 (syn.generated 2 (0-))]; + maybeDuration 3 (syn.generated 2 (0-))]; compare str.position 0 and compare str.channels 2 and compare str.sampleRate 2 and @@ -407,7 +407,7 @@ str = filt.multiplexed [syn.precalculated 2 (vec.fromList [1,2]), filt.multiplexed [syn.precalculated 2 (vec.fromList [3,4]), - withDuration 3 (syn.generated 2 (0-))]]; + maybeDuration 3 (syn.generated 2 (0-))]]; compare str.position 0 and compare str.channels 3 and compare str.sampleRate 2 and @@ -424,7 +424,7 @@ str = filt.multiplexed [syn.precalculated 2 (vec.fromList [1,2]), syn.precalculated 2 (vec.fromList [3,4]), - withDuration 3 (syn.generated 2 (0-))]; + maybeDuration 3 (syn.generated 2 (0-))]; compare str.position 0 and compare str.channels 3 and compare str.sampleRate 2 and @@ -460,6 +460,96 @@ ( str.close (); true ) ), +"duplicated-1-\(name)": \( + original = maybeDuration 3 (syn.precalculated 2 (vec.fromList [1,2,3])); + sn = filt.duplicated 1 original; + str = (head sn); + compare (length sn) 1 and + compare str.position 0 and + compare str.channels 1 and + compare str.sampleRate 2 and + compare str.available (maybeKnown 3) and + compare str.finished? false and + compare (map vec.list (mat.asRows (str.read 1))) [[1]] and + compare str.position 1 and + compare str.available (maybeKnown 2) and + compare (map vec.list (mat.asRows (str.read 3))) [[2,3]] and + compare str.position 3 and + compare str.finished? true and + compare str.available (Known 0) and + ( str.close (); true ) +), + +"duplicated-2-\(name)": \( + original = maybeDuration 3 (syn.precalculated 2 (vec.fromList [1,2,3])); + sn = filt.duplicated 2 original; + s1 = (head sn); + s2 = (head (tail sn)); + + compare (length sn) 2 and + + compare s1.position 0 and + compare s1.channels 1 and + compare s1.sampleRate 2 and + compare s1.available (maybeKnown 3) and + compare s1.finished? false and + + compare s2.position 0 and + compare s2.channels 1 and + compare s2.sampleRate 2 and + compare s2.available (maybeKnown 3) and + compare s2.finished? false and + + compare (map vec.list (mat.asRows (s1.read 1))) [[1]] and + compare s1.position 1 and + compare s1.available (maybeKnown 2) and + compare s2.position 0 and + compare s2.available (maybeKnown 3) and + + compare (map vec.list (mat.asRows (s2.read 2))) [[1,2]] and + compare s1.position 1 and + compare s1.available (maybeKnown 2) and + compare s2.position 2 and + compare s2.available (maybeKnown 1) and + + compare (map vec.list (mat.asRows (s1.read 3))) [[2,3]] and + compare s1.position 3 and + compare s1.finished? true and + compare s1.available (Known 0) and + compare s2.position 2 and + compare s2.finished? false and + compare s2.available (Known 1) and // when one is known, so is the other + + compare (map vec.list (mat.asRows (s1.read 3))) [] and + + compare (map vec.list (mat.asRows (s2.read 1))) [[3]] and + compare s1.position 3 and + compare s1.finished? true and + compare s2.position 3 and + compare s2.finished? true and + + ( s1.close (); s2.close() ; true ) +), + +"convolvedWith-\(name)": \( + ir = mat.newRowVector (vec.fromList [1,2,3]); + signal = maybeDuration 2 (syn.precalculated 2 (vec.fromList [1,2])); + c = filt.convolvedWith ir signal; + compare c.position 0 and + compare c.channels 1 and + compare c.sampleRate 2 and + compare c.available (maybeKnown 4) and + compare (map vec.list (mat.asRows (c.read 3))) + [[ 1*1, 2*1 + 1*2, 0*1 + 2*2 + 1*3 ]] and + compare c.available (Known 1) and + compare c.finished? false and + compare (map vec.list (mat.asRows (c.read 4))) + [[ 0*1 + 0*2 + 2*3 ]] and + compare c.available (Known 0) and + compare c.finished? true and + ( c.close (); true ) +), + //!!! still no tests for filters with multi-channel inputs ]);
--- a/yetilab/vector.yeti Fri May 24 12:41:41 2013 +0100 +++ b/yetilab/vector.yeti Wed May 29 17:32:58 2013 +0100 @@ -72,7 +72,15 @@ //!!! 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); + if start < 0 then slice v 0 end + elif start > length' v then slice v (length' v) end + else + if end < start then slice v start start + elif end > length' v then slice v start (length' v) + else + Arrays#copyOfRange(v, start, end); + fi + fi; resizedTo n v is number -> ~double[] -> ~double[] = Arrays#copyOf(v, n);
--- a/yetilab/vector/test/test_vector.yeti Fri May 24 12:41:41 2013 +0100 +++ b/yetilab/vector/test/test_vector.yeti Wed May 29 17:32:58 2013 +0100 @@ -78,9 +78,12 @@ "slice": \( v = vec.fromList [1,2,3,4]; - vec.equal (vec.slice v 0 4) v and ( - vec.equal (vec.slice v 2 4) (vec.fromList [3,4]) - ) + vec.equal (vec.slice v 0 4) v and + vec.equal (vec.slice v 2 4) (vec.fromList [3,4]) and + vec.equal (vec.slice v (-1) 2) (vec.fromList [1,2]) and + vec.equal (vec.slice v 3 5) (vec.fromList [4]) and + vec.equal (vec.slice v 5 7) (vec.fromList []) and + vec.equal (vec.slice v 3 2) (vec.fromList []) ), "resizedTo": \(