Mercurial > hg > ishara
changeset 12:fbc0540a9208
Moved some high-order functions from funutils to arrutils, updated docs and cleaned up funutils.
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/arrutils/foldcols.m Mon Jan 14 22:21:11 2013 +0000 @@ -0,0 +1,13 @@ +% foldcols - fold from left combinator for columns of an array +% +% foldcols :; +% (A,[[N]]->A) ~'folding function', +% A ~'initial value', +% [[N,L]] ~'data to scan, sequence of length L' +% -> A. + +function y=foldcols(f,y,X) + for i=1:size(X,2), y=f(y,X(:,i)); end +end + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/arrutils/foldrcols.m Mon Jan 14 22:21:11 2013 +0000 @@ -0,0 +1,11 @@ +% foldcols :; +% ([[M]], [[N]] -> [[M]]) ~'folding function', +% [[M]] ~'initial value', +% [[N,L]] ~'data to scan, sequence of length L' +% -> [[M]]. + +function y=foldrcols(f,y,X,varargin) + for i=size(X,2):-1:1, y=f(y,X(:,i)); end +end + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/arrutils/forels.m Mon Jan 14 22:21:11 2013 +0000 @@ -0,0 +1,23 @@ +function forels(f,X,varargin) +% forels - do an action for each element of an array in order +% +% forels :: +% (A->action) ~'action to apply to each element', +% [[Size]->A] ~'array of elements of type', +% options { +% pause :: bool/0 +% drawnow :: bool/1 +% } ~'see ITERATE for more options' +% -> action. +% +% Note, the array can be multidimensional - the standard order +% cycles through the earlier indices before the later ones, eg +% rows, then columns, then slices etc. + + N=numel(X); + iterate(@g,1,varargin{:}); + + function i=g(i) + if i>N, i=[]; else f(X(i)); i=i+1; end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/arrutils/mapcols.m Mon Jan 14 22:21:11 2013 +0000 @@ -0,0 +1,23 @@ +function Y=mapcols(f,X) +% mapcols - Map a function of a vector over the columns of an array +% +% mapcols :: +% ([[N]->A] -> [[M]->B]) ~'function maps a column of A to one of B', +% [[N,L]->A] +% -> [[M,L]->B]. + +n=size(X,2); +if n==0, Y=[]; +else + y1=f(X(:,1)); + if size(y1,2)>1 + Y=repmat(y1(:),1,n); + for i=2:n + Y(:,i)=flatten(f(flatten(X(:,i)))); + end + else + Y=repmat(y1,1,n); + for i=2:n, Y(:,i)=f(X(:,i)); end + end +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/arrutils/maprows.m Mon Jan 14 22:21:11 2013 +0000 @@ -0,0 +1,16 @@ +function Y=maprows(f,X) +% maprows - Map a function of a vector over the rows of an array +% +% maprows :: +% ([[1,N]->A] -> [[1,M]->B]) ~'function maps a row of A to a row of B', +% [[L,N]->A] +% -> [[L,M]->B]. + +n=size(X,1); +if n==0, Y=[]; +else + for i=n:-1:1 + Y(i,:)=f(X(i,:)); + end +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/arrutils/scancols.m Mon Jan 14 22:21:11 2013 +0000 @@ -0,0 +1,12 @@ +% scancols :; +% ([[M]], [[N]] -> [[M]]) ~'scannning function', +% [[M]] ~'initial value', +% [[N,L]] ~'data to scan, sequence of length L' +% -> [[M,L]]. + +function Y=scancols(f,y,X) + Y=zeros(size(y,1),size(X,2)); + for i=1:size(X,2), y=f(y,X(:,i)); Y(:,i)=y; end +end + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/arrutils/scanrcols.m Mon Jan 14 22:21:11 2013 +0000 @@ -0,0 +1,13 @@ +% scanrcols - scan array columns from the right +% +% scanrcols :; +% ([[M]], [[N]] -> [[M]]) ~'scannning function', +% [[M]] ~'initial value', +% [[N,L]] ~'data to scan, sequence of length L' +% -> [[M,L]]. + +function Y=scanrcols(f,y,X,varargin) + Y=zeros(size(y,1),size(X,2)); + for i=size(X,2):-1:1, y=f(y,X(:,i)); Y(:,i)=y; end + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/arrutils/zipmap.m Mon Jan 14 22:21:11 2013 +0000 @@ -0,0 +1,139 @@ +function varargout=zipmap(spec,f,varargin) +% zipmap - Map and zip function over multidimensional arrays +% +% ZIPMAP allows a certain simple functions to be applied to multidimensional +% array arguments, manipulating the dimensions to combine elementwise and +% outer-product-like behaviour. (The name comes from functional programming +% terminology: functions/operators like .* and + which apply elementwise to +% vector arguments are said to zip their arguments, while outer products are +% like mapping a function over a list, or a list of functions over another list.) +% +% Let f be a vectorised function which knows how to zip array arguments. Eg, +% f(x,y)=x+y. If x and y are vectors, they must be the same size, and +% the function is applied to corresponding pairs of elements, resulting in +% a vector of the same size. With ZIPMAP, you can build functions, that, eg, +% add EVERY pair of elements (not just corresponding pairs) resulting in a +% 2D array: zipmap(0,@(x,y)x+y,[1:4]',[1:6]') will do this +% +% The domain of a multidimensional array can be described a list containing the +% size of each dimension, as returned by the SIZE function (or SIZE1 which strips +% trailing 1s). The arguments to f must have a certain domain structure: +% +% dom arg1 = [p1 zipdom] +% dom arg2 = [p2 zipdom] +% : +% +% where p1, p2, etc are the domains of the elementary function of which f +% is a vectorisation, eg the elementary domain of .* can be scalars and +% hence p1=p2=[], but the two elementary domains of CROSS are both [3], because it +% it operates on pairs of 3-D vectors. The zipdom part must be the same for +% all arguments, otherwise, we cannot extract matching argument tuples. +% If this is the case, the f must return a result: +% +% dom f(...) : [rdom zipdom] +% +% where rdom is the domain of the elementary function, eg [3] for the vector +% valued CROSS product, but [] for the scalar valued DOT product. Note that +% these domains can be vectors of any length from zero up, eg the determinant +% of a square matrix has a domain of [n n]. +% +% ZIPDIM allows the domains of the arguments and result to be generalised as follows: +% +% dom arg1 : [p1 m1 zipdom] +% dom arg2 : [p2 m2 zipdom] +% : +% +% dom zipdom(...) : [rdom m1 m2 ... zipdom ] +% +% All the mapped dimensions m1, m2 etc go into a sort of outer product where +% every combination of values is evaluated. In addition, the order of the +% m1, m2 etc can be permuted in the result at essentially no extra computational cost. +% +% Usage: r=zipmap(spec,f,<varargs>) +% +% spec defines how the domain of each of the arguments is to be interpreted, ie +% how is is split into elementary, mappable, and zippable domains. +% +% If spec is a number z, then the last z dimensions of each argument are marked for +% zipping, while the rest are for mapping. The elementary domains are assumed to +% be scalar and hence p1, p2 etc =[]. So, zipmap(0,...) does the complete outer +% product type of evaluation. +% +% If spec is structure, the field 'zipdims' determines how many dimensions are zipped. +% The field 'pdims' is a the vector [length(p1) length(p2) ..], ie the dimensionality +% of each elementary domain: 0 for scalars, 1 for vectors, 2 for matrices etc. +% The optional field 'mapord' determines the reordering of the mapped domains, eg +% if mapord=[2 1 3], then the result domain is [m2 m1 m3] instead of [m1 m2 m3]. +% +% If spec is a cell array, it is interpreted as {zipdims pdims mapord}. +% +% Extra options +% +% If spec is a structure, it can contain further options: if spec.shift=1, +% then the domains of all arguments are pre-shifted to remove singleton +% dimensions before anything else is done. Amongst other effects, this means +% that row vectors can be used in place of column vectors. + + % unpack args from spec + if iscell(spec) + [zipdims,pdims,mapord]=getargs(spec,{0 [] []}); + elseif isstruct(spec) + zipdims=getparam(spec,'zipdims',0); + pdims=getparam(spec,'pdims',[]); + mapord=getparam(spec,'mapord',[]); + if getparam(spec,'shift',0), + varargin=cellmap(@shiftdim,varargin); + end + elseif isscalar(spec) + zipdims=spec; pdims=[]; mapord=[]; + end + + + argdoms=cellmap(@size1,varargin); + if isempty(pdims), pdims=zeros(size(varargin)); end + for i=1:length(varargin) + [pdoms{i},mapdoms{i},zipdoms{i}]=split(argdoms{i},pdims(i),zipdims); + end + + + % check all zipdoms match and use first + zipdom=zipdoms{1}; + for i=2:length(zipdoms) + if ~all(zipdoms{i}==zipdom), error('Zip domains do not match'); end + end + + + if isempty(mapord), mapord=1:length(varargin); end + outerdom=cat(2,mapdoms{mapord}); + outer1=cellmap(@to1s,mapdoms); + for i=1:length(varargin) + % need to reshape each arg and then repmat up to correct size + newsizes=outer1; newsizes{i}=mapdoms{i}; + newsize=[pdoms{i} cat(2,newsizes{mapord}) zipdom]; + varargin{i}=reshape(varargin{i},tosize([pdoms{i} cat(2,newsizes{mapord}) zipdom])); + newsizes=mapdoms; newsizes{i}=outer1{i}; + newsize=[to1s(pdoms{i}) cat(2,newsizes{mapord}) to1s(zipdom)]; + varargin{i}=repmat(varargin{i},tosize(newsize)); + % size(varargin{i}) + end + + [varargout{1:max(1,nargout)}]=feval(f,varargin{:}); +end + +function [a,b,c]=split(x,n,m) + a=x(1:n); + b=x(n+1:end-m); + c=x(end-m+1:end); +end + +% getargs - get values of optional parameters with defaults +% +% getargs :: {I:[N]->(A(I) | nil)}, {I:[N]->A(I)} -> A(1), ..., A(N). +function varargout=getargs(args,defs) + nout=max(length(args),length(defs)); + varargout=defs; + for i=1:length(args) + if ~isempty(args{i}), varargout(i)=args(i); end + end +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/cellutils/@cell/foldr.m Mon Jan 14 22:21:11 2013 +0000 @@ -0,0 +1,13 @@ +function X=foldr(fn,e,args) +% foldr - Fold combinator from functional programming +% +% This function applies an associative operator to a list of arguments, +% starting from the right, eg +% elements, eg foldr(@plus,0,{1,2,3,4}) = (1+(2+(3+(4+0)))). +% +% foldr :: +% (Y,X->X) ~'associative binary operator', +% Y ~'initial element', +% {[N]->Y} ~'list (cell array) of arguments (at least 2 elements)' +% -> Y. +X=e; for i=length(args):-1:1, X=fn(args{i},X); end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/@function_handle/mtimes.m Mon Jan 14 22:21:11 2013 +0000 @@ -0,0 +1,10 @@ +function h=compose(f,g) +% compose - Constructs composition of two functions +% +% compose :: (B->C), (A{1:N}->B) -> (A{1:N}->C). +% +% returns the function h such that h(...) = f(g(...)) + + h=@fg; + function x=fg(varargin), x=f(g(varargin{:})); end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/@function_handle/plus.m Mon Jan 14 22:21:11 2013 +0000 @@ -0,0 +1,6 @@ +function h=plus(f,g) +% plus - Constructs parallel composition of two functions +% +% plus :: (A1->B1), (A2->B2) -> (A1,A2->B1,B2). + h=@(x,y)deal(f(x),g(y)); +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/TODO Mon Jan 14 22:21:11 2013 +0000 @@ -0,0 +1,16 @@ +Think about algebra of function handles - funseq, scanner_add_plotter etc +are special cases function combinators. What is the most general language +for function algebra? Is it the arrow algebra restricted to functional arrows? + + +Function combinators + composition : f*g(x) = f(g(x)) + parallel composition f+g(x,y)=f(x),g(y) + +Function types + state transformers: S->S + scanner: Y,X->Y + folder: X,S->S + accum: Y,S->X,S + +Also what about actions? (Function with side-effects or dependence on global state)
--- a/general/funutils/apply.m Mon Jan 14 15:52:31 2013 +0000 +++ b/general/funutils/apply.m Mon Jan 14 22:21:11 2013 +0000 @@ -1,9 +1,9 @@ function varargout=apply(fn,args) % apply - Apply function to list (cell array) of arguments % -% Not typable. -% -% if [y1,y2,...]=fn(x1,x2,...), then -% [y1,y2,...]=apply(fn,{x1,x2,...}) +% apply :: +% (A:typelist(N)->B:typelist(M)) ~'function with N inputs and M outputs', +% cell { A:typelist(N) } ~'cell array with N elements of types AX' +% -> B{1}, ..., B{M} ~'M return values of types B{1} to B{M}'. -[varargout{1:max(1,nargout)}] = feval(fn,args{:}); +[varargout{1:max(1,nargout)}] = fn(args{:});
--- a/general/funutils/bind.m Mon Jan 14 15:52:31 2013 +0000 +++ b/general/funutils/bind.m Mon Jan 14 22:21:11 2013 +0000 @@ -1,6 +1,10 @@ -function cfn=bind(fn,varargin) % bind - Create a partially applied function % +% bind :: +% func(A{1}, ..., A{N}->B{1:L}) ~'func from N inputs to L outputs', +% A{1}, ..., A{M} ~'M<=N input arguments of the correct types' +% -> func(A{M+1}, ..., A{N}->B{1:L}) ~'func from remaining arguments to returns'. +% % BIND(fn,a1,a2,...) % If fn is an ordinary function, the parameters a1, a2 etc % are bound as the first few arguments @@ -8,8 +12,8 @@ % If fn is a function object as returned by FUNC, BIND, or PERM, % the given parameters are bound to the free slots of the function % and a new partially applied function is returned. -% +function cfn=bind(fn,varargin) if ischar(fn), fn=str2func(fn); end if ~isa(fn,'func'), fn=func(fn); end cfn=bind(fn,varargin{:});
--- a/general/funutils/bind1.m Mon Jan 14 15:52:31 2013 +0000 +++ b/general/funutils/bind1.m Mon Jan 14 22:21:11 2013 +0000 @@ -1,6 +1,9 @@ % bind1 - Bind arguments to a function using Matlab closure % -% bind1 :: (A1, A2, ... -> B1, B2 ..), A1 -> (A2, ...) -> B1, B2 ... +% bind1 :: +% func(A{1}, ..., A{N}->B{1:L}) ~'func from N inputs to L outputs', +% A{1}, ..., A{M} ~'M<=N input arguments of the correct types' +% -> func(A{M+1}, ..., A{N}->B{1:L}) ~'func from remaining arguments to returns'. function g=bind1(f,varargin) args=varargin;
--- a/general/funutils/compose.m Mon Jan 14 15:52:31 2013 +0000 +++ b/general/funutils/compose.m Mon Jan 14 22:21:11 2013 +0000 @@ -1,7 +1,7 @@ function h=compose(f,g) % compose - Constructs composition of two functions % -% compose :: (B->C), (A->B) -> (A->C). +% compose :: (B->C), (A{1:N}->B) -> (A{1:N}->C). % % returns the function h such that h(...) = f(g(...))
--- a/general/funutils/doer.m Mon Jan 14 15:52:31 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -function h=funseq(varargin) -% funseq - Constructs sequential application of several functions -% -% h=funseq(f,...,g) -% -% returns the function h such that h(...) = g(...) but -% all functions are evaluated in order. - - fns=varargin; - h=@seq; - - function varargout=seq(varargin) - for i=1:length(fns)-1 - feval(fns{i},varargin{:}); - end - if nargout==0, - feval(fns{end},varargin{:}); - else - [varargout{1:nargout}]=feval(fns{end},varargin{:}); - end - end -end
--- a/general/funutils/feval2cell.m Mon Jan 14 15:52:31 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -function Y=returns(I,F,varargin) -% returns - Evaluate function and return multiple values in cell array -% -% returns :: -% I:[[M]->[N]] ~'M numbers between 1 and N', -% (A(1),...,A(L) -> B(1), ..., B(N)) ~'function with L in and N outputs', -% A(1), ..., A(L) ~'arguments for function' -% -> cell { B(I(1)), ..., B(I(M)) } ~'selected returns in a cell array'. - -Z=cell(max(I),1); -[Z{:}]=F(varargin{:}); -Y=Z(I);
--- a/general/funutils/flip.m Mon Jan 14 15:52:31 2013 +0000 +++ b/general/funutils/flip.m Mon Jan 14 22:21:11 2013 +0000 @@ -2,6 +2,7 @@ % flip - Flip order of first two arguments to a function % % flip :: (A,B->C) -> (B,A->C). +% flip :: (A,B,D{1:N}->C) -> (B,A,D{1:N}->C). if isa(f,'func'), g=perm(f,[2,1]);
--- a/general/funutils/foldcols.m Mon Jan 14 15:52:31 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -% foldcols - fold from left combinator for columns of an array -% -% foldcols :; -% (A,[[N]]->A) ~'folding function', -% A ~'initial value', -% [[N,L]] ~'data to scan, sequence of length L' -% -> A. - -function y=foldcols(f,y,X,varargin) - if nargin>3 - opts=prefs('draw',0,varargin{:}); - for i=1:size(X,2) - y1=f(y,X(:,i)); - if opts.draw - opts.plotfn(i,y,X(:,i),y1); - end - optpause(opts); - y=y1; - end - else % streamlined version - for i=1:size(X,2), y=f(y,X(:,i)); end - end - -
--- a/general/funutils/foldrcols.m Mon Jan 14 15:52:31 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -% foldcols :; -% ([[M]], [[N]] -> [[M]]) ~'folding function', -% [[M]] ~'initial value', -% [[N,L]] ~'data to scan, sequence of length L' -% -> [[M]]. - -function y=foldrcols(f,y,X,varargin) - if nargin>3 - opts=prefs('draw',0,varargin{:}); - for i=size(X,2):-1:1 - y1=f(y,X(:,i)); - if opts.draw - opts.plotfn(i,y,X(:,i),y1); - end - optpause(opts); - y=y1; - end - else % streamlined version - for i=size(X,2):-1:1, y=f(y,X(:,i)); end - end - -
--- a/general/funutils/forels.m Mon Jan 14 15:52:31 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -function forels(f,X,varargin) -% forels - do an action for each element of an array in order -% -% forels :: -% (A->action) ~'action to apply to each element', -% [[Size]->A] ~'array of elements of type', -% options { -% pause :: bool/0 -% drawnow :: bool/1 -% } ~'see ITERATE for more options' -% -> action. -% -% Note, the array can be multidimensional - the standard order -% cycles through the earlier indices before the later ones, eg -% rows, then columns, then slices etc. - - N=numel(X); - iterate(@g,1,varargin{:}); - - function i=g(i) - if i>N, i=[]; else f(X(i)); i=i+1; end - end -end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/funseq.m Mon Jan 14 22:21:11 2013 +0000 @@ -0,0 +1,22 @@ +function h=funseq(varargin) +% funseq - Constructs sequential application of several functions +% +% h=funseq(f,...,g) +% +% returns the function h such that h(...) = g(...) but +% all functions are evaluated in order. + + fns=varargin; + h=@seq; + + function varargout=seq(varargin) + for i=1:length(fns)-1 + feval(fns{i},varargin{:}); + end + if nargout==0, + feval(fns{end},varargin{:}); + else + [varargout{1:nargout}]=feval(fns{end},varargin{:}); + end + end +end
--- a/general/funutils/mapcols.m Mon Jan 14 15:52:31 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -function Y=mapcols(f,X) -% mapcols - Map a function of a vector over the columns of an array -% -% mapcols :: -% ([[N]->A] -> [[M]->B]) ~'function maps a column of A to one of B', -% [[N,L]->A] -% -> [[M,L]->B]. - -n=size(X,2); -if n==0, Y=[]; -else - for i=n:-1:1 - Y(:,i)=flatten(feval(f,flatten(X(:,i)))); - end -end -
--- a/general/funutils/maprows.m Mon Jan 14 15:52:31 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -function Y=maprows(f,X) -% maprows - Map a function of a vector over the rows of an array -% -% maprows :: -% ([[1,N]->A] -> [[1,M]->B]) ~'function maps a row of A to a row of B', -% [[L,N]->A] -% -> [[L,M]->B]. - -n=size(X,1); -if n==0, Y=[]; -else - for i=n:-1:1 - Y(i,:)=f(X(i,:)); - end -end -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/returns.m Mon Jan 14 22:21:11 2013 +0000 @@ -0,0 +1,12 @@ +function Y=returns(I,F,varargin) +% returns - Evaluate function and return multiple values in cell array +% +% returns :: +% I:[[M]->[N]] ~'M numbers between 1 and N', +% (A(1),...,A(L) -> B(1), ..., B(N)) ~'function with L in and N outputs', +% A(1), ..., A(L) ~'arguments for function' +% -> cell { B(I(1)), ..., B(I(M)) } ~'selected returns in a cell array'. + +Z=cell(max(I),1); +[Z{:}]=F(varargin{:}); +Y=Z(I);
--- a/general/funutils/scancols.m Mon Jan 14 15:52:31 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -% scancols :; -% ([[M]], [[N]] -> [[M]]) ~'scannning function', -% [[M]] ~'initial value', -% [[N,L]] ~'data to scan, sequence of length L' -% -> [[M,L]]. - -function Y=scancols(f,y,X,varargin) - Y=zeros(size(y,1),size(X,2)); - - if nargin>3 - opts=prefs('draw',0,varargin{:}); - for i=1:size(X,2) - y1=f(y,X(:,i)); - Y(:,i)=y1; - if opts.draw, opts.plotfn(i,y,X(:,i),y1); end - optpause(opts); - y=y1; - end - else - for i=1:size(X,2), y=f(y,X(:,i)); Y(:,i)=y; end - end - -
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/scanner_add_plotter.m Mon Jan 14 22:21:11 2013 +0000 @@ -0,0 +1,16 @@ +% scanner_add_plotter - Add plotting capabilities to scan function +% +% scanner_add_plotter :: +% (S,X->S) ~'scanning function', +% options { +% draw :: bool/false ~'enable drawing if true'; +% pause :: natural/0 ~'pause duration in ms'; +% drawnow :: bool/true ~'whether or not to call drawnow afterwards' +% } +% -> (S,X->X) ~'new scanning function'. + +function f1=scanner_add_plotter(f,opts) + opts=prefs('draw',0,varargin{:}); + if ~opts.draw, f1=f; else ps=pauser(opts); f1=@g; end + function y1=g(y,x), y1={f(y,x),i}; opts.plotfn(x,y,y1); ps(); end +end
--- a/general/funutils/scanrcols.m Mon Jan 14 15:52:31 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -% scanrcols - scan array columns from the right -% -% scanrcols :; -% ([[M]], [[N]] -> [[M]]) ~'scannning function', -% [[M]] ~'initial value', -% [[N,L]] ~'data to scan, sequence of length L' -% -> [[M,L]]. - -function Y=scanrcols(f,y,X,varargin) - Y=zeros(size(y,1),size(X,2)); - - if nargin>3 - opts=prefs('draw',0,varargin{:}); - for i=size(X,2):-1:1 - y1=f(y,X(:,i)); - Y(:,i)=y1; - if opts.draw, opts.plotfn(i,y,X(:,i),y1); end - optpause(opts); - y=y1; - end - else - for i=size(X,2):-1:1, y=f(y,X(:,i)); Y(:,i)=y; end - end - -
--- a/general/funutils/tail.m Mon Jan 14 15:52:31 2013 +0000 +++ b/general/funutils/tail.m Mon Jan 14 22:21:11 2013 +0000 @@ -5,7 +5,7 @@ % thunk(B{1:M}) ::= % exists C{1:L} . cell { C{1:L}->B{1:M}, cell { C{1:L} } } % | cell { {0}, cell { B{1:L} } } -% | unit -> B{1:M}. +% | void -> B{1:M}. function varargout=feval_tail1(fn,varargin) ret=fn(varargin{:});
--- a/general/funutils/tail_call.m Mon Jan 14 15:52:31 2013 +0000 +++ b/general/funutils/tail_call.m Mon Jan 14 22:21:11 2013 +0000 @@ -5,5 +5,5 @@ % thunk(B{1:M}) ::= % exists C{1:L} . cell { C{1:L}->B{1:M}, cell { C{1:L} } } % | cell { {0}, cell { B{1:L} } } -% | unit -> B{1:M}. +% | void -> B{1:M}. function ret=tail_call(fn,varargin), ret={fn,varargin}; end
--- a/general/funutils/tail_return.m Mon Jan 14 15:52:31 2013 +0000 +++ b/general/funutils/tail_return.m Mon Jan 14 22:21:11 2013 +0000 @@ -5,5 +5,5 @@ % thunk(B{1:M}) ::= % exists C{1:L} . cell { C{1:L}->B{1:M}, cell { C{1:L} } } % | cell { {0}, cell { B{1:L} } } -% | unit -> B{1:M}. +% | void -> B{1:M}. function ret=tail_return(varargin), ret={0,varargin}; end
--- a/general/funutils/zip.m Mon Jan 14 15:52:31 2013 +0000 +++ b/general/funutils/zip.m Mon Jan 14 22:21:11 2013 +0000 @@ -1,4 +1,7 @@ % zip - Polymorphic zip using zipwith(@tuple,...) +% +% zip :: seq(A1), seq(A2), ... -> seq(cell {A1,A2,..}). +% zip :: cells(A1), cells(A2), ... -> cells(cell {A1,A2,..}). function y=zip(varargin) y=zipwith(@tuple,varargin{:}); end
--- a/general/funutils/zipmap.m Mon Jan 14 15:52:31 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,139 +0,0 @@ -function varargout=zipmap(spec,f,varargin) -% zipmap - Map and zip function over multidimensional arrays -% -% ZIPMAP allows a certain simple functions to be applied to multidimensional -% array arguments, manipulating the dimensions to combine elementwise and -% outer-product-like behaviour. (The name comes from functional programming -% terminology: functions/operators like .* and + which apply elementwise to -% vector arguments are said to zip their arguments, while outer products are -% like mapping a function over a list, or a list of functions over another list.) -% -% Let f be a vectorised function which knows how to zip array arguments. Eg, -% f(x,y)=x+y. If x and y are vectors, they must be the same size, and -% the function is applied to corresponding pairs of elements, resulting in -% a vector of the same size. With ZIPMAP, you can build functions, that, eg, -% add EVERY pair of elements (not just corresponding pairs) resulting in a -% 2D array: zipmap(0,inline('x+y','x','y'),[1:4]',[1:6]') will do this -% -% The domain of a multidimensional array can be described a list containing the -% size of each dimension, as returned by the SIZE function (or SIZE1 which strips -% trailing 1s). The arguments to f must have a certain domain structure: -% -% dom arg1 = [p1 zipdom] -% dom arg2 = [p2 zipdom] -% : -% -% where p1, p2, etc are the domains of the elementary function of which f -% is a vectorisation, eg the elementary domain of .* can be scalars and -% hence p1=p2=[], but the two elementary domains of CROSS are both [3], because it -% it operates on pairs of 3-D vectors. The zipdom part must be the same for -% all arguments, otherwise, we cannot extract matching argument tuples. -% If this is the case, the f must return a result: -% -% dom f(...) : [rdom zipdom] -% -% where rdom is the domain of the elementary function, eg [3] for the vector -% valued CROSS product, but [] for the scalar valued DOT product. Note that -% these domains can be vectors of any length from zero up, eg the determinant -% of a square matrix has a domain of [n n]. -% -% ZIPDIM allows the domains of the arguments and result to be generalised as follows: -% -% dom arg1 : [p1 m1 zipdom] -% dom arg2 : [p2 m2 zipdom] -% : -% -% dom zipdom(...) : [rdom m1 m2 ... zipdom ] -% -% All the mapped dimensions m1, m2 etc go into a sort of outer product where -% every combination of values is evaluated. In addition, the order of the -% m1, m2 etc can be permuted in the result at essentially no extra computational cost. -% -% Usage: r=zipmap(spec,f,<varargs>) -% -% spec defines how the domain of each of the arguments is to be interpreted, ie -% how is is split into elementary, mappable, and zippable domains. -% -% If spec is a number z, then the last z dimensions of each argument are marked for -% zipping, while the rest are for mapping. The elementary domains are assumed to -% be scalar and hence p1, p2 etc =[]. So, zipmap(0,...) does the complete outer -% product type of evaluation. -% -% If spec is structure, the field 'zipdims' determines how many dimensions are zipped. -% The field 'pdims' is a the vector [length(p1) length(p2) ..], ie the dimensionality -% of each elementary domain: 0 for scalars, 1 for vectors, 2 for matrices etc. -% The optional field 'mapord' determines the reordering of the mapped domains, eg -% if mapord=[2 1 3], then the result domain is [m2 m1 m3] instead of [m1 m2 m3]. -% -% If spec is a cell array, it is interpreted as {zipdims pdims mapord}. -% -% Extra options -% -% If spec is a structure, it can contain further options: if spec.shift=1, -% then the domains of all arguments are pre-shifted to remove singleton -% dimensions before anything else is done. Amongst other effects, this means -% that row vectors can be used in place of column vectors. - - -% unpack args from spec -if iscell(spec) - [zipdims,pdims,mapord]=getargs(spec,{0 [] []}); -elseif isstruct(spec) - zipdims=getparam(spec,'zipdims',0); - pdims=getparam(spec,'pdims',[]); - mapord=getparam(spec,'mapord',[]); - if getparam(spec,'shift',0), - varargin=cellmap(@shiftdim,varargin); - end -elseif isscalar(spec) - zipdims=spec; pdims=[]; mapord=[]; -end - - -argdoms=cellmap(@size1,varargin); -if isempty(pdims), pdims=zeros(size(varargin)); end -for i=1:length(varargin) - [pdoms{i},mapdoms{i},zipdoms{i}]=split(argdoms{i},pdims(i),zipdims); -end - - -% check all zipdoms match and use first -zipdom=zipdoms{1}; -for i=2:length(zipdoms) - if ~all(zipdoms{i}==zipdom), error('Zip domains do not match'); end -end - - -if isempty(mapord), mapord=1:length(varargin); end -outerdom=cat(2,mapdoms{mapord}); -outer1=cellmap(@to1s,mapdoms); -for i=1:length(varargin) - % need to reshape each arg and then repmat up to correct size - newsizes=outer1; newsizes{i}=mapdoms{i}; - newsize=[pdoms{i} cat(2,newsizes{mapord}) zipdom]; - varargin{i}=reshape(varargin{i},tosize([pdoms{i} cat(2,newsizes{mapord}) zipdom])); - newsizes=mapdoms; newsizes{i}=outer1{i}; - newsize=[to1s(pdoms{i}) cat(2,newsizes{mapord}) to1s(zipdom)]; - varargin{i}=repmat(varargin{i},tosize(newsize)); -% size(varargin{i}) -end - -[varargout{1:max(1,nargout)}]=feval(f,varargin{:}); - -function [a,b,c]=split(x,n,m) - a=x(1:n); - b=x(n+1:end-m); - c=x(end-m+1:end); - -% getargs - get values of optional parameters with defaults -% -% getargs :: {I:[N]->(A(I) | nil)}, {I:[N]->A(I)} -> A(1), ..., A(N). - -function varargout=getargs(args,defs) - -nout=max(length(args),length(defs)); -varargout=defs; -for i=1:length(args) - if ~isempty(args{i}), varargout(i)=args(i); end -end -