view sequences/@seq/seq.m @ 6:0ce3c2070089

Removed duplicate code and fixed doc in timed_action.
author samer
date Mon, 14 Jan 2013 14:33:37 +0000
parents 3f77126f7b5f
children f0a3d7d7a0e3
line wrap: on
line source
% 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