classdef ZeroBased
%ZeroBased - a class of arrays like MATLAB normal arrays, but can be indexed
%starting from 0.
%
%USAGE:
%
% A=ZeroBased(B)
%
%where B is a normal MATLAB matrix will cast B to A, which is exactly
%the same, except that it is 0-based indexed instead of 1-based.
%
%
%EXAMPLE 1:
%
% >>A=ZeroBased(rand(3))
%
% A =
%
% 0.7922 0.0357 0.6787
% 0.9595 0.8491 0.7577
% 0.6557 0.9340 0.7431
%
% >>A(0,2)
%
% ans =
%
% 0.6787
%
%EXAMPLE 2:
%
%It works for sparse matrices too, and will even display at the command line
%with zero-based indexing display syntax, e.g.,
%
% >> A=ZeroBased(speye(3))
%
% A =
%
% (0,0) 1
% (1,1) 1
% (2,2) 1
%
%
%by Matt Jacobson
properties
data;
%classname;
end
methods
function obj=ZeroBased(data)
%constructor for ZeroBased
obj.data=data;
%obj.classname=class(data);
end
function varargout=size(obj,varargin)
[varargout{1:nargout}] = size( obj.data , varargin{:});
end
function objnew=subsref(obj,S)
%SUBSREF for ZeroBased class
nn=length(S.subs);
for ii=1:nn
if ~(ischar(S.subs{ii})|| islogical(S.subs{ii})),
S.subs{ii}=S.subs{ii}+1;
end
end
objnew=ZeroBased(builtin('subsref',obj.data,S));
end
function obj=subsasgn(obj,S,rhs)
%SUBSASGN for ZeroBased class
nn=length(S.subs);
for ii=1:nn
if ~(ischar(S.subs{ii})||islogical(S.subs{ii})),
S.subs{ii}=S.subs{ii}+1;
end
end
obj.data=builtin('subsasgn',obj.data,S,rhs);
end
function E=end(obj,K,N)
E=builtin('end',obj.data,K,N)-1;
end
function I=subsindex(obj)
I=double(obj.data-1);
end
function I=colon(varargin)
varargin=recastCell(varargin);
I=ZeroBased(colon(varargin{:}));
end
function varargout=find(obj,varargin)
[varargout{1:nargout}]=find(obj.data,varargin{:});
for ii=1:min(2,nargout)
varargout{ii}=varargout{ii}-1;
end
end
function display(obj)
l=inputname(1);
T=evalc('obj.data'); %only way to get at the builtin display method
if ~isempty(l),
T=strrep(T,'ans =',[l ' =']);
end
jj=find(T~=sprintf('\n'),1,'last');
T=T(1:jj);
if issparse(obj)
Delimiters={'\((\d*),', ',(\d*)\)'};
str=Delimiters{1};
[tokens,starts]=regexp(T,str,'tokens','start');
Indices1Based=cellfun(@(x) x{1}, tokens, 'uni', 0);
Indices0Based=cellfun(...
@(i) num2str(str2double(i)-1), Indices1Based, 'uni', 0);
for ii=1:length(Indices1Based)
st=starts(ii);
len1=length(Indices1Based{ii});
len0=length(Indices0Based{ii});
ub=st+len1;
lb=ub-len0+1;
T(st+1:ub)=' ';
T(lb:ub)=Indices0Based{ii};
if len0<len1, T(st:st+1)=fliplr(T(st:st+1)); end
end
str=Delimiters{2};
[tokens,starts]=regexp(T,str,'tokens','start');
Indices1Based=cellfun(@(x) x{1}, tokens, 'uni', 0);
Indices0Based=cellfun(...
@(i) num2str(str2double(i)-1), Indices1Based, 'uni', 0);
for ii=1:length(Indices1Based)
st=starts(ii);
len1=length(Indices1Based{ii});
len0=length(Indices0Based{ii});
ub=st+len0;
lb=st+1;
T(st+1:st+len1)=' ';
T(lb:ub)=Indices0Based{ii};
if len0<len1, T(ub+1:ub+2)=fliplr(T(ub+1:ub+2)); end
end
elseif iscell(obj) || isnumeric(obj) || islogical(obj) %%Fix the Column labels
Delimiters={'Columns (\d*) ', 'through (\d*)\s', 'Column (\d*)\s'};
for kk=1:length(Delimiters)
str=Delimiters{kk};
[tokens,tokenExtents]=regexp(T,str,'tokens','tokenExtents');
Indices1Based=cellfun(@(x) x{1}, tokens, 'uni', 0);
Indices0Based=cellfun(...
@(i) num2str(str2double(i)-1), Indices1Based, 'uni', 0);
for ii=1:length(Indices1Based)
len0=length(Indices0Based{ii});
ub=tokenExtents{ii}(2);
lb=tokenExtents{ii}(1);
T(lb:ub)=' ';
T(lb:lb+len0-1)=Indices0Based{ii};
end
end
end
disp(T), disp ' '
end
%%Unary ops
function obj=uplus(obj)
end
function obj=uminus(obj)
obj.data=-obj.data;
end
function obj=not(obj)
obj.data = ~obj.data ;
end
%%Binary ops
function obj=plus(L,R)
obj = ZeroBased( recast(L) + recast(R));
end
function obj=minus(L,R)
obj = ZeroBased( recast(L) - recast(R));
end
function obj=times(L,R)
obj = ZeroBased( recast(L) .* recast(R));
end
function obj=rdivide(L,R)
obj = ZeroBased( recast(L) ./ recast(R), s);
end
function obj=ldivide(L,R)
obj = ZeroBased( recast(L) .\ recast(R));
end
function obj=power(L,R)
obj = ZeroBased( recast(L) .^ recast(R));
end
function obj=lt(L,R)
obj = ZeroBased( recast(L) < recast(R));
end
function obj=le(L,R)
obj = ZeroBased( recast(L) <= recast(R));
end
function obj=gt(L,R)
obj = ZeroBased( recast(L) > recast(R));
end
function obj=ge(L,R)
obj = ZeroBased( recast(L) >= recast(R));
end
function obj=eq(L,R)
obj = ZeroBased( recast(L) == recast(R));
end
function obj=ne(L,R)
obj = ZeroBased( recast(L) ~= recast(R));
end
function obj=and(L,R)
obj = ZeroBased( recast(L) & recast(R));
end
function obj=or(L,R)
obj = ZeroBased( recast(L) | recast(R));
end
%%Methods for 2D Matrices
function obj=inv(obj)
obj = ZeroBased(inv(recast(obj)));
end
function obj=triu(obj,varargin)
obj = ZeroBased( triu( recast(obj) , varargin{:} ) );
end
function obj=tril(obj,varargin)
obj = ZeroBased( tril( recast(obj) , varargin{:} ));
end
function obj=transpose(obj)
obj.data=obj.data.';
end
function obj=ctranspose(obj)
obj.data=obj.data';
end
function obj=mtimes(L,R)
obj = ZeroBased( recast(L)*recast(R));
end
function obj=mrdivide(L,R)
obj = ZeroBased( recast(L)/recast(R));
end
function obj=mldivide(L,R)
obj = ZeroBased( recast(L)\recast(R));
end
function obj=mpower(L,R)
obj = ZeroBased( recast(L)^recast(R));
end
function obj=sum(obj,varargin)
obj.data = sum( obj.data , varargin{:});
end
function obj=prod(obj,varargin)
obj.data = prod( obj.data , varargin{:});
end
function obj=mean(obj,varargin)
obj.data = mean( obj.data , varargin{:});
end
function obj=permute(obj,varargin)
obj.data = permute( obj.data , varargin{:});
end
function obj=ipermute(obj,varargin)
obj.data = ipermute( obj.data , varargin{:});
end
function obj=abs(obj)
obj.data = abs( obj.data);
end
function obj=all(obj,varargin)
obj.data = all( obj.data , varargin{:});
end
function obj=any(obj,varargin)
obj.data = any( obj.data , varargin{:});
end
function obj=circshift(obj,varargin)
obj.data = circshift( obj.data , varargin{:});
end
function obj=conj(obj,varargin)
obj.data = conj( obj.data , varargin{:});
end
function Z=conv(varargin)
varargin=recastCell(varargin);
Z = ZeroBased(conv(varargin{:}));
end
function Z=conv2(varargin)
varargin=recastCell(varargin);
Z = ZeroBased(conv2(varargin{:}));
end
function Z=convn(varargin)
varargin=recastCell(varargin);
Z = ZeroBased(convn(varargin{:}));
end
function Z=fft(varargin)
varargin=recastCell(varargin);
Z = ZeroBased(fft(varargin{:}));
end
function Z=fft2(varargin)
varargin=recastCell(varargin);
Z = ZeroBased(fft2(varargin{:}));
end
function Z=fftn(varargin)
varargin=recastCell(varargin);
Z = ZeroBased(fftn(varargin{:}));
end
function Z=bsxfun(varargin)
varargin=recastCell(varargin);
Z = ZeroBased(bsxfun(varargin{:}));
end
function Z=cat(varargin)
varargin=recastCell(varargin);
Z = ZeroBased(cat(varargin{:}));
end
function Z=horzcat(varargin)
varargin=recastCell(varargin);
Z = ZeroBased(horzcat(varargin{:}));
end
function Z=vertcat(varargin)
varargin=recastCell(varargin);
Z = ZeroBased(horzcat(varargin{:}));
end
function out=double(obj)
out=double(obj.data);
end
function out=logical(obj)
out=logical(obj.data);
end
function out=sparse(obj)
out=sparse(obj.data);
end
function out=single(obj)
out=single(obj.data);
end
function obj=flipdim(obj)
obj.data=flipdim(obj.data);
end
function obj=fliplr(obj)
obj.data=fliplr(obj.data);
end
function obj=flipud(obj)
obj.data=flipud(obj.data);
end
function obj=full(obj)
obj.data=full(obj.data);
end
function obj=imag(obj)
obj.data=imag(obj.data);
end
function obj=real(obj)
obj.data=real(obj.data);
end
function Z=isequal(varargin)
varargin=recastCell(varargin);
Z = ZeroBased(isequal(varargin{:}));
end
function Z=isequalwithequalnans(varargin)
varargin=recastCell(varargin);
Z = ZeroBased(isequalwithequalnans(varargin{:}));
end
function obj=isempty(obj)
obj.data=isempty(obj.data);
end
function obj=isreal(obj)
obj.data=isreal(obj.data);
end
function obj=issparse(obj)
obj.data=issparse(obj.data);
end
function obj=isfinite(obj)
obj.data=isfinite(obj.data);
end
function obj=isinf(obj)
obj.data=isinf(obj.data);
end
function obj=islogical(obj)
obj.data=islogical(obj.data);
end
function obj=isfloat(obj)
obj.data=isfloat(obj.data);
end
function obj=isnan(obj)
obj.data=isnan(obj.data);
end
function obj=isnumeric(obj)
obj.data=isnumeric(obj.data);
end
function obj=length(obj)
obj.data=length(obj.data);
end
function obj=loadobj(obj)
obj=ZeroBased(obj.data);
end
function [varargout]=max(obj,varargin)
[varargout{1:nargout}]=max(obj.data,varargin{:});
if nargout>1, varargout{2}=varargout{2}-1; end
varargout=cellfun(@(c) ZeroBased(c), varargout,'uni',0);
end
function [varargout]=min(obj,varargin)
[varargout{1:nargout}]=min(obj.data,varargin{:});
if nargout>1, varargout{2}=varargout{2}-1; end
varargout=cellfun(@(c) ZeroBased(c), varargout,'uni',0);
end
function obj=ndims(obj)
obj.data=ndims(obj.data);
end
function obj=nnz(obj)
obj.data=nnz(obj.data);
end
function obj=nonzeros(obj)
obj.data=nonzeros(obj.data);
end
function obj=numel(obj)
obj.data=numel(obj.data);
end
function obj=nzmax(obj,varargin)
obj.data=nzmax(obj.data,varargin{:});
end
function obj=repmat(obj,varargin)
obj.data=repmat(obj.data,varargin{:});
end
function obj=reshape(obj,varargin)
obj.data=reshape(obj.data,varargin{:});
end
function obj=rot90(obj,varargin)
obj.data=rot90(obj.data,varargin{:});
end
function obj=sqrt(obj)
obj.data=sqrt(obj.data);
end
function obj=squeeze(obj)
obj.data=squeeze(obj.data);
end
function [varargout]=shiftdim(obj,varargin)
[varargout{1:nargout}]=shiftdim(obj.data,varargin{:});
if nargout>1, varargout{2}=varargout{2}-1; end
varargout=cellfun(@(c) ZeroBased(c), varargout,'uni',0);
end
end
end
function out=recast(in)
if isa(in,'ZeroBased')
out=in.data;
else
out=in;
end
% if isa(in,'ZeroBased')
% out=in.data;
% elseif isscalar(in)
% out=in;
% else
% error 'Mixed operations involving ZeroBased array and ordinary 1-based non-scalar arrays are forbidden.'
% end
end
function outcell=recastCell(incell)
map=cellfun('isclass',incell,'ZeroBased' );
incell(map)=cellfun(@(c) c.data,incell(map), 'uni',0);
outcell=incell;
end