Mercurial > hg > may
changeset 485:7bd05cfef750
Pull blockfuncs functions into vector (except for fftshift which goes into fft), drop vec.raw
author | Chris Cannam |
---|---|
date | Sat, 02 Nov 2013 14:58:44 +0000 |
parents | 9f87e8eb1e7e |
children | 061dc568cfd8 |
files | src/may/matrix.yeti src/may/signal/window.yeti src/may/stream/channels.yeti src/may/stream/filter.yeti src/may/stream/framer.yeti src/may/stream/resample.yeti src/may/stream/test/test_audiofile.yeti src/may/stream/test/test_resample.yeti src/may/test/all.yeti src/may/transform/fft.yeti src/may/transform/test/test_fft.yeti src/may/vector.yeti src/may/vector/blockfuncs.yeti src/may/vector/test/test_blockfuncs.yeti src/may/vector/test/test_vector.yeti |
diffstat | 15 files changed, 359 insertions(+), 385 deletions(-) [+] |
line wrap: on
line diff
--- a/src/may/matrix.yeti Fri Nov 01 22:12:37 2013 +0000 +++ b/src/may/matrix.yeti Sat Nov 02 14:58:44 2013 +0000 @@ -42,7 +42,6 @@ module may.matrix; vec = load may.vector; -bf = load may.vector.blockfuncs; typedef opaque matrix_t = DenseRows. array<vec.vector_t> | // array of rows @@ -462,7 +461,7 @@ elif isSparse? m1 and isSparse? m2 then sparseSumOrDifference (+) m1 m2; else - add2 v1 v2 = bf.add [v1,v2]; + add2 v1 v2 = vec.add [v1,v2]; denseLinearOp add2 m1 m2; fi; @@ -472,7 +471,7 @@ elif isSparse? m1 and isSparse? m2 then sparseSumOrDifference (-) m1 m2; else - denseLinearOp bf.subtract m1 m2; + denseLinearOp vec.subtract m1 m2; fi; scaled factor m = @@ -480,9 +479,9 @@ 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)); + newMatrix (typeOf m) (map (vec.scaled factor) (asRows m)); else - newMatrix (typeOf m) (map (bf.scaled factor) (asColumns m)); + newMatrix (typeOf m) (map (vec.scaled factor) (asColumns m)); fi; abs' m = @@ -490,9 +489,9 @@ 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)); + newMatrix (typeOf m) (map vec.abs (asRows m)); else - newMatrix (typeOf m) (map bf.abs (asColumns m)); + newMatrix (typeOf m) (map vec.abs (asColumns m)); fi; negative m = @@ -500,9 +499,9 @@ makeSparse (typeOf m) (size m) (map do { i, j, v }: { i, j, v = (-v) } done (enumerate m)) elif isRowMajor? m then - newMatrix (typeOf m) (map bf.negative (asRows m)); + newMatrix (typeOf m) (map vec.negative (asRows m)); else - newMatrix (typeOf m) (map bf.negative (asColumns m)); + newMatrix (typeOf m) (map vec.negative (asColumns m)); fi; //!!! doc: filter by predicate, always returns sparse matrix @@ -602,7 +601,7 @@ 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)); + data[j][i] := vec.sum (vec.multiply row (getColumn j m2)); done; done; DenseCols (array (map vec.vector (list data))));
--- a/src/may/signal/window.yeti Fri Nov 01 22:12:37 2013 +0000 +++ b/src/may/signal/window.yeti Sat Nov 02 14:58:44 2013 +0000 @@ -1,7 +1,6 @@ module may.signal.window; vec = load may.vector; -bf = load may.vector.blockfuncs; mat = load may.matrix; maths = load may.mathmisc; @@ -209,19 +208,19 @@ //!!! doc note: recalculates window every time! not fast for multiple blocks, consider windowedFrames then windowed windowFunc data = - bf.multiply (windowFunc (vec.length data)) data; + vec.multiply (windowFunc (vec.length data)) data; windowedRows windowFunc matrix = (w = windowFunc (mat.width matrix); mat.newMatrix (RowMajor ()) - (map (bf.multiply w) (mat.asRows matrix))); + (map (vec.multiply w) (mat.asRows matrix))); windowedFrames windowFunc frames = case frames of []: frames; _: (first = head frames; window = windowFunc (vec.length first); - map (bf.multiply window) frames); + map (vec.multiply window) frames); esac; {
--- a/src/may/stream/channels.yeti Fri Nov 01 22:12:37 2013 +0000 +++ b/src/may/stream/channels.yeti Sat Nov 02 14:58:44 2013 +0000 @@ -3,13 +3,12 @@ vec = load may.vector; mat = load may.matrix; -bf = load may.vector.blockfuncs; interleaved m = - bf.zipped (mat.asRows m); + vec.zipped (mat.asRows m); deinterleaved channels b = - mat.newMatrix (RowMajor ()) (list (bf.unzipped channels b)); + mat.newMatrix (RowMajor ()) (list (vec.unzipped channels b)); mixedDown m = //!!!doc: average, not sum ({ columns, rows } = (mat.size m); @@ -18,7 +17,7 @@ elif rows == 1 then mat.getRow 0 m else - bf.divideBy rows (bf.add (mat.asRows m)); + vec.divideBy rows (vec.add (mat.asRows m)); fi); mixedDownFromInterleaved channels b = @@ -26,14 +25,13 @@ b; else columns = ((vec.length b) / channels); - v = vec.raw b; v' = new double[columns]; for [0..channels-1] do row: for [0..columns-1] do col: - v'[col] := v'[col] + v[col * channels + row]; + v'[col] := v'[col] + vec.at b (col * channels + row); done; done; - bf.divideBy channels (vec.vector v'); + vec.divideBy channels (vec.vector v'); fi; mixedFromInterleavedTo targetChannels channels b = @@ -43,14 +41,15 @@ mixedDownFromInterleaved channels b; else columns = ((vec.length b) / channels); - v = vec.raw b; v' = new double[columns * targetChannels]; for [0..targetChannels-1] do target: for [0..columns-1] do col: if target < channels then - v'[col * targetChannels + target] := v[col * channels + target]; + v'[col * targetChannels + target] := + vec.at b (col * channels + target); elif channels == 1 and target == 1 then - v'[col * targetChannels + target] := v[col * channels]; + v'[col * targetChannels + target] := + vec.at b (col * channels); fi done done;
--- a/src/may/stream/filter.yeti Fri Nov 01 22:12:37 2013 +0000 +++ b/src/may/stream/filter.yeti Sat Nov 02 14:58:44 2013 +0000 @@ -3,7 +3,6 @@ mat = load may.matrix; vec = load may.vector; -bf = load may.vector.blockfuncs; win = load may.signal.window; convolve = load may.stream.convolve; manip = load may.stream.manipulate; @@ -16,19 +15,19 @@ filterLength = vec.length kw; // First arg to sinc is the complete cycle length for the cutoff frequency idealFor freq = - bf.scaled (2 * freq / rate) + vec.scaled (2 * freq / rate) (win.sinc (rate / freq) filterLength); idealBandpass = if f1 < rate/2 then - if f0 > 0 then bf.subtract (idealFor f1) (idealFor f0) + if f0 > 0 then vec.subtract (idealFor f1) (idealFor f0) else idealFor f1 fi else - if f0 > 0 then bf.subtract (win.dirac filterLength) (idealFor f0) + if f0 > 0 then vec.subtract (win.dirac filterLength) (idealFor f0) else win.dirac filterLength; fi; fi; - filter = bf.multiply idealBandpass kw; + filter = vec.multiply idealBandpass kw; filtered = convolve.convolvedWith [Framesize 1024] (mat.newMatrix (RowMajor ()) (map \filter [1..s.channels])) s;
--- a/src/may/stream/framer.yeti Fri Nov 01 22:12:37 2013 +0000 +++ b/src/may/stream/framer.yeti Sat Nov 02 14:58:44 2013 +0000 @@ -7,7 +7,6 @@ */ vec = load may.vector; -bf = load may.vector.blockfuncs; af = load may.stream.audiofile; win = load may.signal.window; fft = load may.transform.fft; @@ -123,7 +122,7 @@ var position = 0; factor = hop / (framesize/2); - w = bf.scaled factor (window framesize); + w = vec.scaled factor (window framesize); channels = mat.height (head frames); // so we don't need to keep a head ptr syncd = synchronized remaining; @@ -137,7 +136,7 @@ else this = mat.resizedTo { columns = framesize, rows = channels } (mat.newMatrix (RowMajor ()) - (map (bf.multiply w) (mat.asRows (head remaining)))); + (map (vec.multiply w) (mat.asRows (head remaining)))); remaining := tail remaining; framesFor (samples - hop) (this::acc) fi; @@ -177,7 +176,7 @@ windowedFrames { framesize, hop, window } stream = (win = window framesize; - map (bf.multiply win) (monoFrames { framesize, hop } stream)); + map (vec.multiply win) (monoFrames { framesize, hop } stream)); frequencyDomainFrames parameters stream = (f = fft.realForward parameters.framesize;
--- a/src/may/stream/resample.yeti Fri Nov 01 22:12:37 2013 +0000 +++ b/src/may/stream/resample.yeti Sat Nov 02 14:58:44 2013 +0000 @@ -3,7 +3,6 @@ mat = load may.matrix; vec = load may.vector; -bf = load may.vector.blockfuncs; win = load may.signal.window; manip = load may.stream.manipulate; convolve = load may.stream.convolve; @@ -26,7 +25,7 @@ length = if length > maxlength then maxlength else length fi; kw = win.kaiser (pp with { length }); sw = win.sinc (n*2) length; - bf.multiply sw kw); + vec.multiply sw kw); durationAdjusterFor factor s = case s.available of @@ -298,8 +297,8 @@ pd = phaseData[phase]; for [0..s.channels-1] do ch: - rowdata[ch][i] := bf.sum - (bf.multiply (mat.getRow ch buffer) pd.filter); + rowdata[ch][i] := vec.sum + (vec.multiply (mat.getRow ch buffer) pd.filter); done; buffer := mat.concat (Horizontal ()) @@ -330,7 +329,7 @@ obtained = fill rowdata n; scaleFactor = (targetRate / g) / fparams.n; result = mat.newMatrix (RowMajor ()) - (map do r: bf.scaled scaleFactor (vec.vector r) done rowdata); + (map do r: vec.scaled scaleFactor (vec.vector r) done rowdata); if obtained < n then mat.columnSlice result 0 obtained else result fi)
--- a/src/may/stream/test/test_audiofile.yeti Fri Nov 01 22:12:37 2013 +0000 +++ b/src/may/stream/test/test_audiofile.yeti Sat Nov 02 14:58:44 2013 +0000 @@ -4,7 +4,6 @@ af = load may.stream.audiofile; vec = load may.vector; mat = load may.matrix; -bf = load may.vector.blockfuncs; ref = load may.stream.test.audiofile_reference; @@ -29,7 +28,7 @@ do test ref: abs (test - ref) < slack done); maxOf m = - bf.max (vec.fromList (map bf.max (mat.asRows m))); + vec.max (vec.fromList (map vec.max (mat.asRows m))); testReferenceFile rate channels bitdepth = (test = readAll (af.open (testfile "\(rate)-\(channels)-\(bitdepth)"));
--- a/src/may/stream/test/test_resample.yeti Fri Nov 01 22:12:37 2013 +0000 +++ b/src/may/stream/test/test_resample.yeti Sat Nov 02 14:58:44 2013 +0000 @@ -2,7 +2,6 @@ module may.stream.test.test_resample; vec = load may.vector; -bf = load may.vector.blockfuncs; mat = load may.matrix; syn = load may.stream.syntheticstream; manip = load may.stream.manipulate; @@ -154,7 +153,7 @@ // Return magnitude spectrum, running fft at n points and then // truncating to m specOf sig n m = - vec.resizedTo m (bf.divideBy n (fft.realForwardMagnitude n sig)); + vec.resizedTo m (vec.divideBy n (fft.realForwardMagnitude n sig)); all id (map do { inrate, outrate }: @@ -184,7 +183,7 @@ // Interpolating any signal by N should give a signal in which // every Nth sample is the original signal data = vec.fromList [ 0, 0.1, -0.3, -0.4, -0.3, 0, 0.5, 0.2, 0.8, -0.1 ]; - data = vec.concat [ data, bf.scaled (5/4) data, bf.scaled (3/4) data, data ]; + data = vec.concat [ data, vec.scaled (5/4) data, vec.scaled (3/4) data, data ]; data = vec.concat [ data, data ]; input = manip.withDuration (vec.length data) (syn.precalculatedMono 4 data); factor = 3; @@ -198,7 +197,7 @@ "interpolated-rs-misc": \( // Just as above, but using resampledTo instead of interpolated data = vec.fromList [ 0, 0.1, -0.3, -0.4, -0.3, 0, 0.5, 0.2, 0.8, -0.1 ]; - data = vec.concat [ data, bf.scaled (5/4) data, bf.scaled (3/4) data, data ]; + data = vec.concat [ data, vec.scaled (5/4) data, vec.scaled (3/4) data, data ]; data = vec.concat [ data, data ]; input = manip.withDuration (vec.length data) (syn.precalculatedMono 4 data); factor = 3; @@ -212,7 +211,7 @@ "same-rate": \( // Test that resample to the original rate leaves data unchanged data = vec.fromList [ 0, 0.1, -0.3, -0.4, -0.3, 0, 0.5, 0.2, 0.8, -0.1 ]; - data = vec.concat [ data, bf.scaled (5/4) data, bf.scaled (3/4) data, data ]; + data = vec.concat [ data, vec.scaled (5/4) data, vec.scaled (3/4) data, data ]; data = vec.concat [ data, data ]; input = syn.precalculatedMono 4 data; output = resample.resampledTo (input.sampleRate) input;
--- a/src/may/test/all.yeti Fri Nov 01 22:12:37 2013 +0000 +++ b/src/may/test/all.yeti Sat Nov 02 14:58:44 2013 +0000 @@ -6,7 +6,6 @@ tests = [ "mathmisc" : load may.mathmisc.test.test_mathmisc, "vector" : load may.vector.test.test_vector, -"blockfuncs" : load may.vector.test.test_blockfuncs, "complex" : load may.complex.test.test_complex, "framer" : load may.stream.test.test_framer, "channels" : load may.stream.test.test_channels,
--- a/src/may/transform/fft.yeti Fri Nov 01 22:12:37 2013 +0000 +++ b/src/may/transform/fft.yeti Sat Nov 02 14:58:44 2013 +0000 @@ -5,7 +5,6 @@ vec = load may.vector; complex = load may.complex; -bf = load may.vector.blockfuncs; packedToComplex len p is number -> ~double[] -> array<complex.complex_t> = (n = len / 2; @@ -32,11 +31,11 @@ v); unpackedToComplex len unp is number -> vec.vector_t -> array<complex.complex_t> = - (vv = bf.unzipped 2 unp; + (vv = vec.unzipped 2 unp; array (map2 complex.complex (vec.list vv[0]) (vec.list vv[1]))); complexToUnpacked cc is array<complex.complex_t> -> vec.vector_t = - bf.zipped [ vec.fromList (map complex.real cc), + vec.zipped [ vec.fromList (map complex.real cc), vec.fromList (map complex.imaginary cc) ]; //!!! doc: n separately as below @@ -82,11 +81,23 @@ vec.vector arr; done); +fftshift v = + (len = vec.length v; + half = int(len/2 + 0.5); // round up for odd-length sequences + vec.concat [vec.slice v half len, vec.slice v 0 half]); + +ifftshift v = + (len = vec.length v; + half = int(len/2); // round down for odd-length sequences + vec.concat [vec.slice v half len, vec.slice v 0 half]); + { forward, inverse, realForward, realForwardMagnitude, realInverse, +fftshift, +ifftshift, }
--- a/src/may/transform/test/test_fft.yeti Fri Nov 01 22:12:37 2013 +0000 +++ b/src/may/transform/test/test_fft.yeti Sat Nov 02 14:58:44 2013 +0000 @@ -1,8 +1,8 @@ module may.transform.test.test_fft; -{ forward, inverse, realForward, realForwardMagnitude, realInverse } = load may.transform.fft; -{ list, fromList } = load may.vector; +{ forward, inverse, realForward, realForwardMagnitude, realInverse, fftshift, ifftshift } = load may.transform.fft; +{ list, fromList, zeros } = load may.vector; { complex, magnitude, real, imaginary } = load may.complex; { compare } = load may.test.test; @@ -67,6 +67,18 @@ testFFTComplex [1,0,-1,0] [0,1,0,-1] [0,4,0,0] [0,0,0,0]; ), +"fftshift": \( + compare ((list . fftshift . zeros) 0) [] and + compare ((list . fftshift . fromList) [1,2,3,4]) [3,4,1,2] and + compare ((list . fftshift . fromList) [1,2,3,4,5]) [4,5,1,2,3] +), + +"ifftshift": \( + compare ((list . ifftshift . zeros) 0) [] and + compare ((list . ifftshift . fromList) [3,4,1,2]) [1,2,3,4] and + compare ((list . ifftshift . fromList) [4,5,1,2,3]) [1,2,3,4,5] +), + ] is hash<string, () -> boolean>;
--- a/src/may/vector.yeti Fri Nov 01 22:12:37 2013 +0000 +++ b/src/may/vector.yeti Sat Nov 02 14:58:44 2013 +0000 @@ -16,9 +16,12 @@ module may.vector; import java.util: Arrays; +import may.bits: VectorBits; + +{ ceil } = load may.mathmisc; /// Return a vector of n zeros. -zeros n = +zeros n is number -> ~double[] = new double[n]; /// Return a vector of length n, containing all m. @@ -130,7 +133,7 @@ /// Return a single new vector that contains the contents of all the /// given vectors, in order. (Unlike the standard module list concat /// function, this one cannot be lazy.) -concat vv is list?<~double[]> -> ~double[] = +concat' vv is list?<~double[]> -> ~double[] = case vv of [v]: v; v0::rest: @@ -150,7 +153,139 @@ /// vector, repeated n times. The vector will therefore have length n /// times the length of v. repeated v n is ~double[] -> number -> ~double[] = - concat (map \(v) [1..n]); + concat' (map \(v) [1..n]); + +sum' v is ~double[] -> number = + VectorBits#sum(v); + +max' v is ~double[] -> number = + (var mx = 0; + for [0..length v - 1] do i: + if i == 0 or v[i] > mx then + mx := v[i]; + fi + done; + mx); + +maxindex v is ~double[] -> number = + (var mx = 0; + var mi = -1; + for [0..length v - 1] do i: + if i == 0 or v[i] > mx then + mx := v[i]; + mi := i; + fi + done; + mi); + +min' v is ~double[] -> number = + (var mn = 0; + for [0..length v - 1] do i: + if i == 0 or v[i] < mn then + mn := v[i]; + fi + done; + mn); + +minindex v is ~double[] -> number = + (var mn = 0; + var mi = -1; + for [0..length v - 1] do i: + if i == 0 or v[i] < mn then + mn := v[i]; + mi := i; + fi + done; + mi); + +mean v is ~double[] -> number = + case length v of + 0: 0; + len: sum' v / len + esac; + +add vv is list?<~double[]> -> ~double[] = + (len = head (sort (map length' vv)); + out = new double[len]; + for vv do v: + VectorBits#addTo(out, v, len); + done; + out); + +subtract v1 v2 is ~double[] -> ~double[] -> ~double[] = + (len = if length v1 < length v2 then length v1 else length v2 fi; + out = new double[len]; + for [0..len-1] do i: + out[i] := v1[i] - v2[i] + done; + out); + +multiply b1 b2 is ~double[] -> ~double[] -> ~double[] = + VectorBits#multiply(b1, b2); + +scaled n v is number -> ~double[] -> ~double[] = + if n == 1 then v + else VectorBits#scaled(v, n); + fi; + +divideBy n v is number -> ~double[] -> ~double[] = + // Not just "scaled (1/n)" -- this way we get exact rationals. In fact + // the unit test for this function will fail if we use scaled (1/n) + if n == 1 then v + else fromList (map (/ n) (list' v)); + fi; + +sqr v = + multiply v v; + +rms = + sqrt . mean . sqr; + +abs' = + fromList . (map abs) . list'; + +negative = + fromList . (map (0-)) . list'; + +sqrt' = + fromList . (map sqrt) . list'; + +unityNormalised v is ~double[] -> ~double[] = + (m = max' (abs' v); + if m != 0 then + divideBy m v; + else + v; + fi); + +zipped vv is list?<~double[]> -> ~double[] = + case vv of + [v]: v; + first::rest: + (len = length' first; + if len != min' (fromList (map length' vv)) then + failWith "Vectors must all be of the same length"; + fi; + fromList + (concat + (map do i: + map do v: + at' v i + done vv + done [0..len-1]))); + _: zeros 0; + esac; + +unzipped n v is number -> ~double[] -> array<~double[]> = + if n == 1 then array [v] + else + len = length' v; + vv = array (map \(new double[ceil(len / n)]) [1..n]); + for [0..len-1] do x: + vv[x % n][int (x / n)] := at' v x; + done; + array vv; + fi; typedef opaque vector_t = ~double[]; @@ -174,8 +309,26 @@ resizedTo, reverse, repeated, - concat, - raw = id, + concat = concat', + sum = sum', + mean, + add, + subtract, + multiply, + divideBy, + scaled, + abs = abs', + negative, + sqr, + sqrt = sqrt', + rms, + max = max', + min = min', + maxindex, + minindex, + unityNormalised, + zipped, + unzipped, } as { zeros is number -> vector_t, consts is number -> number -> vector_t, @@ -197,8 +350,24 @@ reverse is vector_t -> vector_t, repeated is vector_t -> number -> vector_t, concat is list?<vector_t> -> vector_t, - raw is vector_t -> ~double[], + sum is vector_t -> number, + mean is vector_t -> number, + add is list?<vector_t> -> vector_t, + subtract is vector_t -> vector_t -> vector_t, + multiply is vector_t -> vector_t -> vector_t, + divideBy is number -> vector_t -> vector_t, + scaled is number -> vector_t -> vector_t, + abs is vector_t -> vector_t, + negative is vector_t -> vector_t, + sqr is vector_t -> vector_t, + sqrt is vector_t -> vector_t, + rms is vector_t -> number, + max is vector_t -> number, + min is vector_t -> number, + maxindex is vector_t -> number, + minindex is vector_t -> number, + unityNormalised is vector_t -> vector_t, + zipped is list?<vector_t> -> vector_t, + unzipped is number -> vector_t -> array<vector_t>, } - -
--- a/src/may/vector/blockfuncs.yeti Fri Nov 01 22:12:37 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,183 +0,0 @@ - -module may.vector.blockfuncs; - -vec = load may.vector; - -{ ceil } = load may.mathmisc; - -import may.bits: VectorBits; - -sum' v = VectorBits#sum(vec.raw v); - -max' v = - (dat = vec.raw v; - var mx = 0; - for [0..length dat - 1] do i: - if i == 0 or dat[i] > mx then - mx := dat[i]; - fi - done; - mx); - -maxindex v = - (dat = vec.raw v; - var mx = 0; - var mi = -1; - for [0..length dat - 1] do i: - if i == 0 or dat[i] > mx then - mx := dat[i]; - mi := i; - fi - done; - mi); - -min' v = - (dat = vec.raw v; - var mn = 0; - for [0..length dat - 1] do i: - if i == 0 or dat[i] < mn then - mn := dat[i]; - fi - done; - mn); - -minindex v = - (dat = vec.raw v; - var mn = 0; - var mi = -1; - for [0..length dat - 1] do i: - if i == 0 or dat[i] < mn then - mn := dat[i]; - mi := i; - fi - done; - mi); - -mean v = - case vec.length v of - 0: 0; - len: sum' v / len - esac; - -add bb = - (len = head (sort (map vec.length bb)); - vv = map vec.raw bb; - out = new double[len]; - for vv do v: - VectorBits#addTo(out, v, len); - done; - vec.vector out); - -subtract b1 b2 = - (v1 = vec.raw b1; - v2 = vec.raw b2; - len = if length v1 < length v2 then length v1 else length v2 fi; - out = new double[len]; - for [0..len-1] do i: - out[i] := v1[i] - v2[i] - done; - vec.vector out); - -multiply b1 b2 = - vec.vector VectorBits#multiply(vec.raw b1, vec.raw b2); - -scaled n v = - if n == 1 then v - else vec.vector VectorBits#scaled(vec.raw v, n); - fi; - -divideBy n v = - // Not just "scaled (1/n)" -- this way we get exact rationals. In fact - // the unit test for this function will fail if we use scaled (1/n) - if n == 1 then v - else vec.fromList (map (/ n) (vec.list v)); - fi; - -sqr v = - multiply v v; - -rms = - sqrt . mean . sqr; - -abs' = - vec.fromList . (map abs) . vec.list; - -negative = - vec.fromList . (map (0-)) . vec.list; - -sqrt' = - vec.fromList . (map sqrt) . vec.list; - -unityNormalised v = - (m = max' (abs' v); - if m != 0 then - divideBy m v; - else - v; - fi); - -fftshift v = - (len = vec.length v; - half = int(len/2 + 0.5); // round up for odd-length sequences - vec.concat [vec.slice v half len, vec.slice v 0 half]); - -ifftshift v = - (len = vec.length v; - half = int(len/2); // round down for odd-length sequences - vec.concat [vec.slice v half len, vec.slice v 0 half]); - -zipped vv = - case vv of - [v]: v; - first::rest: - (len = vec.length first; - if len != min' (vec.fromList (map vec.length vv)) then - failWith "Vectors must all be of the same length"; - fi; - vec.fromList - (concat - (map do i: - map do v: - vec.at v i - done vv - done [0..len-1]))); - _: vec.zeros 0; - esac; - -unzipped n v = - if n == 1 then array [v] - else - len = vec.length v; - vv = array (map \(new double[ceil(len / n)]) [1..n]); - for [0..len-1] do x: - vv[x % n][int (x / n)] := vec.at v x; - done; - array (map vec.vector vv); - fi; - -{ -sum is vec.vector_t -> number = sum', -mean is vec.vector_t -> number, -add is list?<vec.vector_t> -> vec.vector_t, -subtract is vec.vector_t -> vec.vector_t -> vec.vector_t, -multiply is vec.vector_t -> vec.vector_t -> vec.vector_t, -divideBy is number -> vec.vector_t -> vec.vector_t, -scaled is number -> vec.vector_t -> vec.vector_t, -abs is vec.vector_t -> vec.vector_t = abs', -negative is vec.vector_t -> vec.vector_t, -sqr is vec.vector_t -> vec.vector_t, -sqrt is vec.vector_t -> vec.vector_t = sqrt', -rms is vec.vector_t -> number, -max is vec.vector_t -> number = max', -min is vec.vector_t -> number = min', -maxindex is vec.vector_t -> number, -minindex is vec.vector_t -> number, -unityNormalised is vec.vector_t -> vec.vector_t, -fftshift is vec.vector_t -> vec.vector_t, -ifftshift is vec.vector_t -> vec.vector_t, -zipped is list?<vec.vector_t> -> vec.vector_t, -unzipped is number -> vec.vector_t -> array<vec.vector_t>, -} - - -
--- a/src/may/vector/test/test_blockfuncs.yeti Fri Nov 01 22:12:37 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,143 +0,0 @@ - -module may.vector.test.test_blockfuncs; - -stdSqrt = sqrt; - -{ zeros, consts, ones, fromList, list } = load may.vector; -{ sum, max, min, maxindex, minindex, mean, add, subtract, multiply, divideBy, scaled, abs, negative, sqr, sqrt, rms, unityNormalised, fftshift, ifftshift, zipped, unzipped } = load may.vector.blockfuncs; -{ compare } = load may.test.test; - -[ - -"sum": \( - compare ((sum . zeros) 0) 0 and - compare ((sum . zeros) 5) 0 and - compare ((sum . ones) 5) 5 and - compare ((sum . fromList) [1,-2,3,0]) 2 -), - -"max": \( - compare ((max . fromList) [1,-2,3,0]) 3 and - compare ((max . fromList) [-1,-2,-3]) (-1) and - compare ((max . fromList) [4,1]) 4 and - compare ((max . fromList) []) 0 -), - -"min": \( - compare ((min . fromList) [1,-2,3,0]) (-2) and - compare ((min . fromList) [-1,-2,-3]) (-3) and - compare ((min . fromList) [4,1]) 1 and - compare ((min . fromList) []) 0 -), - -"maxindex": \( - compare ((maxindex . fromList) [1,-2,3,0]) 2 and - compare ((maxindex . fromList) [-1,-2,-3]) 0 and - compare ((maxindex . fromList) [4,1]) 0 and - compare ((maxindex . fromList) []) (-1) -), - -"minindex": \( - compare ((minindex . fromList) [1,-2,3,0]) 1 and - compare ((minindex . fromList) [-1,-2,-3]) 2 and - compare ((minindex . fromList) [4,1]) 1 and - compare ((minindex . fromList) []) (-1) -), - -"mean": \( - compare ((mean . zeros) 0) 0 and - compare ((mean . zeros) 5) 0 and - compare ((mean . ones) 5) 1 and - compare ((mean . fromList) [1,-2,3,0]) 0.5 -), - -"add": \( - compare (list (add [zeros 0, ones 5])) [] and - compare (list (add [consts 3 4, fromList [1,2,3] ])) [4,5,6] and - compare (list (add [consts (-3) 4, fromList [1,2,3] ])) [-2,-1,0] -), - -"subtract": \( - compare (list (subtract (zeros 0) (ones 5))) [] and - compare (list (subtract (consts 3 4) (fromList [1,2,3]))) [2,1,0] and - compare (list (subtract (consts (-3) 4) (fromList [1,2,3]))) [-4,-5,-6] -), - -"multiply": \( - compare (list (multiply (zeros 0) (ones 5))) [] and - compare (list (multiply (consts (-3) 4) (fromList [1,2,3]))) [-3,-6,-9] -), - -"divideBy": \( - compare (list (divideBy 5 (ones 0))) [] and - compare (list (divideBy 5 (fromList [1,2,-3]))) [0.2,0.4,-0.6] -), - -"scaled": \( - compare (list (scaled 5 (ones 0))) [] and - compare (list (scaled 5 (fromList [1,2,-3]))) [5,10,-15] -), - -"abs": \( - compare (list (abs (ones 0))) [] and - compare (list (abs (fromList [1,2,-3]))) [1,2,3] -), - -"negative": \( - compare (list (negative (ones 0))) [] and - compare (list (negative (fromList [1,2,-3]))) [-1,-2,3] -), - -"sqr": \( - compare ((list . sqr . zeros) 0) [] and - compare ((list . sqr . ones) 5) [1,1,1,1,1] and - compare ((list . sqr . fromList) [0.5,-2,3,0]) [0.25,4,9,0] -), - -"sqrt": \( - compare ((list . sqrt . zeros) 0) [] and - compare ((list . sqrt . ones) 5) [1,1,1,1,1] and - compare ((list . sqrt . fromList) [0.25,4,9,0]) [0.5,2,3,0] -), - -"rms": \( - compare ((rms . zeros) 0) 0 and - compare ((rms . ones) 5) 1 and - compare ((rms . fromList) [-1,2,2]) (stdSqrt 3) -), - -"unityNormalised": \( - compare ((list . unityNormalised . fromList) [1,-2,3,0]) [1/3,-2/3,1,0] and - compare ((list . unityNormalised . fromList) [-1,-2,-3]) [-1/3,-2/3,-1] and - compare ((list . unityNormalised . fromList) [4,1]) [1,1/4] and - compare ((list . unityNormalised . fromList) []) [] -), - -"fftshift": \( - compare ((list . fftshift . zeros) 0) [] and - compare ((list . fftshift . fromList) [1,2,3,4]) [3,4,1,2] and - compare ((list . fftshift . fromList) [1,2,3,4,5]) [4,5,1,2,3] -), - -"ifftshift": \( - compare ((list . ifftshift . zeros) 0) [] and - compare ((list . ifftshift . fromList) [3,4,1,2]) [1,2,3,4] and - compare ((list . ifftshift . fromList) [4,5,1,2,3]) [1,2,3,4,5] -), - -"zipped": \( - compare (list (zipped (map fromList []))) [] and - compare (list (zipped (map fromList [[],[]]))) [] and - compare (list (zipped (map fromList [[1,2]]))) [1,2] and - compare (list (zipped (map fromList [[1,2],[3,4],[5,6]]))) [1,3,5,2,4,6] -), - -"unzipped": \( - compare (map list (unzipped 1 (fromList []))) [[]] and - compare (map list (unzipped 1 (fromList [1,2,3]))) [[1,2,3]] and - compare (map list (unzipped 3 (fromList [1,3,5,2,4,6]))) [[1,2],[3,4],[5,6]] -), - -] is hash<string, () -> boolean>; - -
--- a/src/may/vector/test/test_vector.yeti Fri Nov 01 22:12:37 2013 +0000 +++ b/src/may/vector/test/test_vector.yeti Sat Nov 02 14:58:44 2013 +0000 @@ -124,6 +124,123 @@ vec.equal (vec.concat [v,w,v]) (vec.fromList [1,2,3,4,5,6,1,2,3]) ), +"sum": \( + compare ((vec.sum . vec.zeros) 0) 0 and + compare ((vec.sum . vec.zeros) 5) 0 and + compare ((vec.sum . vec.ones) 5) 5 and + compare ((vec.sum . vec.fromList) [1,-2,3,0]) 2 +), + +"max": \( + compare ((vec.max . vec.fromList) [1,-2,3,0]) 3 and + compare ((vec.max . vec.fromList) [-1,-2,-3]) (-1) and + compare ((vec.max . vec.fromList) [4,1]) 4 and + compare ((vec.max . vec.fromList) []) 0 +), + +"min": \( + compare ((vec.min . vec.fromList) [1,-2,3,0]) (-2) and + compare ((vec.min . vec.fromList) [-1,-2,-3]) (-3) and + compare ((vec.min . vec.fromList) [4,1]) 1 and + compare ((vec.min . vec.fromList) []) 0 +), + +"maxindex": \( + compare ((vec.maxindex . vec.fromList) [1,-2,3,0]) 2 and + compare ((vec.maxindex . vec.fromList) [-1,-2,-3]) 0 and + compare ((vec.maxindex . vec.fromList) [4,1]) 0 and + compare ((vec.maxindex . vec.fromList) []) (-1) +), + +"minindex": \( + compare ((vec.minindex . vec.fromList) [1,-2,3,0]) 1 and + compare ((vec.minindex . vec.fromList) [-1,-2,-3]) 2 and + compare ((vec.minindex . vec.fromList) [4,1]) 1 and + compare ((vec.minindex . vec.fromList) []) (-1) +), + +"mean": \( + compare ((vec.mean . vec.zeros) 0) 0 and + compare ((vec.mean . vec.zeros) 5) 0 and + compare ((vec.mean . vec.ones) 5) 1 and + compare ((vec.mean . vec.fromList) [1,-2,3,0]) 0.5 +), + +"add": \( + compare (vec.list (vec.add [vec.zeros 0, vec.ones 5])) [] and + compare (vec.list (vec.add [vec.consts 3 4, vec.fromList [1,2,3] ])) [4,5,6] and + compare (vec.list (vec.add [vec.consts (-3) 4, vec.fromList [1,2,3] ])) [-2,-1,0] +), + +"subtract": \( + compare (vec.list (vec.subtract (vec.zeros 0) (vec.ones 5))) [] and + compare (vec.list (vec.subtract (vec.consts 3 4) (vec.fromList [1,2,3]))) [2,1,0] and + compare (vec.list (vec.subtract (vec.consts (-3) 4) (vec.fromList [1,2,3]))) [-4,-5,-6] +), + +"multiply": \( + compare (vec.list (vec.multiply (vec.zeros 0) (vec.ones 5))) [] and + compare (vec.list (vec.multiply (vec.consts (-3) 4) (vec.fromList [1,2,3]))) [-3,-6,-9] +), + +"divideBy": \( + compare (vec.list (vec.divideBy 5 (vec.ones 0))) [] and + compare (vec.list (vec.divideBy 5 (vec.fromList [1,2,-3]))) [0.2,0.4,-0.6] +), + +"scaled": \( + compare (vec.list (vec.scaled 5 (vec.ones 0))) [] and + compare (vec.list (vec.scaled 5 (vec.fromList [1,2,-3]))) [5,10,-15] +), + +"abs": \( + compare (vec.list (vec.abs (vec.ones 0))) [] and + compare (vec.list (vec.abs (vec.fromList [1,2,-3]))) [1,2,3] +), + +"negative": \( + compare (vec.list (vec.negative (vec.ones 0))) [] and + compare (vec.list (vec.negative (vec.fromList [1,2,-3]))) [-1,-2,3] +), + +"sqr": \( + compare ((vec.list . vec.sqr . vec.zeros) 0) [] and + compare ((vec.list . vec.sqr . vec.ones) 5) [1,1,1,1,1] and + compare ((vec.list . vec.sqr . vec.fromList) [0.5,-2,3,0]) [0.25,4,9,0] +), + +"sqrt": \( + compare ((vec.list . vec.sqrt . vec.zeros) 0) [] and + compare ((vec.list . vec.sqrt . vec.ones) 5) [1,1,1,1,1] and + compare ((vec.list . vec.sqrt . vec.fromList) [0.25,4,9,0]) [0.5,2,3,0] +), + +"rms": \( + compare ((vec.rms . vec.zeros) 0) 0 and + compare ((vec.rms . vec.ones) 5) 1 and + compare ((vec.rms . vec.fromList) [-1,2,2]) (sqrt 3) +), + +"unityNormalised": \( + compare ((vec.list . vec.unityNormalised . vec.fromList) [1,-2,3,0]) [1/3,-2/3,1,0] and + compare ((vec.list . vec.unityNormalised . vec.fromList) [-1,-2,-3]) [-1/3,-2/3,-1] and + compare ((vec.list . vec.unityNormalised . vec.fromList) [4,1]) [1,1/4] and + compare ((vec.list . vec.unityNormalised . vec.fromList) []) [] +), + +"zipped": \( + compare (vec.list (vec.zipped (map vec.fromList []))) [] and + compare (vec.list (vec.zipped (map vec.fromList [[],[]]))) [] and + compare (vec.list (vec.zipped (map vec.fromList [[1,2]]))) [1,2] and + compare (vec.list (vec.zipped (map vec.fromList [[1,2],[3,4],[5,6]]))) [1,3,5,2,4,6] +), + +"unzipped": \( + compare (map vec.list (vec.unzipped 1 (vec.fromList []))) [[]] and + compare (map vec.list (vec.unzipped 1 (vec.fromList [1,2,3]))) [[1,2,3]] and + compare (map vec.list (vec.unzipped 3 (vec.fromList [1,3,5,2,4,6]))) [[1,2],[3,4],[5,6]] +), + ] is hash<string, () -> boolean>;