function mobjtest(TOL)
%Performs numerous tests of RobustSparse math operations,
%
% mobjtest(TOL)
%
%TOL is a tolerance value on the percent error. Execution will pause in debug
%mode for inspection if any one of the tests exhibits an error greater than
%TOL.
if nargin<1
TOL=inf; %default tolerance value on discrepancies
end
CHECKTYPES=false;
%%function for measuring error
err=@(x,y) DiscrepancyMeasure(x,y,TOL,CHECKTYPES);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%TEST DATA
A=rand(3); B=rand(3)>.5;
Aobj=MatrixObj;
Aobj.Params=A;
Ops.size = [];
Ops.subsref = [];
Ops.subsasgn = [];
Ops.end = [];
Ops.subsindex = [];
Ops.colon = [];
Ops.vertcat = @(obj,Q) [obj.Params; Q];
Ops.horzcat = @(obj,Q) [obj.Params, Q];
Ops.ctranspose = @(obj) obj.Params';
Ops.transpose = @(obj) obj.Params.';
Ops.uminus = @(obj) -obj.Params;
Ops.uplus = @(obj) +obj.Params;
Ops.plus = @(obj,Q) obj.Params+Q;
Ops.minus = @(obj,Q) obj.Params-Q;
Ops.mldivide = @(obj,Q) obj.Params\Q;
Ops.mpower = @(obj,Q) obj.Params^Q;
Ops.mrdivide = @(obj,Q) obj.Params/Q;
Ops.mtimes = @(obj,Q) obj.Params*Q;
Ops.power = @(obj,Q) obj.Params.^Q;
Ops.rdivide = @(obj,Q) obj.Params./Q;
Ops.ldivide = @(obj,Q) obj.Params.\Q;
Ops.times = @(obj,Q) obj.Params.*Q;
Ops.inv = @(obj) inv(obj.Params);
Ops.sum = @mysum;
function sumval=mysum(obj,varargin)
sumval=sum(obj.Params,varargin{:});
end
Ops.gt = @(obj,Q) obj.Params>Q;
Ops.not = @(obj,Q) ~obj.Params;
Ops.eq = @(obj,Q) obj.Params==Q;
Ops.or = @(obj,Q) obj.Params|Q;
Ops.ge = @(obj,Q) obj.Params>=Q;
Ops.lt = @(obj,Q) obj.Params<Q;
Ops.le = @(obj,Q) obj.Params<=Q;
Ops.ne = @(obj,Q) obj.Params~=Q;
Ops.and = @(obj,Q) obj.Params&Q;
%%%%%%%%%%%%%%%%%%%%%%%%%%%TESTS%%%%%%%%%%%%%%%%%%%%%%%%%%
Aobj.Ops=Ops;
%%Test of uplus, uminus
Error(1)= err( +Aobj , +A );
Error(end+1)= err( -Aobj , -A );
Aobj.Ops.uplus=[]; %test default
Error(end+1)= err( +Aobj , +A );
%%Test of plus, minus
Error(end+1)= err( Aobj+B , A+B );
Error(end+1)= err( Aobj-B , A-B );
%%Test of inv
Error(end+1)= err( inv(Aobj) , inv(A) );
%%Test of sum
Error(end+1)= err( sum(Aobj) , sum(A) );
Error(end+1)= err( sum(Aobj,2) , sum(A,2) );
%%Test of mtimes
Error(end+1)= err( Aobj*3 , A*3 );
%%Test of transpose, ctranspose
Error(end+1)= err( Aobj.' , A.' );
Error(end+1)= err( Aobj' , A' );
Error(end+1)= err( (Aobj*i).' , (A*i).' );
Error(end+1)= err( (Aobj*i)' , (A*i)' );
%Test of Trans feature
Zobj=Aobj;
Zobj.Ops.transpose=@(obj) setfield(obj,'Params',obj.Params.');
Zobj.Ops.ctranspose=@(obj) setfield(obj,'Params',obj.Params');
Zobj.Trans.transpose=@(obj) -obj.Params;
Zobj.Trans.ctranspose=@(obj) -obj.Params*i;
Error(end+1)= err( (Zobj.').' , -A.' );
Error(end+1)= err( (Zobj')' , -A'*i );
%%Test of mldivide
Error(end+1)= err( Aobj\B , A\B );
%%Test of mrdivide
C=rand(size(A));
Error(end+1)= err( Aobj/C , A/C );
%%Test of times
Error(end+1)= err( Aobj.*B , A.*B );
%%Test of rdivide
Error(end+1)= err( Aobj./B , A./B );
%%Test of ldivide
Error(end+1)= err( Aobj.\B , A.\B );
%%Test of power, mpower
Error(end+1)= err( Aobj.^2 , A.^2 );
Error(end+1)= err( Aobj^2 , A^2 );
%%Test of vertcat,horzcat
Error(end+1)= err( [Aobj,B] , [A,B] );
Error(end+1)= err( [Aobj;B] , [A;B] );
%%Test of size
[aa,bb,cc]=size(A);
Aobj.Ops.size = size(A); %implement using numeric data
Error(end+1)= err( size(Aobj) , size(A) );
Error(end+1)= err( size(Aobj,1) , size(A,1) );
Error(end+1)= err( size(Aobj,2) , size(A,2) );
Error(end+1)= err( size(Aobj,3) , size(A,3) );
[aaa,bbb,ccc]=size(Aobj);
Error(end+1)= err( [aaa,bbb,ccc] , [aa,bb,cc] );
Aobj.Ops.size = @(obj) size(obj.Params); %implement using function handle
Error(end+1)= err( size(Aobj) , size(A) );
Error(end+1)= err( size(Aobj,1) , size(A,1) );
Error(end+1)= err( size(Aobj,2) , size(A,2) );
Error(end+1)= err( size(Aobj,3) , size(A,3) );
[aaa,bbb,ccc]=size(Aobj);
Error(end+1)= err( [aaa,bbb,ccc] , [aa,bb,cc] );
%%Test of subsindex
Aobj.Ops.subsindex = @(obj) find(obj.Params>.5)-1;
Error(end+1)= err( B(Aobj) , B(A>0.5) );
%%Test of colon
Aobj.Ops.colon=@(J,D,K) 1:10;
Error(end+1)= err( Aobj:1:10 , 1:10 );
Aobj.Ops.colon=@(J,K) 1:10;
Error(end+1)= err( Aobj:10 , 1:10 );
%%Test of set,get
A(1)=rand;
Aobj=set(Aobj,'Params',A);
Error(end+1)= err( get(Aobj,'Params') , A );
%%Test of relational and logical operators
Error(end+1)= err( Aobj>B , A>B );
Error(end+1)= err( Aobj>=B , A>=B );
Error(end+1)= err( Aobj<B , A<B );
Error(end+1)= err( Aobj<=B , A<=B );
Error(end+1)= err( Aobj==B , A==B );
Error(end+1)= err( Aobj~=B , A~=B );
Error(end+1)= err( Aobj|B , A|B );
Error(end+1)= err( ~Aobj , ~A );
%%Test of subsref, subsasgn, end
Tobj=Aobj;
Tobj.Ops.subsref=@mysubsref; %defined down at the bottom
Tobj.Ops.subsasgn=@mysubsasgn;%defined down at the bottom
Error(end+1)= err( Tobj(1) , A(1) );
Tobj(1)=pi; A(1)=pi;
Error(end+1)= err( Tobj.Params , A );
Error(end+1)= err( Tobj(end,1) , A(end,1) ); %test of "end"
Error(end+1)= err( Tobj(:,:,end) , A(:,:,end) );
Tobj=Aobj; Tobj.Params=A; %some resettings
Tobj.Ops.end=@(obj,kk,nn) size(A,kk); %override default "end"
Tobj.Ops.subsref=@mysubsref; %defined down at the bottom
Tobj.Ops.subsasgn=@mysubsasgn;%defined down at the bottom
Error(end+1)= err( Tobj(end,1) , A(end,1) );
Error(end+1)= err( Tobj(:,end) , A(:,end) );
Tobj(1,end)=exp(1); A(1,end)=exp(1);
Error(end+1)= err( Tobj.Params , A );
%%%%%%%%%%%%%%%%%%%%%%%TESTS - DATAOBJ SUBCLASSS%%%%%%%%%%%%%%%%%%%%%%%%%%
A=rand(3); B=rand(3)>.5;
Aobj=DataObj(A);
%%Test of uplus, uminus
Error(end+1)= err( +Aobj , +A );
Error(end+1)= err( -Aobj , -A );
Aobj.Ops.uplus=[]; %test default
Error(end+1)= err( +Aobj , +A );
%%Test of plus, minus
Error(end+1)= err( Aobj+B , A+B );
Error(end+1)= err( Aobj-B , A-B );
%%Test of inv
Error(end+1)= err( inv(Aobj) , inv(A) );
%%Test of sum
Error(end+1)= err( sum(Aobj) , sum(A) );
Error(end+1)= err( sum(Aobj,2) , sum(A,2) );
%%Test of mtimes
Error(end+1)= err( Aobj*3 , A*3 );
%%Test of transpose, ctranspose
Error(end+1)= err( Aobj.' , A.' );
Error(end+1)= err( Aobj' , A' );
Error(end+1)= err( (Aobj*i).' , (A*i).' );
Error(end+1)= err( (Aobj*i)' , (A*i)' );
%Test of Trans feature
Zobj=Aobj;
Zobj.Trans.transpose=@(Data) -Data;
Zobj.Trans.ctranspose=@(Data) -Data*i;
Error(end+1)= err( (Zobj.').' , -A.' );
Error(end+1)= err( (Zobj')' , -A'*i );
%%Test of mldivide
Error(end+1)= err( Aobj\B , A\B );
%%Test of mrdivide
C=rand(size(A));
Error(end+1)= err( Aobj/C , A/C );
%%Test of times
Error(end+1)= err( Aobj.*B , A.*B );
%%Test of rdivide
Error(end+1)= err( Aobj./B , A./B );
%%Test of ldivide
Error(end+1)= err( Aobj.\B , A.\B );
%%Test of power, mpower
Error(end+1)= err( Aobj.^2 , A.^2 );
Error(end+1)= err( Aobj^2 , A^2 );
%%Test of vertcat,horzcat
Error(end+1)= err( [Aobj,B] , [A,B] );
Error(end+1)= err( [Aobj;B] , [A;B] );
%%Test of size
[aa,bb,cc]=size(A);
Aobj.Ops.size = size(A); %implement using numeric data
Error(end+1)= err( size(Aobj) , size(A) );
Error(end+1)= err( size(Aobj,1) , size(A,1) );
Error(end+1)= err( size(Aobj,2) , size(A,2) );
Error(end+1)= err( size(Aobj,3) , size(A,3) );
[aaa,bbb,ccc]=size(Aobj);
Error(end+1)= err( [aaa,bbb,ccc] , [aa,bb,cc] );
Aobj.Ops.size = @(obj) size(obj); %implement using function handle
Error(end+1)= err( size(Aobj) , size(A) );
Error(end+1)= err( size(Aobj,1) , size(A,1) );
Error(end+1)= err( size(Aobj,2) , size(A,2) );
Error(end+1)= err( size(Aobj,3) , size(A,3) );
[aaa,bbb,ccc]=size(Aobj);
Error(end+1)= err( [aaa,bbb,ccc] , [aa,bb,cc] );
%%Test of subsindex
Aobj.Ops.subsindex = @(obj) find(obj>.5)-1;
Error(end+1)= err( B(Aobj) , B(A>0.5) );
%%Test of colon
Aobj.Ops.colon=@(J,D,K) 1:10;
Error(end+1)= err( Aobj:1:10 , 1:10 );
Aobj.Ops.colon=@(J,K) 1:10;
Error(end+1)= err( Aobj:10 , 1:10 );
%%Test of set,get
A(1)=rand;
Aobj=set(Aobj,'Params',A);
Error(end+1)= err( get(Aobj,'Params') , A );
%%Test of relational and logical operators
Error(end+1)= err( Aobj>B , A>B );
Error(end+1)= err( Aobj>=B , A>=B );
Error(end+1)= err( Aobj<B , A<B );
Error(end+1)= err( Aobj<=B , A<=B );
Error(end+1)= err( Aobj==B , A==B );
Error(end+1)= err( Aobj~=B , A~=B );
Error(end+1)= err( Aobj|B , A|B );
Error(end+1)= err( ~Aobj , ~A );
%%Test of subsref, subsasgn, end
Tobj=Aobj; A=Aobj.Data; %some resettings
Tobj.Ops.subsref=@Psubsref; %defined down at the bottom
Tobj.Ops.subsasgn=@Psubsasgn;%defined down at the bottom
Error(end+1)= err( Tobj(1) , A(1) );
Tobj(1)=pi; A(1)=pi;
Error(end+1)= err( Tobj , A );
Error(end+1)= err( Tobj(end,1) , A(end,1) ); %test of "end"
Error(end+1)= err( Tobj(:,:,end) , A(:,:,end) );
Tobj=Aobj; A=Aobj.Data; %some resettings
Tobj.Ops.end=@(obj,kk,nn) size(A,kk); %override default "end"
Tobj.Ops.subsref=@Psubsref; %defined down at the bottom
Tobj.Ops.subsasgn=@Psubsasgn;%defined down at the bottom
Error(end+1)= err( Tobj(end,1) , A(end,1) );
Error(end+1)= err( Tobj(:,end) , A(:,end) );
Tobj(1,end)=exp(1); A(1,end)=exp(1);
Error(end+1)= err( Tobj , A );
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%END TESTS%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
MAX_ERROR=max(Error);
disp(['Maximum observed error was ' num2str(MAX_ERROR) ' percent.'])
end
function errval=DiscrepancyMeasure(X,Y,TOL,CHECKTYPES)
if isa(X,'DataObj'), X=X.Data; end
if isa(Y,'DataObj'), Y=Y.Data; end
errval=Discrepancy(X,Y)/Discrepancy(0,Y)*100; %normalize
if errval>TOL,
disp ' '; disp 'Discrepancy detected'
errval,
x=myfull(X); y=myfull(Y);
keyboard;
end
end
function errval=Discrepancy(X,Y)
%Primary error measurement function
fin=@(a) a(isfinite(a));
nonfin=@(a) a(~isfinite(a));
x=myfull(X); y=myfull(Y);
errval= norm( fin(x-y) , inf)+...
~isequalwithequalnans(nonfin(x),nonfin(y))*...
~isempty([nonfin(x);nonfin(y)]);
end
function A=myfull(A)
if isa(A,'MatrixObj')
A=A.Params;
else
A=full(A);
end
end
function out=mysubsref(obj,S)
switch S.type
case '.'
out=get(obj,S.subs);
otherwise
Params=get(obj,'Params');
out=Params(S.subs{:});
end
end
function out=mysubsasgn(obj,S,rhs)
switch S.type
case '.'
out=set(obj,S.subs,rhs);
otherwise
Params=get(obj,'Params');
Params(S.subs{:})=rhs;
out=set(obj,'Params',Params);
end
end
function out=Psubsref(X,S)
out=X(S.subs{:});
end
function X=Psubsasgn(X,S,rhs)
X(S.subs{:})=rhs;
end