Mercurial > hg > ishara
changeset 3:3f77126f7b5f
First major revision of sequence library, now using classdef form, STILL A BIT BROKEN!
line wrap: on
line diff
--- a/arrows/@agraph/acquire.m Sat Dec 22 16:17:51 2012 +0000 +++ b/arrows/@agraph/acquire.m Wed Jan 09 22:22:21 2013 +0000 @@ -6,7 +6,8 @@ ud.arrows=[ud.arrows,{a}]; set(0,'UserData',ud); else - fprintf('Arrow %s cannot use figure %d, already in use by %s.\n',tostring(a),fig(a),tostring(ud.arrows{i})); + fprintf('Arrow %s [%s] cannot use figure %d, already in use by %s [%s].\n',... + tostring(a),a.opts.name,fig(a),tostring(ud.arrows{i}),ud.arrows{i}.opts.name); error('Figure already in use by arrow.'); end end
--- a/arrows/@plotter/plotter.m Sat Dec 22 16:17:51 2012 +0000 +++ b/arrows/@plotter/plotter.m Wed Jan 09 22:22:21 2013 +0000 @@ -16,7 +16,7 @@ % the handle graphics object returned by the plotting function. function o=plotter(varargin) - s.opts=prefs('dlim',[],'dom',[],'ylim',[],'xlim',[],'plotfn',@plot,'args',{},'tranpose',0,varargin{:}); + s.opts=prefs('dlim',[],'dom',[],'ylim',[],'xlim',[],'plotfn',@plot,'args',{},'transpose',0,varargin{:}); if isempty(s.opts.ylim), s.opts.ylim=s.opts.dlim; end o=class(s,'plotter',agraph(1,s.opts)); end
--- a/arrows/adata.m Sat Dec 22 16:17:51 2012 +0000 +++ b/arrows/adata.m Wed Jan 09 22:22:21 2013 +0000 @@ -1,11 +1,11 @@ -% adata - Arrow to generate stream from lazy sequence object +% aseq - Arrow to generate stream from lazy sequence object % -% adata :: seq(A) -> arrow( {}, {A}, seq(A)). -function a=adata(X) +% aseq :: seq(A) -> arrow( {}, {A}, seq(A)). +function a=aseq(X) a=unfolder(@decons1,X); end function [h,t]=decons1(x) - if isempty(x), error('ARROW:EOF','End of data sequence'); end + if isempty(x), error('ARROW:EOF','End of sequence'); end [h,t]=decons(x); end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/bindcat.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,40 @@ +% bindcat - sort of monadic bind for sequences. +% +% bindcat :: +% seq(A) ~ 'the first sequence', +% (A->seq(A)) ~ 'function to return second sequence given last element of first' +% -> seq(A) ~ 'resultant sequence'. +% +% The resulting sequence consists of the entire sequence represented by the +% first parameter, followed by the sequence obtained by applying the second +% parameter to the last nonempty element of the first sequence. +% +% Example: +% +% gather(2,bindcat(cellseq({1,2,3,4}),@(x)take(head(x),0))) +% +% ans = 1 2 3 4 0 0 0 0 +classdef bindcat < seq + properties (GetAccess=private, SetAccess=private) + source + nfn + x + end + methods + function o=bindcat(X,F) + o.source=X; + o.nfn=F; + o.x=head(X); + end + + function z=elsize(o), z=size(o.x); end + function s=tostring(o), s=sprintf('%s >>= %s',tostring(o.source),tostring(o.nfn)); end + function x=head(o), x=o.x; end + function o=next(o), + o.source=next(o.source); + if isempty(o.source), o=o.nfn(o.x); + else o.x=head(o.source); + end + end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/buffer.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,70 @@ +% buffer - collect elements of sequence into sequence of arrays +% +% buffer :: +% seq([Size:[[1,E]]]) ~'sequence of E dimensional arrays', +% L:natural ~'buffer width', +% E:natural ~'effective dimension of input values', +% buffer_tailfn ~'function to deal with last incomplete buffer' +% -> seq([[Size,L]]) ~'buffered sequence (no-overlapping)'. +% +% buffer_tailfn can be +% seq.buffer.truncate :: void -> tailfn ~'discard incomplete buffer'. +% seq.buffer.append :: void -> tailfn ~'append smaller buffer to sequence'. +% seq.buffer.pad :: [[N]]-> tailfn ~'pad final buffer with value'. + +classdef buffer < seq + properties (GetAccess=private, SetAccess=immutable) + width + colons + tailfn + end + properties (GetAccess=private, SetAccess=private) + source + buf + end + methods + function a=buffer(source,L,dim,tailfn) + sz=size1(source); + if nargin<3, dim=length(sz); end + if nargin<4, tailfn=seq.buffer.truncate; end + colons = repmat({':'},1,dim); + buf=repmat(head(source),tosize([ones(size(colons)),L])); + source=next(source); + for i=2:L + if isempty(source), a=tailfn(buf,i-1,colons); return; end + buf(colons{:},i)=head(source); + source=next(source); + end + a.source = source; + a.width = L; + a.colons=colons; + a.tailfn = tailfn; + a.buf=buf; + end + + function z=elsize(a), z=size(a.buf); end + function s=tostring(a), s=sprintf('%s >> buffer(%d,%d)',tostring(a.source),a.width,length(a.colons)+1); end + function x=head(a), x=a.buf; end + function a=next(a) + % read next lot of values and make an array + for i=1:a.width + if isempty(a.source), a=a.tailfn(a.buf,i-1,a.colons); return; end + a.buf(a.colons{:},i)=head(a.source); + a.source=next(a.source); + end + end + end + + methods (Static) + function f=truncate, f=@(buf,i,colons)[]; end + function f=append, f=@(buf,i,colons)singleton(buf(colons{:},1:i)); end + function f=pad(x), f=@padfn; + function s=padfn(buf,i,colons) + L=size(buf,length(colons)+1); + buf(colons{:},i+1:L)=repmat(x,tosize([ones(size(colons)),L-i])); + s=singleton(buf); + end + end + end +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/cache.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,22 @@ +% cache- Cache each buffer to speed up multiple reads +% +% cache :: seq(A) -> seq(A). +% +% The idea is that the data is cached on each call to next, +% so that reading the array does not require calls to source. +classdef cache < seq + properties (GetAccess=private, SetAccess=private) + source + x + end + methods + function o=cache(source), o.source=source; o.x=head(source); end + function x=head(o), x=o.x; end + function s=tostring(o), s=['cache(',tostring(o.source),')']; end + function z=elsize(o), z=size(o.x); end + function o=next(o) + o.source=next(o.source); + if ~isempty(o.source), o.x=head(o.source); else o=[]; end + end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/concat.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,46 @@ +% concat - Concatenate sequences +% +% concat :: +% seq(seq(A)) ~ 'sequence of sequences' +% -> seq(A) ~ 'resultant sequence'. +% +% concat :: +% {[N]->seq(A)} ~ 'cell array of N sequences', +% -> seq(A) ~ 'resultant sequence'. +classdef concat < seq + properties (GetAccess=private, SetAccess=private) + current + sources + end + methods + function o=concat(sources) + if iscell(sources), sources=cellseq(sources); end + if isempty(sources), o=[]; return; end + + hd=head(sources); + while isempty(hd) + sources=next(sources); + if isempty(sources), o=[]; return; end + hd=head(sources); + end + o.current=hd; + o.sources=next(sources); + end + + function x=head(o), x=head(o.current); end + function s=elsize(o), s=elsize(o.current); end + function s=tostring(o), s=sprintf('concat(%s,...)',tostring(o.current)); end + function o=next(o), + o.current=next(o.current); + if isempty(o.current), o=next_source(o); end + end + + function o=next_source(o) + while isempty(o.current) + if isempty(o.sources), o=[]; break; end + o.current=head(o.sources); + o.sources=next(o.sources); + end + end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/cons.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,17 @@ +% cons - sequence constructor +% +% cons :: A, seq(A) -> seq(A). +classdef cons < seq + properties (GetAccess=private, SetAccess=immutable) + hd + tl + end + methods + function o=cons(h,t), o.hd=h; o.tl=t; end + function x=head(o), x=o.hd; end + function b=next(o), b=o.tl; end + function z=elsize(o), z=size(o.hd); end + function s=tostring(o), s=sprintf('%s > %s',tostring(o.hd),tostring(o.tl)); end + end +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/cycle.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,23 @@ +% cycle - cycles through input sequence repeatedly +% +% cycle :: seq(A) -> seq(A). +classdef cycle < seq + properties (GetAccess=private, SetAccess=private) + source + orig + end + methods + function o=cycle(source) + o.orig=source; + o.source=source; + end + + function z=elsize(o), z=elsize(o.source); end + function s=tostring(o), s=sprintf('cycle(%s)',tostring(o.source)); end + function x=head(o), x=head(o.source); end + function o=next(o), + o.source=next(o.source); + if isempty(o.source), o.source=o.orig; end + end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/iterate.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,16 @@ +% iterate - Construct sequence by recursive application of arbitrary function +% +% iterate :: (A->A), A -> seq(A). +classdef iterate < seq + properties (GetAccess=private, SetAccess=private) + fn + s + end + methods + function x=iterate(f,s0), x.fn=f; x.s=s0; end + function z=elsize(x), z=size(x.s); end + function s=tostring(x), s=sprintf('iter(%s,%s)',tostring(x.fn),tostring(x.s)); end + function a=head(x), a=x.s; end + function x=next(x), x.s=x.fn(x.s); if isempty(x.s), x=[]; end; end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/lcons.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,17 @@ +% lcons - sequence constructor +% +% lcons :: A, (void->seq(A)) -> seq(A). +classdef lcons < seq + properties (GetAccess=private, SetAccess=immutable) + hd + tlfn + end + methods + function o=lcons(h,tf), o.hd=h; o.tlfn=tf; end + function x=head(o), x=o.hd; end + function b=next(o), b=o.tlfn(); end + function z=elsize(o), z=size(o.hd); end + function s=tostring(o), s=sprintf('%s > (%s)',tostring(o.hd),tostring(o.tlfn)); end + end +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/map.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,23 @@ +% map - seq where values is a stateless function of another sequence +% +% map :: (A->B), seq(A) -> seq(B). +classdef map < seq + properties (GetAccess=public, SetAccess=private) + fn + source + end + methods + function d=map(fn,source,varargin) + d.fn=fn; + d.source=source; + end + + function s=tostring(d), s=sprintf('%s >> %s',tostring(d.source),tostring(d.fn)); end; + function x=head(d), x=d.fn(head(d.source)); end + function s=elsize(d), s=size(head(d)); end + function d=next(d) + d.source=next(d.source); + if isempty(d.source), d=[]; end + end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/mapaccum.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,30 @@ +% mapaccum - sequences where values are a stateful function of another sequence +% +% mapaccum :: (A,S->B,S), S, seq(A) -> seq(B). +classdef mapaccum < seq + properties (GetAccess=private, SetAccess=private) + sfn + source + state + x + end + methods + function d=mapaccum(sfn,state,source) + d.sfn=sfn; % function to apply + d.source=next(source); + [d.x,d.state]=d.sfn(head(source),state); + end + + function s=elsize(d), s=size(d.x); end + function s=tostring(d), s=sprintf('%s >> [%s]',tostring(d.source),tostring(d.sfn)); end + function x=head(d), x=d.x; end + function d=next(d), + d.source=next(d.source); + if ~isempty(d.source) + [d.x,d.state]=d.sfn(head(d.source),d.state); + else + d=[]; + end + end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/merge.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,41 @@ +% merge - Combine several seq sources using a given function +% +% merge :: +% ( (A1,...,An)->natural ~ chooser function, +% n:natural ~ number of sources to combine, +% seq A1,...,seq An ~ n seq sources, +% ... ~ options +% ) -> seq B +classdef merge < seq + properties (GetAccess=private, SetAccess=private) + fn + sources + hd + end + methods + function d=merge(c,sources,varargin) + d.fn=c; + d.hd=[]; + d.sources=sources; + end + + + function x=head(d), x=d.hd; end + function d=next(d) + data=cellmap(@head,d.sources); + if isempty(data), d=[]; + else + k=d.fn(data); + d.hd=data{k}; + nk=next(d.sources{k}); + if isempty(nk), d.sources(k)=[]; + else d.sources{k}=nk; end + end + end + + function z=elsize(d), z=size(d.hd); end + function s=tostring(d) + s=sprintf('{ %s } >> merge(%s)',cat_sep(',',cellmap(@tostring,d.sources)),tostring(d.fn)); + end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/repeat.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,15 @@ +% repeat - infinite sequence repeating one value +% +% repeat :: A -> seq(A). +classdef repeat < seq + properties (GetAccess=private, SetAccess=immutable) + value + end + methods + function d=repeat(x), d.value=x; end + function s=elsize(o), s=size(o.value); end + function x=head(o), x=o.value; end + function o=next(o), end; + function s=tostring(o), s=sprintf('repeat(%s)',tostring(o.value)); end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/replicate.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,1 @@ +function y=replicate(n,x), y=take(n,repeat(x));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/resize.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,36 @@ +% resize - sequence with overridden reported element size +% +% resize :: Size:[[1,E]], seq([_->A]) -> seq([Size->A]). +classdef resize < seq + properties (GetAccess=private, SetAccess=private) + source + newsize + check + end + methods + function o=resize(newsize,source,check) + if ~size_match(elsize(source),newsize), + error('seq.resize: size mismatch'); + end + if nargin<3, check=0; end + o.source=source; + o.newsize=newsize; + o.check=check; + end + + function x=head(a), x=head(a.source); if a.check, size_check(a.newsize,size(x)); end; end + function a=next(a), a.source=next(a.source); if isempty(a.source), a=[]; end; end + function s=elsize(a), s=a.newsize; end + function s=tostring(a), s=tostring(a.source); end + end +end + +function b=size_match(s1,s2) + b=all((s1==s2) | isnan(s1) | isnan(s2)); +end + +function b=size_check(spec,size) + if ~all((spec==size) | isnan(spec)) + error('seq.resize: element size does not match specification'); + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/scanl.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,32 @@ +% scanl - sequence of values accumulated by function passing over sequence +% +% This works like scanl in a functional language (see eg, Haskell) +% +% scanl :: +% (S,A)->S) ~ function to update output given new input, +% S ~ initial state, +% seq(A), ~ source seq +%-> seq(S). +classdef scanl < seq + properties (GetAccess=private, SetAccess=private) + scanfn + source + x + end + methods + function d=scanl(f,s0,source) + d.scanfn=f; % function to apply + d.x=d.scanfn(s0,head(source)); + d.source=next(source); + end + + function s=tostring(d), s=sprintf('%s >> scan(%s)',tostring(d.source),tostring(d.scanfn)); end + function z=elsize(d), z=size(d.x); end; + function x=head(d), x=d.x; end + function d=next(d), + if isempty(d.source), d=[]; return; end + d.x=d.scanfn(d.x,head(d.source)); + d.source=next(d.source); + end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/select.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,30 @@ +% select - Use boolean function to keep only matching elements from sequence +% +% select :: (A->bool), seq(A) -> seq(A). +classdef select < seq + properties (GetAccess=private, SetAccess=private) + fn + source + x + end + methods + function d=select(fn,source) + d.fn=fn; % function to apply + d.source=source; + d.x=head(source); + if ~d.fn(d.x), d=next(d); end + end + + function z=elsize(o), z=elsize(d.x); end + function s=tostring(o), s=sprintf('%s >> %s?',tostring(o.source),tostring(o.fn)); end + function x=head(d), x=d.x; end + function o=next(o) + while 1 + o.source=next(o.source); + if isempty(o.source), o=[]; return; end + o.x=head(o.source); + if o.fn(o.x), break; end + end + end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/skin.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,20 @@ +% skin - Give a sequence arbitrary string represention +% +% skin :: seq(A), (seq(A)->string) -> seq(A). +classdef skin < seq + properties (GetAccess=private, SetAccess=private) + source + stringfn + end + methods + function o=skin(source,stringfn) + o.source=source; o.stringfn=stringfn; + end + + function x=head(a), x=head(a.source); end + function a=next(a), a.source=next(a.source); if isempty(a.source), a=[]; end; end + function s=elsize(a), s=elsize(a.source); end + function s=tostring(a), s=a.stringfn(a); end + end +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/slices.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,63 @@ +% slices - sequence obtained from slices of an array +% +% slices :: +% [[Size,M]->A] ~'array to slices', +% -> seq([[Size]->A]). +% +% slices :: +% [Size->A] ~'array to slices', +% D:natural ~'dimension of desired values' +% -> seq([Size:[[1,D]]->A]). +% +% If 2nd parameter not given, the array is sliced along it's +% last non-singleton dimension, so the element size is the size +% after this dimension has been removed. If given, the dimension +% parameter cannot be smaller than the number of non-singleton +% dimensions in the input. + +classdef slices < seq + properties (GetAccess=private, SetAccess=immutable) + slice % natural -> [[N]] + elsz % [[1,E]] + length % natural + dim + end + properties (GetAccess=private, SetAccess=private) + index % natural + end + methods + function d=slices(x,dim) + sz=strip1(size(x)); + if nargin<2, dim=length(sz)-1; end + if dim<length(sz)-1, error('Cannot slice along inner dimensions'); end + + d.elsz=sz(1:dim); + d.slice=slicer(x,dim+1); + d.length=size(x,dim+1); + d.index=1; + d.dim=dim; + end + + function s=elsize(o), s=tosize(o.elsz); end + function s=tostring(o), + s=sprintf('slices(x:[%s],%d)@%d',mat2str([o.elsz,o.length]),o.dim,o.index); + end + function x=head(o), x=o.slice(o.index); end + function o=next(o) + if o.index<o.length, o.index=o.index+1; + else o=[]; + end + end + end +end + +function f=slicer(x,dim) + switch dim + case 1, f=@(i)x(i); + case 2, f=@(i)x(:,i); + case 3, f=@(i)x(:,:,i); + otherwise + colons=repmat({':'},1,dim-1); + f=@(i)x(colons{:},i); + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/subsample.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,25 @@ +% subsample - keep every N values from a sequence +% +% subsample :: +% natural ~ sample rate, +% seq(A), ~ source seq, +% ... ~ options) +% -> seq(A). +classdef subsample < seq + properties (GetAccess=private, SetAccess=private) + source + n + end + methods + function d=subsample(a,s), d.n=a; d.source=s; end + function s=tostring(d), s=sprintf('%s >> subsample(%d)',tostring(d.source),tostring(d.n)); end + function z=elsize(o), o=size(head(o)); end + function x=head(d), x=head(d.source); end + function o=next(o) + for i=1:o.n + o.source=next(o.source); + if isempty(o.source), o=[]; break; end + end + end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/take.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,22 @@ +% TAKE - Take first n alements of sequence then stop +% +% take :: natural, seq(A) -> seq(A). +classdef take < seq + properties (GetAccess=private, SetAccess=private) + source + n + end + methods + function o=take(n,source), o.source=source; o.n=n; end + function z=elsize(o), z=elsize(o.source); end + function s=tostring(o), s=sprintf('take(%d,%s)',o.n,tostring(o.source)); end + function x=head(o), x=head(o.source); end + function o=next(o) + if o.n==1, o=[]; + else + o.source=next(o.source); + if isempty(o), o=[]; else o.n=o.n-1; end + end + end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/takewhile.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,32 @@ +% takewhile - Take elements of seq while a condition is met. +% +% takewhile :: (A->bool), seq(A) -> seq(A). +classdef takewhile < seq + properties (GetAccess=private, SetAccess=private) + source + f + x + end + methods + function o=takewhile(f,source) + if ~f(head(source)), o=[]; + else + o.source=source; + o.f=f; + o.x=head(source); + end + end + + function z=elsize(o), z=size(o.x); end + function s=tostring(o), s=sprintf('takewhile(%s,%s)',tostring(o.f),tostring(o.source)); end + function x=head(o), x=o.x; end + function o=next(o) + o.source=next(o.source); + if isempty(o.source), o=[]; + else + o.x=head(o.source); + if ~o.f(o.x), o=[]; end + end + end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/unfold.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,36 @@ +% unfoldseq - sequence obtained by iterating fn over state +% +% unfold :: +% (S->A,S) ~'unfolding function', +% S ~ initial state, +% -> unfold(S,A) < seq(A). +% +% NB. The empty array [] is a special value for the state +% meaning there are no more elements in the sequence. You +% cannot use [] as a normal state value. +classdef unfold < seq + properties (GetAccess=private, SetAccess=immutable) + fn + end + properties (GetAccess=private, SetAccess=private) + value + state + end + methods + function d=unfold(f,s0,varargin) + [x,s]=f(s0); + d.value=x; + d.state=s; + d.fn=f; % function to apply + end + + function s=elsize(o), s=size(o.value); end + function s=tostring(o), s=sprintf('unfold(%s,%s)',tostring(o.fn),tostring(o.state)); end + function x=head(o), x=o.value; end + function o=next(o) + if isempty(o.state), o=[]; + else [o.value,o.state]=o.fn(o.state); + end + end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/unfold_inf.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,28 @@ +% unfold_inf - infinite sequence obtained by iterating function over state +% +% unfold_inf :: +% (S->A,S) ~'unfolding function', +% S ~ initial state, +% -> seq(A). +classdef unfold_inf < seq + properties (GetAccess=private, SetAccess=immutable) + fn + end + properties (GetAccess=private, SetAccess=private) + value + state + end + methods + function d=unfold_inf(f,s0,varargin) + [x,s]=f(s0); + d.value=x; + d.state=s; + d.fn=f; % function to apply + end + + function s=elsize(o), s=size(o.value); end + function s=tostring(o), s=sprintf('unfold(%s,%s)',tostring(o.fn),tostring(o.state)); end + function x=head(o), x=o.value; end + function o=next(o), [o.value,o.state]=o.fn(o.state); end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/window.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,124 @@ +% window - abstract data object for extracting window from another data +% +% window :: +% X:seq([[C,M]]) ~'source signal', +% N:natural ~'window size', +% natural ~'hop size', +% options { +% dim :: natural/ndims(X) ~'dimension to window along (default is last)'; +% wrap:: bool /1 ~ if 1, then source is treated as a contiguous stream in +% the dimth dimension; otherwise, each buffer is windowed +% independently.' +% } +% -> seq([[C,N]]). +classdef window < seq + properties (GetAccess=private, SetAccess=private) + source + hop + length + pos + opts + curr + end + methods + function a=window(src,span,hop,varargin) + if nargin<3, + if nargin<2, span=1; end + hop=span; + end + sz=size(src); + opts=prefs('wrap',1,'dim',length(sz),'strict',1,varargin{:}); + + dim=opts.dim; wrap=opts.wrap; + a.hop=hop; a.span=span; + + % mutable state + a.length=sz(dim); + a.pos = 0; + a.opts =opts; + a.curr =[]; + + % sort out function table + if wrap + ft.headfn=@(a)a.curr; + ft.nextfn=@next_caching; + + [a.curr,src,a.pos,a.length]=itread(dim,span,src,0,a.length); + if size(a.curr,dim)<span, a=[]; return; end; % !! Strict window length? + a.source=src; + a=a@dseq(src,arrset(sz,dim,span),ft); + else + ft.headfn=@(a)extract(head(source(a)),dim,a.pos+[1 span]); + ft.nextfn=@next_seq_nowrap; + a.source=src; + + a=a@dseq(src,arrset(sz,dim,span),ft); + if a.length<span, a=next_seq_nowrap(a); end; + end + + + % optimised next (assumes wrap=1) + function a=next_caching(a) + src=source(a); + if isempty(src) + a=[]; + else + [x,src,a.pos,a.length]=itread(dim,hop,src,a.pos,a.length); + if size(x,dim)<hop, + if opts.strict, + a=[]; % strict window length + else + a.curr=cat(dim,extract(a.curr,dim,[hop+1 span]),x); + a.source=src; + end + else + a.curr=cat(dim,extract(a.curr,dim,[hop+1 span]),x); + a.source=src; + end + end + end + + function a=next_seq_nowrap(a) + a.pos=a.pos+hop; % next window position + while a.pos+span>a.length % next window would overrun + a=next_nc(a); if isempty(a), break; end + a.length=size(source(a),dim); + a.pos=0; + end + end + end + + + % iterative read - read len samples starting at pos in head + % buffer of source. Returns tail source and pos for subsequent + % reads. + function [chunk,source,pos,max]=itread(dim,len,source,pos,max) + if len==0 || isempty(source), chunk=[]; return; end + + chunk=[]; + if pos+len>=max + chunk=extract(head(source),dim,[pos+1 max]); + len=pos+len-max; + source=next(source); + if ~isempty(source), + max=size(source,dim); + while len>=max + chunk=cat(dim,chunk,head(source)); len=len-max; + source=next(source); + if isempty(source), break; end + max=size(source,dim); + end + pos=0; + end + end + if ~isempty(source), + ex=extract(head(source),dim,pos+[1 len]); + if isempty(chunk), chunk=ex; else chunk=cat(dim,chunk,ex); end + pos=pos+len; + end + end + end + + function s=stringfn(a), s=sprintf('%s >> window(%d/%d)',tostring(a.source),a.span,a.hop); end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/zipaccum.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,38 @@ +% zipaccum - Combine several seq sources using a stateful function +% +% zipaccum :: +% (A(1),...,A(N),S->B,S) ~ 'zipping function', +% S ~ 'initial state', +% {I:[N]->seq(A(I))} ~ 'cell array of N sequences', +% -> seq(B). +classdef zipaccum < seq + properties (GetAccess=private, SetAccess=private) + fn + sources + state + x + end + methods + function d=zipaccum(fn,state0,sources) + d.fn=fn; + d.sources=sources; + heads=cellmap(@head,sources); + [d.x,d.state]=d.fn(heads{:},state0); + end + + function z=elsize(o), z=size(o.x); end + function x=head(d), x=d.x; end + function d=next(d) + d.sources=cellmap(@next,d.sources); + if any(cell2mat(cellmap(@isempty,d.sources))), d=[]; + else + args=cellmap(@head,d.sources); + [d.x,d.state]=d.fn(args{:},d.state); + end + end + + function s=tostring(d) + s=sprintf('{%s} >> [%s]',cat_sep(',',cellmap(@tostring,d.sources)),tostring(d.fn)); + end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/+seq/zipwith.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,35 @@ +% zipwith - Combine several seq sources using a given function +% +% zipwith :: +% (A(1),...,A(N)->B) ~ 'zipping function', +% {I:[N]->seq(A(I))} ~ 'cell array of N sequences', +% -> seq(B). +classdef zipwith < seq + properties (GetAccess=private, SetAccess=private) + fn + sources + end + + methods + function d=zipwith(fn,sources) + d.fn=fn; + d.sources=sources; + end + + function s=elsize(d), s=size(head(d)); end + function x=head(d) + args=cellmap(@head,d.sources); + x=d.fn(args{:}); + end + + function d=next(d) + d.sources=cellmap(@next,d.sources); + if any(cell2mat(cellmap(@isempty,d.sources))), d=[]; end + end + + function s=tostring(d) + s=sprintf('{%s} >> %s',cat_sep(',',cellmap(@tostring,d.sources)),tostring(d.fn)); + end + + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/cumsum.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,22 @@ +% cumsum - cumsum for sequences +% +% cumsum :: seq [[N,M]], D:natural -> seq [[N,M]]. +% +% cumulative sum taken along Dth dimension of the array +function y=cumsum(x,n) + if length(size(x))>2 + error('cumsum not supported for >2 dim array sequences'); + end + + switch n + case 1 + y=scanl(@cs1,zeros(1,size(x,2)),x); + case 2 + y=scanl(@cs2,zeros(size(x,1),1),x); + case 3 + error('cumsum(.,3) not supported for sequences'); + end + + function w=cs1(s,z), w=row(cumsum([s(end,:);z],1),2:size(z,1)+1); end + function w=cs2(s,z), w=col(cumsum([s(:,end),z],2),2:size(z,2)+1); end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/diffwith.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,15 @@ +function Y=diffwith(F,X) +% diffwith - Generalised diff using argbitrary binary function +% +% diffwith :: (A,A->B), seq A -> seq B. +% +% The given function gets called with the current value as the +% first arguments and the previous value as the second. + + Y=mapaccum(@diffst,next(X),head(X)); + function [y,s]=diffst(x,s) + y=F(x,s); + s=x; + end +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/dynfilter.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,15 @@ +function y=dynfilter(ab,x,z,dim) +% dynfilter - filter for sequences of array with dynamically varying filter coeffs +% +% dynfilter :: seq {[[P]],[[P]]}, seq [Size], [[P]], D:natural -> seq [Size]. +% dynfilter :: seq {[[P]],[[P]]}, seq [Size], [[P]] -> seq [Size]. +% dynfilter :: seq {[[P]],[[P]]}, seq [Size] -> seq [Size]. +% +% filtering is done along Dth dimension of the array (default=1) + +if nargin<5, + dim=find(size(x)>1,1); + if nargin<4, z=[]; end +end + +y = zipaccum(@(ab1,x1,z1)filter(ab1{1},ab1{2},x1,z1,dim),{ab,x},z);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/filter.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,16 @@ +function y=filter(a,b,x,z,dim) +% filter - filter for sequences of array +% +% filter :: [[P]], [[P]], seq [Size], [[P]], D:natural -> seq [Size]. +% filter :: [[P]], [[P]], seq [Size], [[P]] -> seq [Size]. +% filter :: [[P]], [[P]], seq [Size] -> seq [Size]. +% +% filtering is done along Dth dimension of the array (default=1) + +if nargin<5, + dim=find(size(x)>1,1); + if isempty(dim), dim=1; end + if nargin<4, z=[]; end +end + +y = mapaccum(@(x1,z1)filter(a,b,x1,z1,dim),x,z);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/foldl.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,28 @@ +function x=foldl(fn,e,y,varargin) +% foldl - Fold combinator for sequences +% +% This function applies an associative operator to a list of arguments, +% starting from the left using the given starting element. +% +% foldl :: +% (X,Y->X) ~'associative binary operator', +% X ~'initial element', +% seq(Y) ~'a lazy sequence' +% -> X. + +if nargin<4, + x=e; + while ~isempty(y) + x=fn(x,head(y)); + y=next(y); + end +else + opts=prefs('quiet',1,varargin{:}); + x=e; + while ~isempty(y) + x=fn(x,head(y)); + y=next(y); + if ~opts.quiet, fprintf('.'); end + optpause(opts); + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/foreach.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,10 @@ +% foreach - do an action for each element in a sequence in order +% +% foreach :: (A=>void), seq(A), options {} -> action. +function foreach(f,X,varargin) + iterate(@g,X,varargin{:}); + function x=g(x) + f(head(x)); + x=next(x); + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/gather.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,18 @@ +% gather - make big array of all arrays in a sequence +% +% gather :: N:natural, seq [D] -> [E], seq [D]. +% gather :: +% N:natural ~'the dimension along which to collect arrays', +% seq [D] ~'the seq to gather', +% options { +% draw :: boolean /0 ~'whether or not to call plotfn every iteration'; +% plotfn :: seq [D]->handle ~'plotting function'; +% save :: natural /0 ~'if >0, then save state every this many interations'; +% recover:: boolean / 0 ~'if 1, then attempt to restart from saved state'; +% id :: string /'@gather' ~'file to save state' +% } +% -> [E], seq [D]. +% +% E is such that E(I) = D(I) if I~=N. The second return +% is the final object in the sequence +function Y=gather(dim,X,varargin), Y=gathern(dim,inf,X,varargin{:}); end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/gathern.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,75 @@ +function [Y,X0]=gathern(dim,n,X,varargin) +% gathern - make big array of n arrays in a sequence +% +% gathern :: N:natural, seq [D] -> [E], seq [D]. +% gathern :: +% D:natural ~'the dimension along which to collect arrays', +% N:natural ~'number of elements to collect', +% seq [D] ~'the seq to gather', +% options { +% draw :: boolean /0 ~'whether or not to call plotfn every iteration'; +% plotfn :: seq [D]->handle ~'plotting function'; +% save :: natural /0 ~'if >0, then save state every this many interations'; +% recover:: boolean / 0 ~'if 1, then attempt to restart from saved state'; +% id :: string /'@gather' ~'file to save state' +% } +% -> [E], seq [D]. +% +% E is such that E(I) = D(I) if I~=N. The second return +% is the final object in the sequence + +Y=[]; i=1; +if nargin<3 % simple version + if ~isempty(X), + Y=head(X); + i=1; while i<n + X0=X; X=next(X0); i=i+1; + if isempty(X), break; end + Y=cat(dim,Y,head(X)); + end + end +else + opts=prefs('save',0,'recover',0,'draw',0,'plotfn',@nullplot,varargin{:}); + draw=opts.draw; + savn=opts.save; + + if opts.recover && exist([opts.id,'.mat'],'file') + load(opts.id); + X=next(X0); + fprintf('recovering from i=%d\n',i); + end + + if savn==0 && ~draw + if ~isempty(X) + Y=head(X); + i=1; while i<n + X0=X; X=next(X0); i=i+1; + if isempty(X), break; end + Y=cat(dim,Y,head(X)); + end + end + else + if savn>0 + fprintf('Will save every %d iterations to %s.mat\n',savn,opts.id); + end + + if ~isempty(X) + Y=head(X); + i=1; while i<n + X0=X; X=next(X0); i=i+1; + if draw, opts.plotfn(X0); end + if mod(i,savn)==0, + fprintf('saving at %d.\n',i); + save(opts.id,'X0','Y','opts','i','dim'); + end + optpause(opts); + if isempty(X), break; end + Y=cat(dim,Y,head(X)); + end + end + if savn>0, delete([opts.id '.mat']); end + end + if nargout>1, if isempty(X), X0=X; else X0=next(X); end; end +end + +function nullplot(A,B), return
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/integrate.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,27 @@ +% integrate - integrate sequence +% +% integrate :: +% seq [[N1,N2]] ~'sequence to integrate', +% D:natural ~'dimension to integrate along', +% [[M1,M2]] ~'initial value', +% ( [[M1,M2]] -> [[M1,M2]]) ~'function to filter initial value each block' +% -> seq [[N,M]]. +% +% cumulative sum taken along Dth dimension of the array + +function y=integrate(x,n,a,ff) + if length(size(x))>2 + error('cumsum not supported for >2 dim array sequences'); + end + + if nargin<4, ff=@(t)t; end + + switch n + case 1, y=scanseq(@cs1,a,x); + case 2, y=scanseq(@cs2,a,x); + case 3, error('integrate(_,3) not supported for sequences'); + end + + function w=cs1(s,z), w=row(cumsum([ff(s(end,:));z],1),2:size(z,1)+1); end + function w=cs2(s,z), w=col(cumsum([ff(s(:,end)),z],2),2:size(z,2)+1); end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/limit.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,29 @@ +% limit - Get the limit of an infinite sequence if it exists +% +% limit :: +% (A,A->nonneg) ~ 'metric', +% seq(A), ~ 'sequence of converging values', +% options { +% maxit :: natural/10e6 ~ 'maximum iterations'; +% tol :: nonneg/1e-5 ~ 'convergence tolerance' +% } +% -> A, natural. + +function [y,its]=limit(d,X,varargin) + opts=prefs('maxit',10e6,'tol',1e-5,varargin{:}); + + tol=opts.tol; + S.x=head(X); + S.X=next(X); + S.f=false; + S.its=0; + S=iterate(@converger,S,'its',opts.maxit); + y=S.x; + its=S.its; + + function S=converger(S) + [xx,S.X]=decons(S.X); + S.its=S.its+1; + if d(S.x,xx)<tol, S=[]; else S.x=xx; end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/max.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,9 @@ +function o=max(A,B,DIM), + if nargin==2 && ~isempty(B), o=binfun(A,B,@max,@(a,b)sprintf('max(%s,%s)',a,b)); + else + if nargin<3, o=fnseq(@max,A); + else o=fnseq(@(x)max(x,[],DIM),A); + end + end +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/mean.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,6 @@ + function o=mean(A,DIM), + if nargin<2, o=fnseq(@mean,A); + else o=fnseq(@(x)mean(x,DIM),A); + end + end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/meandata.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,80 @@ +function m=meandata(x,dim,varargin) +% MEANDATA - Mean of a sequence of arrays +% +% meandata :: +% seq [D] ~ sequence of E dimensional arrays of size D, ie D::[[E]] +% I:[[N]->[E]] ~ array of dimension numbers (between 1 and E) to do mean over +% options { +% check_nans :: {0,1}/0 ~'whether to check for (and ignore) nans' +% } +% -> [R] ~ array of size R, where R=set(D,I,1). +% +% if X is a sequence of 5 x 12 x 50 arrays, then +% M=meandata(X,[1,3]) +% returns a 1 x 12 array. +% +% Options: See ITERATE for applicable options + + opts=prefs('check_nans',0,varargin{:}); + + S.total=0; + S.count=0; + + if opts.check_nans, % world of pain + if isempty(dim) + S=foldl(@mean0_nan_st,S,x,varargin{:}); + elseif isscalar(dim) + S=foldl(@mean_nan_st,S,x,varargin{:}); + else + S=foldl(@meandims_nan_st,S,x,varargin{:}); + end + m=S.total./S.count; + else + if isempty(dim) + S=foldl(@mean0_st,S,x,varargin{:}); + elseif isscalar(dim) + S=foldl(@mean_st,S,x,varargin{:}); + else + S=foldl(@meandims_st,S,x,varargin{:}); + end + m=S.total/S.count; + end + + + % non-nan checking accumulators + function S=meandims_st(S,X) + S.total=S.total+sumdims(X,dim); + S.count=S.count+prod(sizedims(X,dim)); + end + + function S=mean_st(S,X) + S.total=S.total+sum(X,dim); + S.count=S.count+size(X,dim); + end + + function S=mean0_st(S,X) + S.total=S.total+X; + S.count=S.count+1; + end + + % nan checking accumulators + function S=meandims_nan_st(S,X) + I=isnan(X); X(I)=0; + S.total=S.total+sumdims(X,dim); + S.count=S.count+sumdims(~I,dim); + end + + function S=mean_nan_st(S,X) + I=isnan(X); X(I)=0; + S.total=S.total+sum(X,dim); + S.count=S.count+sum(~I,dim); + end + + function S=mean0_nan_st(S,X) + I=isnan(X); X(I)=0; + S.total=S.total+X; + S.count=S.count+(~I); + end +end + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/min.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,11 @@ + +% min - min mapped over sequence (ie NOT aggregate) +function o=min(A,B,DIM), + if nargin==2 && ~isempty(B), o=binfun(A,B,@min@(a,b),sprintf('max(%s,%s)',a,b)); + else + if nargin<3, o=fnseq(@min,A); + else o=fnseq(@(x)min(x,[],DIM),A); + end + end +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/minmax.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,10 @@ + +% minmax - minmax for sequences operates over ENTIRE sequence +% +% minmax :: [D:[[1,E]]], I:[E] -> [set(D,I,2)]. +% +% If you want minmax on a per-buffer basis, use fnseq: +% R=fnseq(@(x)minmax(x,dim),X) +function R=minmax(X,dim) + R=foldl(@(r,t)minmax(cat(dim,r,t),dim),[],X); +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/seq.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,332 @@ +% seq - Base class for sequences +classdef seq + methods (Abstract) + x=head(a) % seq(A) -> A. + b=next(a) % seq(A) -> seq(A). + s=elsize(a) % seq([E->T]) -> E:[[1,D]]. + s=tostring(a) % seq(A) -> string. + end + + methods (Sealed=true) + function varargout=size(a,n) + s=elsize(a); + if nargin>1, varargout={s(n)}; + elseif nargout<=1, varargout={s}; + else + varargout=[num2cell(s(1:nargout-1)),{prod(s(nargout:end))}]; + end + if any(isnan(cell2mat(varargout))) + error('seq:Element size indeterminate'); + end + end + + function l=length(a,n), l=max(size(a)); end + function n=numel(a, varargin), n=prod(size(a)); end + function n=end(a,k,m) + if m==length(elsize(a)), n=size(a,k); + else n=prod(size(a)); end + end + + function display(o) + display(sprintf(' %s :: seq([[%s]])\n', tostring(o), ... + cat_sep(',',cellmap(@fmt_dim,num2cell(elsize(o)))))); + function s=fmt_dim(x), if isnan(x), s='_'; else s=num2str(x); end; end + end + + function y=subsref(a,S) + switch S(1).type + case '()', y=paren(a,S(1)); + case '.', fn=S(1).subs; y=map(@(z)getfield(z,fn),a); + end + if length(S)>1, y=subsref(y,S(2:end)); end + end + end + + methods + % decons - head and tail of sequence + % decons :: seq(A) -> A, seq(A). + function [x,b]=decons(a) + x=head(a); + b=next(a); + end + + % last - get the last array in a sequence (there must be at least one element) + % + % last :: seq(A) -> A. + function z=last(y) + while ~isempty(y), x=y; y=next(x); end + z=head(x); + end + + function f=headfn(o), f=@()head(o); end + + + % ------------- WRAPPERS FOR OTHER SEQ CLASSES --------------------------- + function y=take(n,x), y=seq.take(n,x); end + function y=takewhile(f,x), y=seq.takewhile(f,x); end + + % drop - Drop the first n alements of sequence + % + % drop :: natural, seq A -> seq A + function s=drop(n,s), for i=1:n, s=next(s); end; end + + % dropwhile - Drop elements of sequence that satisfy condition + % + % drop :: (A->bool), seq A -> seq A + function s=dropwhile(f,s) + while ~isempty(s) && f(head(s)), s=next(s); end + end + + % nth1 - Get nth element of a sequence starting at 1 + % + % nth1 :: natural, seq X -> X, seq X ~'tail of sequence'. + function [x,tail]=nth1(n,X) + z=drop(n-1,X); + x=head(z); + if nargout>=2, tail=next(z); end + end + + % once - equivalent to take(1,...) + % + % once :: seq A -> seq A. + function Y=once(X), Y=cons(head(X),[]); end + + function x=map(fn,e,varargin), x=seq.map(fn,e,varargin{:}); end + function x=mapaccum(fn,s0,y), x=seq.mapaccum(fn,s0,y); end + function x=select(fn,y), x=seq.select(fn,y); end + function y=cache(x), y=seq.cache(x); end + function y=buffer(x,varargin), y=seq.buffer(x,varargin{:}); end + + % scanl - scanl combinator for sequences + % + % This function applies an associative operator to a list of arguments, + % starting from the left using the given starting element. + % + % scanl :: + % (X,Y->X) ~'associative binary operator', + % X ~'initial element', + % seq Y ~'a sequence' + % -> seq X. + function x=scanl(fn,e,y,varargin), x=seq.scanl(fn,e,y,varargin{:}); end + + % concat - Concatenate sequences + % + % concat :: + % seq(seq(A)) ~ 'sequence of sequences' + % -> seq(A) ~ 'resultant sequence'. + % + % concat :: + % {[N]->seq(A)} ~ 'cell array of N sequences', + % -> seq(A) ~ 'resultant sequence'. + function y=concat(x), y=seq.concat(x); end + + % append - Append one or more sequences + % + % append :: seq(A), seq(A), ... -> seq(A). + function x=append(varargin), x=seq.concat(cellseq(varargin)); end + + function z=and(x,y), z=seq.concat(cons(x,cons(y,[]))); end + + % cycle - cycles through input sequence repeatedly + % + % cycle :: seq(A) -> seq(A). + function y=cycle(x), y=seq.cycle(x); end + + function y=bindcat(x,f), y=seq.bindcat(x,f); end + % bindcat :: seq(A), (A->seq(A)) -> seq(A). + + function y=subsample(n,x), y=seq.subsample(n,x); end + + function x=zip(varargin) + % zip - combine several sequences into one + % + % zip :: seq(A), seq(B), ... -> seq(cell {A,B,...}). + x=seq.zipwith(@tuple,varargin); + function z=rtuple(varargin), z=varargin; end + end + + % zipwith - apply function to several sequences + % + % zipwith :: + % (A,B,...->X), + % seq A, seq B, ... + % -> seq X. + function x=zipwith(fn,varargin), x=seq.zipwith(fn,varargin); end + + % zipaccum - apply stateful function to several sequences + % + % zipaccum :: + % (A,B,...,S->X,S), + % S, + % seq(A), seq(B), ... + % -> seq(X). + function x=zipaccum(fn,s0,varargin), x=seq.zipaccum(fn,s0,varargin); end + + function xx=unzip(y) + % unzip - Separate sequence of tuples into several sequences + % + % unzip :: + % seq({I:[D]->A(I)}). + % -> {I:[D]->seq(A(I))}. + % + % Note: input MUST be a sequence of constant size cell arrays. + % Output is a cell array of sequences of the same size and shape. + + xx=cell(size(y)); + for i=1:numel(xx) + xx{i}=map(@(a)a{i},y); + end + end + + function y=merge(f,varargin), y=seq.merge(f,varargin); end + + + % ------------------ MAPPERS ------------------------------------ + + % BINOP - Binary operation + % + % binop :: seq A, seq B, (A,B->C), string -> seq C. + % + % Three cases + % A is seq, B is an array + % A is array, B is seq + function o=binop(A,B,fn,opstr) + o=binfun(A,B,fn,@(a,b)sprintf('(%s%s%s)',a,b,opstr)); + end + + function o=binfun(A,B,fn,fmtstr) + if isseq(A), + if isseq(B), o=zipwith(fn,A,B); %@(o)fmtstr(tostring(A),tostring(B))); + else + o=map(@(x)fn(x,B),A); %@(o)fmtstr('.',tostring(B))); + end + else + o=map(@(y)fn(A,y),B); %,@(o)fmtstr(tostring(A),'.')); + end + end + + % vecop - apply binary function to different sized array sequences + % + % vecop :: + % ([[D]],[[D]]->[[D]]) ~'some function requiring equal size args', + % seq [[DX]] ~'first arg of size DX', + % seq [[DY]] ~'second arg of size DY' + % -> seq [[DZ]] ~'result of size DZ' :- DZ=max(DX,DY). + % + % The input sequences must maintain the same size throughout. + function Z=vecop(F,X,Y) + DX=size(X); DY=size(Y); + E=max(length(DX),length(DY)); + EDX=pad1s(E,DX); + EDY=pad1s(E,DY); + if all(EDX>=EDY) + S=EDX./EDY; + Z=binop(X,Y,@(x,y)F(x,repmat(y,S)),['<' tostring(F) '>']); + elseif all(EDY>=EDX) + S=EDY./EDX; + Z=binop(X,Y,@(x,y)F(repmat(x,S),y),['<' tostring(F) '>']); + else + DZ=max(EDX,EDY); + Z=binop(X,Y,@(x,y)F(repmat(x,DZ./EDX),repmat(y,DZ./EDY)),['<' tostring(F) '>']); + end + end + + + function h=plot(A,varargin), h=plotseq(@(x)plot(x,varargin{:}),A); end + function h=imagesc(A,varargin), h=plotseq(@(x)imagesc(x,varargin{:}),A); end + + function o=isfinite(A), o=map(@isfinite, A); end + function o=isinf(A), o=map(@isinf, A); end + function o=isnan(A), o=map(@isnan, A); end + function y=powspec(x), y=map(@powspec,x); end + function y=magspec(x), y=map(@magspec,x); end + function y=phasespec(x), y=map(@phasespec,x); end + function o=uminus(A), o=map(@uminus, A); end + function y=exp(x), y=map(@exp,x); end + function y=cos(x), y=map(@cos,x); end + function y=sin(x), y=map(@sin,x); end + function y=abs(x), y=map(@abs,x); end + function y=sqrt(x), y=map(@sqrt,x); end + function y=tanh(x), y=map(@tanh,x); end + function y=log(x), y=map(@log,x); end + function y=log10(x), y=map(@log10,x); end + function y=log2(x), y=map(@log2,x); end + function o=ctranspse(A), o=map(@ctranspose,A); end + function o=transpse(A), o=map(@transpose,A); end + function y=fft(x), y=map(@fft,x); end + function y=ifft(x), y=map(@ifft,x); end + + function o=reshape(source,varargin) + % reshape - Map reshape over elements of sequence + % + % reshape :: seq [Size->A], ... - > seq [Size1->A]. + % Works exactly like the usual reshape function but when applied + % to a sequence object, returns a new sequence. + + sz=tosize(varargin{:}); + o=map(@(x)reshape(x,varargin{:}),source); + + function s=charfn(sz,o) + s=sprintf('%s >> reshape[%s]',tostring(source(o)),tostring(sz)); + end + end + + function y=paren(a,S) + % paren - Map application of subsref with parentheses to sequence + % + % paren :: seq A, subs -> seq B :- (subsref :: A, subs -> B). + + % NOTE TO SELF: it would be good to work out the size of the + % array that will result when the function is evaluated, to + % save map evaluating it once on construction. + y=map(@(z)subsref(z,S),a); % 'charfn',@(o)charfn(tostring(S.subs{:}),o)); + + function s=charfn(argstr,o) + s=sprintf('%s >> (%s)',tostring(source(o)),argstr); + end + end + + function o=plus(A,B), o=binop(A,B,@plus,'+'); end + function o=power(A,B), o=binop(A,B,@power,'.^'); end + function o=eq(A,B), o=binop(A,B,@eq,'=='); end + function o=ge(A,B), o=binop(A,B,@ge,'>='); end + function o=gt(A,B), o=binop(A,B,@gt,'>'); end + function o=ldivide(A,B), o=binop(A,B,@ldivide,'.\'); end + function o=le(A,B), o=binop(A,B,@le,'<='); end + function o=lt(A,B), o=binop(A,B,@lt,'<'); end + function o=times(A,B), o=binop(A,B,@times,'.*'); end + function o=minus(A,B), o=binop(A,B,@minus,'-'); end + function o=mldivide(A,B),o=binop(A,B,@mldivide,'\'); end + function o=mod(A,B), o=binop(A,B,@mod,'mod'); end + function o=mrdivide(A,B),o=binop(A,B,@mrdivide,'/'); end + function o=rdivide(A,B), o=binop(A,B,@rdivide,'./'); end + function o=mtimes(A,B), o=binop(A,B,@mtimes,'*'); end + + + % max - max mapped over sequence (ie NOT aggregate) + function o=cat(dim,varargin) + if length(varargin)==2 + o=binfun(varargin{1},varargin{2},@(a,b)cat(dim,a,b),@(a,b)sprintf('cat(%d,%s,%s)',dim,a,b)); + else + o=zipwith(@catdim,varargin{:}); + end + function x=catdim(varargin), x=cat(dim,varargin); end + end + + function o=vertcat(varargin) + if length(varargin)==2 + o=binfun(varargin{1},varargin{2},@vertcat,@(a,b)sprintf('[%s;%s]',a,b)); + else + o=zipwith(@vertcat,varargin{:}); + end + end + + function o=horzcat(varargin) + if length(varargin)==2 + o=binfun(varargin{1},varargin{2},@horzcat,@(a,b)sprintf('[%s,%s]',a,b)); + else + o=zipwith(@horzcat,varargin{:}); + end + end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/span.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,9 @@ +function [h,x]=span(f,x) +% span - divide sequence using a test function +% +% span :: (A->bool), seq(A) -> seq(A), seq(A). +% +% span(f,x) = takeWhile(f,x), dropWhile(f,x) +% Will not terminate if head segments turns out to be infinite. +[Y,x]=spanc(f,x); +h=cellseq(Y);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/spanc.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,22 @@ +function [Y,x]=spanc(f,x) +% spanc - divide sequence using a test function +% +% spanc :: (A->bool), seq(A) -> {[N]->A}, seq(A). +% +% spanc f x = (seq2cell (takeWhile f x),dropWhile f x) +% Will not terminate if head segments turns out to be infinite. +% +% Note: this is like span but returns a cell array for the head sequence + +if isempty(x), Y={}; return +else + Y={}; + y=head(x); + while f(y) + Y=horzcat(Y,y); + x=next(x); + if isempty(x), break; end + y=head(x); + end +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/split.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,10 @@ +function [h,t]=split(n,s) +% split - split sequence into initial and trailing segments +% +% split :: N:natural, seq(A) -> seq(A), seq(A) + +h=take(n,s); +t=drop(n,s); + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/split_gather.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,12 @@ +function [h,t]=split(dim,n,s) +% split - gather first n elements and return with rest of sequence +% +% split :: D:natural, N:natural, seq A -> [[N]->A], seq A + +% !! prevent array growth +h=[]; +for i=1:n, x=head(s); h=cat(dim,h,x); s=next(s); end +t=s; + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/sum.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,6 @@ + function o=sum(A,DIM), + if nargin<2, o=fnseq(@sum,A); + else o=fnseq(@(x)sum(x,DIM),A); + end + end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/unbuffer.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,36 @@ +% unbuffer - Opposite of buffer using overlap and add (for sequences) +% +% unbuffer :: +% seq([[N]]) ~'sequence of overlapping frames', +% M:natural ~'hop size' +% -> seq([[1,M]])~'sequence of de-overlapped frames'. +% +% NB. what about windowing function? + +function Y=unbuffer(X,hop) + if isscalar(hop) + N=max(size(X)); + ol=N-hop; + if ol<=hop + I=1:hop; J=1:ol; K=hop+1:N; + Y=mapaccum(@olap1,X,zeros(ol,1)); + else + I=1:hop; J=hop+1:ol; K=ol+1:N; + Y=mapaccum(@olap3,X,zeros(ol,1)); + end + else + Y=zipaccum(@olap2,{windowdata(repeat(hop)),X},[]); + end + + function [y,s1]=olap1(x,s) + y=x(I)'; + y(J)=y(J)+s'; + s1=x(K); + end + + function [y,s1]=olap3(x,s) + y=(s(I)+x(I))'; + s1=[s(J)+x(J);x(K)]; + end +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/window.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,12 @@ +% window - Window a sequnce of arrays in a given dimension +% +% window :: seq [[N,M]] -> seq [[N]]. +% window :: seq [[N,M]], L:natural -> seq [[N,L]]. +% window :: seq [[N,M]], L:natural, natural ~'hop size' -> seq [[N,L]]. +% +% This is just short for windowdata(...) +% Possible optimisation: +% when the span and hop are much less than the input buffer size +% and the source data does not have an efficient extract method, +% then it is worth caching the source data, ie window(cache(x),...) +function Y=window(X,varargin), Y=seq.window(X,varargin{:});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/@seq/window_ns.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,12 @@ +function Y=window_ns(X,W,H), +% window_ns - Window a sequnce of arrays in a given dimension (no strict size) +% +% window_ns :: seq [[N,M]] -> seq [[N]]. +% window_ns :: seq [[N,M]], L:natural -> seq [[N,L]]. +% window_ns :: seq [[N,M]], L:natural, natural ~'hop size' -> seq [[N,L]]. + +if nargin<2, W=1; H=1; +elseif nargin<3, H=W; +end + +Y=seq.window(X,W,H,'strict',0);
--- a/sequences/README Sat Dec 22 16:17:51 2012 +0000 +++ b/sequences/README Wed Jan 09 22:22:21 2013 +0000 @@ -1,28 +1,13 @@ -DATA CLASSES +SEQUENCE CLASSES -These class manage a variety of virtualised data sources. A data -object here is thought of as a lazy list or sequence of arrays, +These class manage a variety of sequence construction methods. A sequence +object here is thought of as a lazy list or sequence of values, where subsequent elements of the sequence are created only when -necessary. For example, an audio file can be read block by block -without loading the whole thing. +necessary. +These are mostly inspired by the Haskell list processing library -SRC_ FUNCTIONS - -The src_ functions can handle data in the form of a cell array -of arrays, a data sequence object (see saml-1.0/data) or a -big array with an array of subranges. They are a simpler way of -providing some of the functionally of the data objects to -functions that need data but don't care where it comes from. - -The point of these is to decouple algorithms that just want to -read data from all the heavy Matlab classes in saml-1.0/data, -which are useful for constructing and manipulating data -sources, but are not necessary for simple batch data applications. -This way, the code can be extracted from the library without -having to bring along all the data classes. - HASKELL LIST FUNCTIONS @@ -41,7 +26,7 @@ scanl :: (a->b->a) -> a -> [b] -> [a] scanl1 :: (a->a->a) -> [a] -> [a] mapAccumL :: (a->b->(a,c)) -> a -> [b] -> (a,[c]) -unfold :: (b->maybe(a,b)) -> b -> [a] +unfoldseq :: (b->maybe(a,b)) -> b -> [a] zipWith :: (a->b->c) -> [a] -> [b] -> [c] iterate :: (a->a) -> a -> [a] repeat :: a -> [a] @@ -84,85 +69,106 @@ fromTo x y = takeWhile (<=y) (from x) -My classes +MY CLASSES -data -ddata -bindcat -concat -rnddata -subseqdata + The base class defining the interface is seq + seq abstract methods + next head tostring elsize -arraydata = repeat -fndata = map -iterdate = iterate -loop = cycle -concat -take = take -scandata = scanl -sfndata = mapAccumL -zipdata = zip -cachedata -celldata + The implementations are in the +seq package directory: -wavelist = concatMap wavedata OR cycle . concatMap wavedata -bufferdata - (sort of (cons (gather (take n x)) (buffer n (drop n))) + bindcat cons map scanl subsample unfold_inf + buffer cycle mapaccum select take windowdata + cache iterate merge skin takewhile zipaccum + concat lcons repeat slices unfold zipwith -windowdata = concatScanl window1 (sort of) -extractdata +METHODS THAT RETURN SEQUENCES -My functions + Basic list combinators -once = take 1 -drop = drop -repeat = loop . (take 1) -folddata = foldl -meandata = foldl accum init -scandatacols f = scanl (y\scancols f (last y)) -squirt f x = buffer (f (window x 1 1)) (size x 2) -expdata = -lindata = + take drop dropwhile + map zip zipwith + mapaccum zipaccum scanl + and concat append + select merge cycle + span spanc split + cache once split_gather + diffwith bindcat + buffer unbuffer -gather dim = foldl (cat dim) [] -seq2cell = foldl \x\y[x {y}] {} + Stateful processors (scanl, mapaccum, zipaccum) + cumsum minmax integrate filter dynfilter + + Lifting ordinary functions and operators with maps and zips: -TO RESOLVE + le minus rdivide times mtimes + ctranspose power uminus paren gt + ldivide transpose mrdivide eq plus + lt mldivide ge subsref + vertcat horzcat cat - optimisation of constructors: - data, ddata, fndata, sfndata - !lindata by start and increment? - !rate conversion, interpolation - !continuous spectral synthesis with phase adjustment + binfun vecop binop unzip + isinf isnan isfinite + tanh cos mod sin + log10 log log2 exp + reshape sqrt abs + min max mean sum + powspec magspec phasespec fft ifft - !the extract method belongs in a DIFFERENT type class: we need a class - of virtual arrays. This is essentially a function which: - (a) has a domain of tuples of natural numbers - (b) knows what its domain (size) is - (c) can be applied to arrays of values and maps over them -Possible renamings: - scandata -> scanl (overloaded) - folddata -> foldl (ditto) - cachedata -> cache (actually just a strict head) - iterdata -> ? (class with iterate) - zipdata -> zip or zipWith - sfndata -> mapaccum - new zipaccum? - fndata -> map - extractdata -> ? - meandata? +METHODS THAT DO NOT RETURN SEQUENCES - tricky:` - windowdata - bufferdata - framedata + decons gather gathern length + limit display headfn size + nth1 numel imagesc + plot foldl last foreach + seq2cell meandata - phasedata, spectraldata - gather vs seq2cell - + +SEQUENCE CREATING FUNCTIONS + + cellseq - Convert cell array directly to sequence + framedata - return abstract data object for buffering signal frames + lazy_cons - Make sequence given head and tail + singleton - infinite sequence repeating one value + naturals - Sequence of natural numbers starting at 0 + integers - Sequence of integers + + rndscanl - Random scanl + rndseq - Sequence of values sampled from a random variable model + rndwindow - get random windows of a signal + rndzip - Random sequence by zipping argument sequences + rndzipaccum - Random sequence by zipping argument sequences with state + + scanseqcols - scandatacols - Scan over columns of array sequence + subseqdata - Sequence of subranges of a large array + + window - Window a sequnce of arrays in a given dimension + window_ns - Window a sequnce of arrays in a given dimension (no strict size) + windowparams - compute windowing parameters to get buffers of a certain size + + expdata - exponential data sequence + lindata - linear data sequence + + +SPECIFICATIONS + + (Some Haskellish stuff) + + once = take 1 + drop = drop + repeat = loop . (take 1) + foldseq = foldl + meandata = foldl accum init + scandatacols f = scanl (y\scancols f (last y)) + gather dim = foldl (cat dim) [] + seq2cell = foldl \x\y[x {y}] {} = gather . map box where box x = {x} + buffer x n dim = cons (gather dim (take n x)) (buffer (drop n x) n dim ); + windowdata = concatScanl window1 (sort of) ?? + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/cellseq.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,7 @@ +% cellseq - Convert cell array directly to sequence +% +% cellseq :: {[L]->A} -> seq(A). +function o=cellseq(elems) + n=length(elems); + o=map(@(i)elems{i},integers(1,length(elems))); +end
--- a/sequences/cons.m Sat Dec 22 16:17:51 2012 +0000 +++ b/sequences/cons.m Wed Jan 09 22:22:21 2013 +0000 @@ -1,8 +1,1 @@ -function Y=cons(X,Z) -% cons - Make sequence given head and tail -% -% cons :: A, seq A -> seq A. - -Y=data(size(X),'datafn',@(o)X,'nextfn',@(o)Z, ... - 'charfn',@(o)[tostring(X) ' | (' tostring(Z) ')']); - +function y=cons(H,T), y=seq.cons(H,T); end
--- a/sequences/expdata.m Sat Dec 22 16:17:51 2012 +0000 +++ b/sequences/expdata.m Wed Jan 09 22:22:21 2013 +0000 @@ -8,23 +8,21 @@ % M:natural ~'buffer size' % -> seq [[1,M]]. -if nargin<4, M=1; end + if nargin<4, M=1; end -lA=log(A); -k=(log(B)-lA)/N; -y=unfold(@ls1,0:M-1); -%y=windowdata(linspace(A,B,N),M,M); + lA=log(A); + k=(log(B)-lA)/N; + y=unfoldseq(@ls1,0:M-1); -function [X,I]=ls1(I), - surp=I(end)-N; - if surp>=0, - X=exp(lA+k*I(1:end-surp)); - if surp<M, X(end)=B; end - else - X=exp(lA+k*I); + function [X,I]=ls1(I), + surp=I(end)-N; + if surp>=0, + X=exp(lA+k*I(1:end-surp)); + if surp<M, X(end)=B; end + else + X=exp(lA+k*I); + end + I=I+M; end - I=I+M; -end - end
--- a/sequences/framedata.m Sat Dec 22 16:17:51 2012 +0000 +++ b/sequences/framedata.m Wed Jan 09 22:22:21 2013 +0000 @@ -1,13 +1,12 @@ -function a=framedata(signal,frame,hop,width,varargin) -% FRAMEDATA - return abstract data object for buffering signal frames +% framedata - return abstract data object for buffering signal frames % % framedata :: -% ( s:data[C,T] ~'C-channel signal of length T', +% ( s:seq [C,T] ~'C-channel signal of length T', % N:natural ~'frame size', % M:natural ~'hop size', % L:natural ~'frames per buffer' | ([] => whole file) % options... ) -% -> data[N,L]. +% -> seq [N,L]. % % Options: % wrap/0 if 1, then buffer samples as if one continuous circular signal @@ -15,15 +14,13 @@ % random/0: if [], return buffers sequentially, if number or random state % vector, return buffers in random order, using value as seed. % filter/[] optional filter function to apply to long windows before buffering -% jump/J number of samples to skip per large buffer. Default is calculated -% to produce seamless buffering with chosen width and hop. % % Note: if the signal is a multichannel signal, ie of size CxT with C>1, % the samples for each channel are interleaved. - +function a=framedata(signal,frame,hop,width,varargin) if nargin<4, width = []; end - opts=prefs('wrap',0,'random',[],'dim',2,varargin{:}); + opts=prefs('wrap',0,'random',[],'dim',2,'filter',@id,varargin{:}); if isempty(width), opts.truncate=0; end [span,jump]=windowparams(size(signal),frame,hop,width,opts); @@ -33,12 +30,15 @@ wd=rndwindow(signal,span,opts.dim); end - if isfield(opts,'filter'), wd=opts.filter(wd); end - if size(wd,1)>1, wd=flatten(wd); end - if hop<frame, args={'nodelay'}; else args={}; end + wd=opts.filter(wd); + if size(wd,1)>1, wd=map(@flatten,wd); end + olap=frame-hop; + if hop<frame, buffn=@(x)buffer(x,frame,olap,'nodelay'); + else buffn=@(x)buffer(x,frame,olap); + end % NB: makes sense to cache large windows to save repeated calls % extract current large window from data source while processing % the buffered window. - a=buffer(cache(wd),frame,frame-hop,args{:}); - + a=map(buffn,cache(wd)); +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/integers.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,7 @@ +% integers - Sequence of integers +% +% integers :: int, int -> seq(int). +function N=integers(a,b) + N=skinseq(iterseq(@succ,a),@(o)sprintf('<%d..%d>',head(o),b)); + function n=succ(n), if n<b, n=n+1; else n=[]; end; end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/isseq.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,1 @@ +function f=isseq(d), f=isa(d,'seq');
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/iterseq.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,1 @@ +function y=iterseq(varargin), y=seq.iterate(varargin{:});
--- a/sequences/lazy_cons.m Sat Dec 22 16:17:51 2012 +0000 +++ b/sequences/lazy_cons.m Wed Jan 09 22:22:21 2013 +0000 @@ -1,8 +1,5 @@ -function Y=lazy_cons(X,Z) % lazy_cons - Make sequence given head and tail % -% lazy_cons :: A, (unit -> seq A) -> seq A. +% lazy_cons :: A, (void -> seq(A)) -> seq(A). +function Y=lazy_cons(X,Z), Y=seq.lcons(X,Z); end -Y=data(size(X),'datafn',@(o)X,'nextfn',@(o)Z(), ... - 'charfn',@(o)[tostring(X) ' | ' tostring(Z) '()']); -
--- a/sequences/lindata.m Sat Dec 22 16:17:51 2012 +0000 +++ b/sequences/lindata.m Wed Jan 09 22:22:21 2013 +0000 @@ -8,21 +8,19 @@ % M:natural ~'buffer size' % -> seq [[1,M]]. -if nargin<4, M=1; end -k=(B-A)/N; -y=unfold(@ls1,0:M-1); -%y=windowdata(linspace(A,B,N),M,M); + if nargin<4, M=1; end + k=(B-A)/N; + y=unfoldseq(@ls1,0:M-1); -function [X,I]=ls1(I), - surp=I(end)-N; - if surp>=0, - X=A+k*I(1:end-surp); - if surp<M, X(end)=B; end - else - X=A+k*I; + function [X,I]=ls1(I), + surp=I(end)-N; + if surp>=0, + X=A+k*I(1:end-surp); + if surp<M, X(end)=B; end + else + X=A+k*I; + end + I=I+M; end - I=I+M; -end - end
--- a/sequences/naturals.m Sat Dec 22 16:17:51 2012 +0000 +++ b/sequences/naturals.m Wed Jan 09 22:22:21 2013 +0000 @@ -1,4 +1,4 @@ -function N=naturals, N=iterdata(@(n)n+1,0,'charfn',@(o)sprintf('%d..',head(o))); % naturals - Sequence of natural numbers starting at 0 % % natural :: seq natural. +function N=naturals, N=skinseq(iterseq(@(n)n+1,0),@(o)sprintf('<%d..>',head(o)));
--- a/sequences/repeat.m Sat Dec 22 16:17:51 2012 +0000 +++ b/sequences/repeat.m Wed Jan 09 22:22:21 2013 +0000 @@ -1,7 +1,1 @@ -function Y=repeat(X) -% repeat - Make infinite sequence of the same given element -% -% repeat :: A -> seq A. - -Y=data(size(X),'datafn',@(o)X,'nextfn',@id,'charfn',@(o)[tostring(X) '>> repeat']); - +function z=repeat(x), z=seq.repeat(x); end
--- a/sequences/rndscanl.m Sat Dec 22 16:17:51 2012 +0000 +++ b/sequences/rndscanl.m Wed Jan 09 22:22:21 2013 +0000 @@ -11,11 +11,11 @@ n=length(varargin)-1; rs0=varargin{n+1}; if n>1, - X=zipaccum(@zafn,{s0,rs0},varargin(1:n)); + X=zipaccum(@zafn,varargin(1:n),{s0,rs0}); elseif n==1 - X=mapaccum(@mafn,{s0,rs0},varargin{1}); + X=mapaccum(@mafn,varargin{1},{s0,rs0}); else - X=unfold(@ufn,{s0,rs0}); + X=unfoldseq(@ufn,{s0,rs0}); end function [x,s]=ufn(s0)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/rndseq.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,54 @@ +% rndseq - Sequence of values sampled from a random variable model +% +% rndseq :: +% model xdom:[[1,XD]] ~ random variable model, data size is xdom, +% sdom:[[1,SD]], ~ size of sample, +% -> seq([[xdom sdom]]) ~ size of rndseq is product of xdom and sdom +% +% rndseq :: +% model xdom:[[1,XD]] ~ random variable model, data size is xdom, +% sdom:[[1,SD]], ~ size of sample, +% rndstate ~ initial state of generators +% -> rndseq([[xdom sdom]]) ~ size of rndseq is product of xdom and sdom +% +% If an initial rndstate is supplied, rndseq is purely functional +% and referentially transparent. Otherwise, the initial construction +% uses the current state of the random generators. After this, the +% entire sequence is fully determined. +% +% EXAMPLE +% +% rndseq(gaussian,[2,200]) :: seq [[2,200]] +% rndseq(dirichlet(3,0.5),6) :: seq [[3,6]] +function d=rndseq(model,sdom,k) + if nargin<2, sdom=1; end + if isa(model,'struct') + if model.nparams>0, + error('Model has unbound parameters'); + end + gen=sampler(model.sample,sdom); + elseif iscell(model) + gen=sampler(model{1},sdom); + end + + if nargin>2, + if ~iscell(k), s={k,k}; else s=k; end + else + s=getrndstate; + end + d=unfoldseq(gen,s); +end + +% this creates a rand-state-managed version of g applied to args, +% ie, +% sampler :: +% ((A1,A2,....) -> random B) ~'an action which generates a value' +% -> (rndstata -> B, rndstate) ~'a deterministic random state transformer'. +function f=sampler(g,varargin) + f=@ufn; + function [x,s]=ufn(s) + setrndstate(s); x=g(varargin{:}); + s=getrndstate; + end +end +
--- a/sequences/rndwindow.m Sat Dec 22 16:17:51 2012 +0000 +++ b/sequences/rndwindow.m Wed Jan 09 22:22:21 2013 +0000 @@ -1,5 +1,5 @@ function Y=rndwindow(X,span,dim,varargin) -% rndwindow - extract random windows of a signal +% rndwindow - get random windows of a signal % % rndwindow :: % [Size:[1,E]] ~'E-dimensional signal array', @@ -17,9 +17,9 @@ if opts.circular, ithresh=len-span+1; - Y=fndata(@exwin_circ,rndzip(@()randnat(len),opts.state),'stringfn',@strfn); + Y=fnseq(@exwin_circ,rndzip(@()randnat(len),opts.state),'stringfn',@strfn); else - Y=fndata(@exwin,rndzip(@()randnat(len-span+1),opts.state),'stringfn',@strfn); + Y=fnseq(@exwin,rndzip(@()randnat(len-span+1),opts.state),'stringfn',@strfn); end function y=exwin(i), y=extract(X,dim,i+ran); end
--- a/sequences/rndzip.m Sat Dec 22 16:17:51 2012 +0000 +++ b/sequences/rndzip.m Wed Jan 09 22:22:21 2013 +0000 @@ -9,9 +9,9 @@ n=length(varargin)-1; if n>0 - X=zipaccum(@zipfn,varargin{n+1},varargin(1:n)); + X=zipaccum(@zipfn,varargin(1:n),varargin{n+1}); else - X=unfold(@ufn,varargin{1}); + X=unfoldseq(@ufn,varargin{1}); end function [x,s]=ufn(s0)
--- a/sequences/rndzipaccum.m Sat Dec 22 16:17:51 2012 +0000 +++ b/sequences/rndzipaccum.m Wed Jan 09 22:22:21 2013 +0000 @@ -10,9 +10,9 @@ n=length(varargin)-1; if n>0 - X=zipaccum(@zafn,{s0,varargin{n+1}},varargin(1:n)); + X=zipaccum(@zafn,varargin(1:n),{s0,varargin{n+1}}); else - X=unfold(@ufn,{s0,varargin{1}}); + X=unfoldseq(@ufn,{s0,varargin{1}}); end function [x,s]=ufn(s0)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/scanseqcols.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,4 @@ +function Y=scandatacols(Fn,Y0,X) +% scandatacols - Scan over columns of array sequence + +Y=scanseq(@(y,x)scancols(Fn,y(:,end),x),Y0,X);
--- a/sequences/seq2cell.m Sat Dec 22 16:17:51 2012 +0000 +++ b/sequences/seq2cell.m Wed Jan 09 22:22:21 2013 +0000 @@ -1,7 +1,7 @@ function Y=seq2cell(X) % seq2cell - gather elements of sequence into a cell array % -% seq2cell :: data A -> {[N]->A}. +% seq2cell :: seq A -> {[N]->A}. Y={}; while ~isempty(X)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/seqbase.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,30 @@ +% seqbase - Base class for sequences +% +% seqbase :: +% Size:[[1,D]], ~ size of item type, +% (seq(A) -> A). +% (seq(A) -> seq(A) | empty), +% (seq(A) -> string) +% -> seq([Size->_]) ~'sequence of things of size Size'. +classdef seqbase < seq + properties (GetAccess=private, SetAccess=immutable) + sz + headfn + nextfn + stringfn + end + methods + function o=seqbase(size,headfn,nextfn,stringfn) + o.sz =size; + o.headfn=headfn; + o.nextfn=nextfn; + o.stringfn=stringfn; + end + + function x=head(a), x=a.headfn(a); end + function b=next(a), b=a.nextfn(a); end + function s=tostring(d), s=d.stringfn(d); end + function s=elsize(a), s=sz; end + end +end +
--- a/sequences/singleton.m Sat Dec 22 16:17:51 2012 +0000 +++ b/sequences/singleton.m Wed Jan 09 22:22:21 2013 +0000 @@ -1,6 +1,4 @@ -function y=singleton(x) -% singleton - Make sequence with exactly one element +% singleton - infinite sequence repeating one value % -% singleton :: A -> seq A. - -y=data(size(x),'datafn',@(o)x,'nextfn',@(o)[],'charfn',@(o)'singleton'); +% singleton :: A -> seq(A). +function s=singleton(x), s=cons(x,[]); end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/skinseq.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,1 @@ +function y=skinseq(varargin), y=seq.skin(varargin{:});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/slices.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,1 @@ +function y=slices(varargin), y=seq.slices(varargin{:}); end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/subsampleseq.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,1 @@ +function y=subsampleseq(n,x), y=seq.subsample(n,x); end
--- a/sequences/subseqdata.m Sat Dec 22 16:17:51 2012 +0000 +++ b/sequences/subseqdata.m Wed Jan 09 22:22:21 2013 +0000 @@ -5,11 +5,7 @@ % [[N,M]] ~ 'big array', % [[2,K]] ~ 'start and end indices' % -> data [[N,M]]. ~ 'resultant sequence'. - - R=windowdata(ranges,1,1); - o=fndata(@(r)extract(X,2,r),R,'sizecheck',1,'charfn',@(o)'subseqdata'); - - function x=getrange(r), x=extract(X,2,r'); end + o=fnseq(@(r)extract(X,2,r),window(ranges),'sizecheck',1); end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sequences/unfoldseq.m Wed Jan 09 22:22:21 2013 +0000 @@ -0,0 +1,1 @@ +function y=unfoldseq(varargin), y=seq.unfold(varargin{:});
--- a/sequences/wavelist.m Sat Dec 22 16:17:51 2012 +0000 +++ b/sequences/wavelist.m Wed Jan 09 22:22:21 2013 +0000 @@ -1,2 +1,2 @@ function o=wavelist(files,varargin) - o=concat(cellmap(@wavedata,files)); + o=cellseq(cellmap(@wavedata,files));
--- a/signals/@signal/signal.m Sat Dec 22 16:17:51 2012 +0000 +++ b/signals/@signal/signal.m Wed Jan 09 22:22:21 2013 +0000 @@ -25,15 +25,17 @@ % } classdef signal - properties (GetAccess=private, SetAccess=immutable) + methods (Abstract) + c=channels(s) + u=construct(s) + r=rate(s) end + methods function s=signal, end function s=and(s1,s2), s=sigcat(s1,s2); end function y=cache(x), y=reclock(rate(x),sigarray(gather(x))); end - function c=channels(s), error('number of channels undefined'); end - function s=construct(sig), error('Cannot construct base signal class'); end function display(a) disp(sprintf(' %s :: signal(%s,%s)',tostring(a),fmt(channels(a)),fmt(rate(a)))); function s=fmt(x), if isnan(x), s='_'; else s=num2str(x); end; end @@ -42,7 +44,6 @@ function y=map(f,x), y=sigmap(f,x); end function s=mpower(a,b), s=resample(b,a); end function s=or(s1,s2), s=sigbinop(@vertcat,s1,s2,@plus); end - function r=rate(s), error('sampling rate undefined'); end function s2=reclock(r,s1), s2=sigreclock(r,s1); end function y=drop(n,x), y=sigdrop(n,x); end function y=take(n,x), y=sigtake(n,x); end
--- a/signals/sigrep.m Sat Dec 22 16:17:51 2012 +0000 +++ b/signals/sigrep.m Wed Jan 09 22:22:21 2013 +0000 @@ -1,3 +1,5 @@ +% sigrep - Signal of repeated values +% sigrep :: natural, A:[[C,1]] -> signal(C,_). function s=sigrep(n,x) %s=sigarray(repmat(x,1,n)); s=take(n,sigconst(x));
--- a/sinks/@sinkarray/sinkarray.m Sat Dec 22 16:17:51 2012 +0000 +++ b/sinks/@sinkarray/sinkarray.m Wed Jan 09 22:22:21 2013 +0000 @@ -7,30 +7,24 @@ % R:nonneg ~'sampling rate' % -> sink(C,R). -classdef sinkarray < sink +classdef sinkarray < sinkbase properties (GetAccess=private,SetAccess=immutable) - chans % natural length % natural - fs % nonneg cont % [[C,N]] -> void end methods function s=sinkarray(cont,ch,len,rate) if nargin<4, rate=nan; end - s.chans=ch; s.length=len; - s.fs=rate; s.cont=cont; + s=s@sinkbase(ch,rate); end function s=tostring(sig), - s=sprintf('sinkarray(%s,<%dx%d>)',tostring(sig.cont),sig.chans,sig.length); + s=sprintf('sinkarray(%s,<%dx%d>)',tostring(sig.cont),channels(sig),sig.length); end - function c=channels(s), c=s.chans; end - function c=rate(s), c=s.fs; end function s=construct(sig) - length=sig.length; ch=channels(sig); array=zeros(ch,length);
--- a/sinks/@sinkcat/sinkcat.m Sat Dec 22 16:17:51 2012 +0000 +++ b/sinks/@sinkcat/sinkcat.m Wed Jan 09 22:22:21 2013 +0000 @@ -4,11 +4,9 @@ % % The resulting sink writes to S1 until it reports full,then % to S2, then S3 and so on, until the last one, then it reports full. -classdef sinkcat < sink +classdef sinkcat < sinkbase properties (GetAccess=private,SetAccess=immutable) sinks % {[M]->sink(C,R)} - chans % natural - fs % nonneg end methods function s=sinkcat(varargin) @@ -18,8 +16,7 @@ ch=foldl(@unify_channels,nan,map(@channels,varargin)); if isinf(ch), error('channel count mismatch'); end s.sinks=varargin; - s.fs=fs; - s.chans=ch; + s=s@sinkbase(ch,fs); end function s=tostring(sig) @@ -30,8 +27,5 @@ else s=sprintf('sinkcat(%s,...)',strx{1}); end end - - function c=rate(s), c=s.fs; end - function c=channels(s), c=s.chans; end end end
--- a/sinks/@sinkempty/sinkempty.m Sat Dec 22 16:17:51 2012 +0000 +++ b/sinks/@sinkempty/sinkempty.m Wed Jan 09 22:22:21 2013 +0000 @@ -1,20 +1,13 @@ % sinkempty - A sink with zero capacity. -classdef sinkempty < sink - properties (GetAccess=private,SetAccess=immutable) - chans % natural - fs % nonneg - end +classdef sinkempty < sinkbase methods function s=sinkempty(channels,rate) if nargin<2, rate=nan; end if nargin<1, channels=nan; end - s.chans=channels; - s.fs=rate; + s=struct@sinkbase(channels,rate); end function s=tostring(sig), s='sinkempty'; end - function c=channels(s), c=s.chans; end - function c=rate(s), c=s.fs; end function s=construct(sig) s.start = @nop; s.stop = @nop;
--- a/sinks/@sinkfun/sinkfun.m Sat Dec 22 16:17:51 2012 +0000 +++ b/sinks/@sinkfun/sinkfun.m Wed Jan 09 22:22:21 2013 +0000 @@ -1,23 +1,18 @@ % sinkfun - sink that calls given function with samples. -classdef sinkfun < sink +classdef sinkfun < sinkbase properties (GetAccess=private,SetAccess=immutable) fun % [[C,N]]->void - chans % natural - fs % nonneg end methods function s=sinkfun(fun,channels,rate) s.fun=fun; - s.fs=rate; - s.chans=channels; + s=s@sinkbase(channels,rate); end function s=tostring(sig) s=sprintf('sinkfun(%s)',tostring(sig.fun)); end - function c=channels(s), c=s.chans; end - function c=rate(s), c=s.fs; end function s=construct(sig) fun=sig.fun; t=0;
--- a/sinks/@sinknull/sinknull.m Sat Dec 22 16:17:51 2012 +0000 +++ b/sinks/@sinknull/sinknull.m Wed Jan 09 22:22:21 2013 +0000 @@ -2,21 +2,14 @@ % % sinknull :: C:natural -> sink(C,_). % sinknull :: C:natural, R:nonneg -> sink(C,R). -classdef sinknull < sink - properties (GetAccess=private,SetAccess=immutable) - chans - fs - end +classdef sinknull < sinkbase methods function s=sinknull(channels,rate) if nargin<2, rate=nan; end if nargin<1, channels=nan; end - s.chans=channels; - s.fs=rate; + s=struct@sinkbase(channels,rate); end function s=tostring(sig), s='sinknull'; end - function c=rate(s), c=s.fs; end - function c=channels(s), c=s.chans; end function s=construct(sig) s.start = @nop; s.stop = @nop;