changeset 3:3f77126f7b5f

First major revision of sequence library, now using classdef form, STILL A BIT BROKEN!
author samer
date Wed, 09 Jan 2013 22:22:21 +0000
parents 7357e1dc2ad6
children e44f49929e56
files arrows/@agraph/acquire.m arrows/@plotter/plotter.m arrows/adata.m sequences/+seq/bindcat.m sequences/+seq/buffer.m sequences/+seq/cache.m sequences/+seq/concat.m sequences/+seq/cons.m sequences/+seq/cycle.m sequences/+seq/iterate.m sequences/+seq/lcons.m sequences/+seq/map.m sequences/+seq/mapaccum.m sequences/+seq/merge.m sequences/+seq/repeat.m sequences/+seq/replicate.m sequences/+seq/resize.m sequences/+seq/scanl.m sequences/+seq/select.m sequences/+seq/skin.m sequences/+seq/slices.m sequences/+seq/subsample.m sequences/+seq/take.m sequences/+seq/takewhile.m sequences/+seq/unfold.m sequences/+seq/unfold_inf.m sequences/+seq/window.m sequences/+seq/zipaccum.m sequences/+seq/zipwith.m sequences/@seq/cumsum.m sequences/@seq/diffwith.m sequences/@seq/dynfilter.m sequences/@seq/filter.m sequences/@seq/foldl.m sequences/@seq/foreach.m sequences/@seq/gather.m sequences/@seq/gathern.m sequences/@seq/integrate.m sequences/@seq/limit.m sequences/@seq/max.m sequences/@seq/mean.m sequences/@seq/meandata.m sequences/@seq/min.m sequences/@seq/minmax.m sequences/@seq/seq.m sequences/@seq/span.m sequences/@seq/spanc.m sequences/@seq/split.m sequences/@seq/split_gather.m sequences/@seq/sum.m sequences/@seq/unbuffer.m sequences/@seq/window.m sequences/@seq/window_ns.m sequences/README sequences/cellseq.m sequences/cons.m sequences/expdata.m sequences/framedata.m sequences/integers.m sequences/isseq.m sequences/iterseq.m sequences/lazy_cons.m sequences/lindata.m sequences/naturals.m sequences/repeat.m sequences/rndscanl.m sequences/rndseq.m sequences/rndwindow.m sequences/rndzip.m sequences/rndzipaccum.m sequences/scanseqcols.m sequences/seq2cell.m sequences/seqbase.m sequences/singleton.m sequences/skinseq.m sequences/slices.m sequences/subsampleseq.m sequences/subseqdata.m sequences/unfoldseq.m sequences/wavelist.m signals/@signal/signal.m signals/sigrep.m sinks/@sinkarray/sinkarray.m sinks/@sinkcat/sinkcat.m sinks/@sinkempty/sinkempty.m sinks/@sinkfun/sinkfun.m sinks/@sinknull/sinknull.m
diffstat 87 files changed, 1987 insertions(+), 222 deletions(-) [+]
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;