% vecgen - Finite vector generator base class

classdef vec
	properties (SetAccess=private,GetAccess=private)
		fillfn  % N:natural -> [[N]]
		label % string
	end
	methods (Sealed)
		function o=vec(fillfn,label), 
			o.fillfn=fillfn; 
			if nargin<2, o.label=tostring(fillfn); 
			else o.label=label;  end
		end
		function x=fill(o,N),    x=o.fillfn(N); end
		function display(o),     disp(['   ' tostring(o) ' :: vec']); end
		function s=tostring(o),  s=o.label; end
		function c=log(a),       c=apply(@log,a); end
		function c=log2(a),      c=apply(@log2,a); end
		function c=log10(a),     c=apply(@log10,a); end
		function c=exp(a),       c=apply(@exp,a); end
		function c=sqrt(a),      c=apply(@sqrt,a); end
		function c=uminus(a),    c=unop(@uminus,a,str.prefix('-')); end
		function c=not(a),       c=unop(@not,a,str.prefix('~')); end
		function c=mtimes(a,b),  c=binop(@times,a,b,str.infix('*')); end
		function c=mrdivide(a,b),c=binop(@rdivide,a,b,str.infix('/')); end
		function c=plus(a,b),    c=binop(@plus,a,b,str.infix('+')); end
		function c=minus(a,b),   c=binop(@minus,a,b,str.infix('-')); end
		function c=eq(a,b),      c=binop(@eq*@double,a,b,str.infix('==')); end
		function c=lt(a,b),      c=binop(@lt,a,b,str.infix('<')); end
		function c=le(a,b),      c=binop(@le,a,b,str.infix('<=')); end
		function c=gt(a,b),      c=binop(@gt,a,b,str.infix('>')); end
		function c=ge(a,b),      c=binop(@ge,a,b,str.infix('>=')); end
		function c=ne(a,b),      c=binop(@ne,a,b,str.infix('=')); end
		function c=or(a,b),      c=binop(@or,a,b,str.infix('|')); end
		function c=and(a,b),     c=binop(@and,a,b,str.infix('&')); end

		function o=apply(f,o), o=unop(f,o,str.functor(func2str(f))); end
	end
end

function v=unop(op,src,rep) 
	v=vec(@(N)op(src.fill(N)), rep(tostring(src))); 
end

function c=binop(op,a,b,rep)
	if isa(a,'vec') && isa(b,'vec')
		c=zipper(op,rep,a,b);
	elseif isa(a,'vec'),
		c=unop(@(A)op(A,b),a,@(A)rep(A,tostring(b)));
	else
		c=unop(@(B)op(a,B),b,@(B)rep(tostring(a),B));
	end
end

function v=zipper(op,rep,varargin)
	strs=map(@tostring,varargin);
	v=vec(@f, rep(strs{:}));
	function x=f(N), yx=map(@(s)fill(s,N),varargin); x=op(yx{:}); end
end
