changeset 38:9d24b616bb06

Added function algebra.
author samer
date Tue, 29 Jan 2013 15:59:01 +0000
parents beb8a3f4a345
children c388f1c70669
files general/funutils/@function_handle/and.m general/funutils/@function_handle/ctranspose.m general/funutils/@function_handle/ge.m general/funutils/@function_handle/gt.m general/funutils/@function_handle/horzcat.m general/funutils/@function_handle/lt.m general/funutils/@function_handle/mpower.m general/funutils/@function_handle/mrdivide.m general/funutils/@function_handle/not.m general/funutils/@function_handle/or.m general/funutils/@function_handle/power.m general/funutils/@function_handle/private/acount.m general/funutils/@function_handle/rdivide.m general/funutils/@function_handle/table.m general/funutils/@function_handle/vertcat.m general/funutils/README.txt general/funutils/TODO general/funutils/funseq.m general/funutils/multicall.m sequences/+seq/selector.m
diffstat 20 files changed, 261 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/general/funutils/@function_handle/and.m	Tue Jan 29 15:59:01 2013 +0000
@@ -0,0 +1,23 @@
+% and - function combinator, f&g (...) = f(...); return g(...)
+%
+% and ::
+%    (A{:} => B{:}),
+%    (A{:} => C{:})
+% -> (A{:} => C{:}).
+%
+% and ::
+%    (A{1:N} => B{:}),
+%    (A{1:N} => C{1:M}),
+%    N:natural,
+%    M:natural
+% -> (A{1:N} => C{1:M}).
+function h=and(f,g,nin,nout)
+	if nargin<4, nout=nargout(g); end
+	if nargin<3, nin=nargin(g); end
+	fns = { @q11, @q1n; @qn1, @qnn };
+	h=fns{acount(nin,1),acount(nout,1)};
+	function y=q11(x), f(x); y=g(x); end
+	function y=qn1(varargin), f(varargin{:}); y=g(varargin{:}); end
+	function varargout=q1n(x), f(x); [varargout{1:nargout}]=g(x); end
+	function varargout=qnn(varargin), f(varargin{:}); [varargout{1:nargout}]=g(varargin{:}); end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/general/funutils/@function_handle/ctranspose.m	Tue Jan 29 15:59:01 2013 +0000
@@ -0,0 +1,10 @@
+function h=ctranspose(f,nin,nout)
+	fns = { @q21, @q2n; @qn1, @qnn };
+	if nargin<3, nout=nargout(f); end
+	if nargin<2, nin=nargin(f); end
+	h=fns{acount(nin,2)-1,acount(nout,1)};
+	function y=q21(x,y), y=f(y,x); end
+	function y=qn1(x,y,varargin), y=f(y,x,varargin{:}); end
+	function varargout=q2n(x,y), [varargout{1:nargout}]=f(y,x); end
+	function varargout=qnn(x,y,varargin), [varargout{1:nargout}]=f(y,x,varargin{:}); end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/general/funutils/@function_handle/ge.m	Tue Jan 29 15:59:01 2013 +0000
@@ -0,0 +1,7 @@
+function g=ge(f,nout)
+	if nargin<2, nout=nargout(f); end
+	if nout<0, error('function must have a definite number of outputs'); end
+	if nargin(f)==1, g=@h1; else g=@hn; end
+	function rets=h1(x), [rets{1:nout}]=f(x); end
+	function rets=hn(varargin), [rets{1:nout}]=f(varargin{:}); end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/general/funutils/@function_handle/gt.m	Tue Jan 29 15:59:01 2013 +0000
@@ -0,0 +1,12 @@
+function g=gt(f,I,nin)
+	if nargin<3, nin=nargin(f); end
+	nout=length(I); MI=max(I);
+	fns = { @q11, @q1n; @qn1, @qnn };
+	g=fns{acount(nin,1),acount(nout,1)};
+
+	function y=q11(x), [rets{1:MI}]=f(x); y=rets{I}; end
+	function y=qn1(varargin), [rets{1:MI}]=f(varargin{:}); y=rets{I}; end
+	function varargout=q1n(x), [rets{1:MI}]=f(x); varargout=rets(I); end
+	function varargout=qnn(varargin), [rets{1:MI}]=f(varargin{:}); varargout=rets(I); end
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/general/funutils/@function_handle/horzcat.m	Tue Jan 29 15:59:01 2013 +0000
@@ -0,0 +1,32 @@
+% horzcat - function combinator, 
+%
+% horzcat ::
+%    F:(A{1:N} => B{1:M}),
+%    G:(A{1:N} => C{1:L}),
+%    N:natural,              ~'defaults to nargin(F)'
+%    M:natural               ~'defaults to nargout(F)'
+% -> (A{1:N} => B{1:M}, C{1:L}).
+function h=horzcat(varargin)
+	funs=varargin;
+	nouts=cell2mat(map(@nargout,varargin));
+	NN=sum(nouts); N=length(funs);
+	fns = { @q1n; @qnn };
+	h=fns{acount(nargin(funs{1}),1)};
+
+	function varargout=q1n(x), 
+		varargout=cell(1,NN);
+		j=0; for i=1:N
+			k=j+nouts(i);
+			[varargout{j+1:k}]=funs{i}(x); 
+			j=k;
+		end
+	end
+	function varargout=qnn(varargin), 
+		varargout=cell(1,NN);
+		j=0; for i=1:N
+			k=j+nouts(i);
+			[varargout{j+1:k}]=funs{i}(varargin{:}); 
+			j=k;
+		end
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/general/funutils/@function_handle/lt.m	Tue Jan 29 15:59:01 2013 +0000
@@ -0,0 +1,10 @@
+function g=le(f,I)
+	if nargout(f)==1, g=@q1; else g=@qn; end
+
+	function x=q1(varargin)
+		x=f(varargin{I});
+	end
+	function varargout=qn(varargin)
+		[varargout{1:nargout}]=f(varargin{I});
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/general/funutils/@function_handle/mpower.m	Tue Jan 29 15:59:01 2013 +0000
@@ -0,0 +1,3 @@
+function varargout=mpower(f,x)
+	[varargout{1:nargout}]=f(x);
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/general/funutils/@function_handle/mrdivide.m	Tue Jan 29 15:59:01 2013 +0000
@@ -0,0 +1,11 @@
+% lt - Bind one argument to a function using Matlab closure
+%
+% lt :: 
+%    (A{1:N}->B{1:L}) ~'func from N inputs to L outputs',
+%    A{1}             ~'first argument'
+% -> (A{2:N}->B{1:L}) ~'func from remaining arguments to returns'.
+
+function g=lt(f,x)
+	g=@(varargin)f(x,varargin{:});
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/general/funutils/@function_handle/not.m	Tue Jan 29 15:59:01 2013 +0000
@@ -0,0 +1,7 @@
+function g=not(f,nout)
+	if nargin<2, nout=nargout(f); end
+	if nout<0, error('function must have a definite number of outputs'); end
+	if nargin(f)==1, g=@h1; else g=@hn; end
+	function rets=h1(x), [rets{1:nout}]=f(x); end
+	function rets=hn(varargin), [rets{1:nout}]=f(varargin{:}); end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/general/funutils/@function_handle/or.m	Tue Jan 29 15:59:01 2013 +0000
@@ -0,0 +1,22 @@
+% or - function combinator, f|g (...) = f(...), g(...)
+%
+% or ::
+%    F:(A{1:N} => B{1:M}),
+%    G:(A{1:N} => C{1:L}),
+%    N:natural,              ~'defaults to nargin(F)'
+%    M:natural               ~'defaults to nargout(F)'
+% -> (A{1:N} => B{1:M}, C{1:L}).
+function h=and(f,g,nin,nout)
+	if nargin<4, nout=nargout(f); end
+	if nargin<3, nin=nargin(f); end
+	fns = { @q11, @q1n; @qn1, @qnn };
+	h=fns{acount(nin,1),max(acount(nargout(g),1),acount(nout,1))};
+
+	function [y,z]=q11(x), y=f(x); z=g(x); end
+	function [y,z]=qn1(varargin), y=f(varargin{:}); z=g(varargin{:}); end
+	function varargout=q1n(x), [varargout{1:nout}]=f(x); [varargout{nout+1:nargout}]=g(x); end
+	function varargout=qnn(varargin), 
+		[varargin{1:nout}]=f(varargin{:}); 
+		[varargout{1:nargout}]=g(varargin{:}); 
+	end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/general/funutils/@function_handle/power.m	Tue Jan 29 15:59:01 2013 +0000
@@ -0,0 +1,2 @@
+function varargout=lt(f,args)
+	[varargout{1:nargout}]=f(args{:});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/general/funutils/@function_handle/private/acount.m	Tue Jan 29 15:59:01 2013 +0000
@@ -0,0 +1,1 @@
+function n=acount(m,k), if m<0 || m>k, n=k+1; else n=m; end; end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/general/funutils/@function_handle/rdivide.m	Tue Jan 29 15:59:01 2013 +0000
@@ -0,0 +1,11 @@
+% rdivide - Bind arguments to a function using Matlab closure
+%
+% rdivide :: 
+%    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=rdivide(f,args)
+	g=@(varargin)f(args{:},varargin{:});
+end
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/general/funutils/@function_handle/table.m	Tue Jan 29 15:59:01 2013 +0000
@@ -0,0 +1,39 @@
+function [g,s,l,seq]=table(f,varargin)
+	opts=options('nargin',nargin(f),'nargout',nargout(f),'file',[],varargin{:});
+	nin=opts.nargin;
+	nout=opts.nargout;
+
+	Table=cell(0,nin+nout);
+
+	g=@lookup;
+	s=@saver;
+	l=@loader;
+	seq=@getrows;
+ 
+	function s=getrows, s=slices(Table,1); end
+	function saver(file), 
+		if nargin<1, file=opts.file; end
+		fprintf('saving %d tabled rows of %s to %s\n',size(Table,1),tostring(f),file);
+		d.table=Table;
+		save(file,'-struct','d'); 
+	end
+	function loader(file), 
+		if nargin<1, file=opts.file; end
+		d=load(file);
+		Table=d.table;
+		fprintf('loading %d tabled rows of %s from %s\n',size(Table,1),tostring(f),file);
+	end
+
+	function varargout=lookup(varargin)
+		matches=select(@(r)isequal(varargin,r(1:nin)),slices(Table,1));
+		if isempty(matches)
+			[varargout{1:nout}]=f(varargin{:});
+			Table=vertcat(Table,[varargin,varargout]);
+		else
+			varargout=col(head(matches),nin+(1:nout));
+		end
+	end
+end
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/general/funutils/@function_handle/vertcat.m	Tue Jan 29 15:59:01 2013 +0000
@@ -0,0 +1,27 @@
+% vercat - function combinator, f&g (...) = f(...); return g(...)
+%
+% and ::
+%    (A{:} => B{:}),
+%    (A{:} => C{:})
+% -> (A{:} => C{:}).
+%
+% and ::
+%    (A{1:N} => B{:}),
+%    (A{1:N} => C{1:M}),
+%    N:natural,
+%    M:natural
+% -> (A{1:N} => C{1:M}).
+function h=vercat(varargin)
+	g=varargin{end};
+	N=length(varargin)-1;
+	fx=varargin(1:N);
+	fns = { @q11, @q1n; @qn1, @qnn };
+	h=fns{acount(nargin(g),1),acount(nargout(g),1)};
+	function y=q11(x), callfx1(x); y=g(x); end
+	function y=qn1(varargin), callfxn(varargin); y=g(varargin{:}); end
+	function varargout=q1n(x), callfx1(x); [varargout{1:nargout}]=g(x); end
+	function varargout=qnn(varargin), callfxn(varargin); [varargout{1:nargout}]=g(varargin{:}); end
+
+	function callfx1(x), for i=1:N, fx{i}(x); end; end
+	function callfxn(args), for i=1:N, fx{i}(args{:}); end; end
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/general/funutils/README.txt	Tue Jan 29 15:59:01 2013 +0000
@@ -0,0 +1,42 @@
+This directory contains some tools to enable a more functional style of programming.
+
+
+The methods in the directory @function_handle apply to ordinary Matlab function 
+handles and implement an algebra of functions accessed via Matlab's numerical
+and logical operators which are normally inapplicable to function handles.
+
+	+    plus       - call two functions in parallel distributing ins and collecting outs
+	*    mtimes     - function composition
+	&    and        - call two functions and return value from 2nd
+	|    or         - call two functions and return values from both
+	[,]  horzcat    - sequence calls and collect all returns
+	[;]  vertcat    - sequence calls and return last
+	^    mpower     - unary application
+	.^   power      - application to cell array of arguments
+	/    rdivide    - bind (unary partial application)
+	./   mrdivide   - unary application (bind and call) [!!! cell input?]
+	>    gt         - select output args
+	>=   ge         - collect N output args in cell
+	<    lt         - select input args
+	<=   le         - select input args from cell array
+	~    not        - collect all output args to cell
+	'    ctranspose - flip 1st and 2nd args
+
+	[f1,f2,...,fn] == f1|f2|...|fn
+	[f1;f2;...;fn] == f1&f2&...&fn
+			f/x/y^z == f.^{x,y,z}
+
+
+ Unused operators: \  .\ .* 
+
+
+Old functions (some not functional algebraic)
+
+  bind1  - partial application, arbitrary arity
+  flip
+  apply
+  compose
+
+  doreturn(f,x,y,...) ==  feval([f<[];@deal],x,y,...)
+  nthret(I,f,x,y,...) ==  feval(f>I,x,y,...)
+  returns(N,f,x,y,...) ==  feval(f>I>=max(I), x,y, ...)
--- a/general/funutils/TODO	Mon Jan 28 10:52:11 2013 +0000
+++ b/general/funutils/TODO	Tue Jan 29 15:59:01 2013 +0000
@@ -1,4 +1,4 @@
-Think about algebra of function handles - funseq, scanner_add_plotter etc
+Think about algebra of function handles - 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?
 
--- a/general/funutils/funseq.m	Mon Jan 28 10:52:11 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/multicall.m	Mon Jan 28 10:52:11 2013 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-function varargout=multicall(varargin)
-% multicall - sequential call to several closures, return values from last
-%
-% y=do(f,g,...,h,x)
-%
-% equivalent to 
-%    f(x); g(x); ...; y=h(x); 
-
-	for i=1:length(varargin)-1
-		feval(varargin{i});
-	end
-	if nargout==0,
-		feval(varargin{end});
-	else
-		[varargout{1:nargout}]=feval(varargin{end});
-	end
-end
--- a/sequences/+seq/selector.m	Mon Jan 28 10:52:11 2013 +0000
+++ b/sequences/+seq/selector.m	Tue Jan 29 15:59:01 2013 +0000
@@ -10,7 +10,7 @@
 	methods (Static)
 		function o=make(fn,source)
 			source=dropwhile(inverse(fn),source);
-			if isempty(source), o=nil; else o=seq.selector(fn,source);
+			if isempty(source), o=nil; else o=seq.selector(fn,source); end
 		end
 	end
 	methods