Skip to content

Commit

Permalink
adding support to _ArrayShape_ to record special matrices
Browse files Browse the repository at this point in the history
  • Loading branch information
fangq committed May 31, 2020
1 parent d88d454 commit fc0b285
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 9 deletions.
27 changes: 27 additions & 0 deletions examples/demo_jsonlab_basic.m
Expand Up @@ -366,6 +366,33 @@
json2data=loadjson(ans)
end

if(exist('bandwidth'))
fprintf(1,'\n%%=================================================\n')
fprintf(1,'%% use _ArrayShape_ \n')
fprintf(1,'%%=================================================\n\n')

lband=2;
uband=3;
data2json=spdiags(true(8,lband+uband+1),-uband:lband,5,8);
data2json=full(double(data2json));
data2json(data2json~=0)=find(data2json)

savejson('',data2json,'usearrayshape',1)
json2data=loadjson(ans,'fullarrayshape',1)

savejson('',tril(data2json),'usearrayshape',1)
json2data=loadjson(ans,'fullarrayshape',1)

savejson('',triu(data2json+1i*data2json),'usearrayshape',1)
json2data=loadjson(ans,'fullarrayshape',1)

savejson('',tril(triu(int8(data2json))),'usearrayshape',1)
json2data=loadjson(ans,'fullarrayshape',1)

savejson('',data2json(:,1:5)+data2json(:,1:5)','usearrayshape',1)
json2data=loadjson(ans,'fullarrayshape',1)
end

try
val=zlibencode('test');
fprintf(1,'\n%%=================================================\n')
Expand Down
82 changes: 78 additions & 4 deletions jdatadecode.m
Expand Up @@ -33,6 +33,8 @@
% jsondecode(), the prefix is 'x'; this function
% attempts to automatically determine the prefix;
% for octave, the default value is an empty string ''.
% FullArrayShape: [0|1] if set to 1, converting _ArrayShape_
% objects to full matrices, otherwise, stay sparse
% FormatVersion: [2|float]: set the JSONLab output version;
% since v2.0, JSONLab uses JData specification Draft 1
% for output format, it is incompatible with all
Expand Down Expand Up @@ -61,6 +63,7 @@
elseif(nargin>2)
opt=varargin2struct(varargin{:});
end
opt.fullarrayshape=jsonopt('FullArrayShape',0,opt);

%% process non-structure inputs
if(~isstruct(data))
Expand Down Expand Up @@ -128,6 +131,9 @@
error('compression method is not supported');
end
else
if(isstruct(data(j).(N_('_ArrayData_'))) && isfield(data(j).(N_('_ArrayData_')),N_('_ArrayType_')))
data(j).(N_('_ArrayData_'))=jdatadecode(data(j).(N_('_ArrayData_')),varargin{:});
end
if(iscell(data(j).(N_('_ArrayData_'))))
data(j).(N_('_ArrayData_'))=cell2mat(cellfun(@(x) double(x(:)),data(j).(N_('_ArrayData_')),'uniformoutput',0)).';
end
Expand All @@ -142,10 +148,8 @@
ndata=permute(ndata,ndims(ndata):-1:1);
end
iscpx=0;
if(isfield(data,N_('_ArrayIsComplex_')))
if(data(j).(N_('_ArrayIsComplex_')))
iscpx=1;
end
if(isfield(data,N_('_ArrayIsComplex_')) && data(j).(N_('_ArrayIsComplex_')) )
iscpx=1;
end
if(isfield(data,N_('_ArrayIsSparse_')) && data(j).(N_('_ArrayIsSparse_')))
if(isfield(data,N_('_ArraySize_')))
Expand Down Expand Up @@ -175,6 +179,76 @@
end
ndata=sparse(ndata(1,:),ndata(2,:),ndata(3,:));
end
elseif(isfield(data,N_('_ArrayShape_')))
if(iscpx)
if(size(ndata,1)==2)
dim=size(ndata);
dim(end+1)=1;
arraydata=reshape(complex(ndata(1,:),ndata(2,:)),dim(2:end)).';
else
error('The first dimension must be 2 for complex-valued arrays');
end
else
arraydata=data.(N_('_ArrayData_'));
end
shapeid=data.(N_('_ArrayShape_'));
if(isfield(data,N_('_ArrayZipSize_')))
datasize=data.(N_('_ArrayZipSize_'));
if(iscpx)
datasize=datasize(2:end);
end
else
datasize=size(arraydata);
end
arraysize=data.(N_('_ArraySize_'));
if(ischar(shapeid))
shapeid={shapeid};
end
if(strcmp(shapeid{1},'diag'))
ndata=spdiags(arraydata(:),0,arraysize(1),arraysize(2));
elseif(strcmp(shapeid{1},'upper') || strcmp(shapeid{1},'uppersymm'))
ndata=zeros(arraysize);
ndata(triu(true(size(ndata)))')=arraydata(:);
if(strcmp(shapeid{1},'uppersymm'))
ndata(triu(true(size(ndata))))=arraydata(:);
end
ndata=ndata.';
elseif(strcmp(shapeid{1},'lower') || strcmp(shapeid{1},'lowersymm'))
ndata=zeros(arraysize);
ndata(tril(true(size(ndata)))')=arraydata(:);
if(strcmp(shapeid{1},'lowersymm'))
ndata(tril(true(size(ndata))))=arraydata(:);
end
ndata=ndata.';
elseif(strcmp(shapeid{1},'upperband') || strcmp(shapeid{1},'uppersymmband'))
if(length(shapeid)>1 && isvector(arraydata))
datasize=[shapeid{2}+1, prod(datasize)/(shapeid{2}+1)];
end
ndata=spdiags(reshape(arraydata,min(arraysize),datasize(1)),-datasize(1)+1:0,arraysize(2),arraysize(1)).';
if(strcmp(shapeid{1},'uppersymmband'))
diagonal=diag(ndata);
ndata=ndata+ndata.';
ndata(1:arraysize(1)+1:end)=diagonal;
end
elseif(strcmp(shapeid{1},'lowerband') || strcmp(shapeid{1},'lowersymmband'))
if(length(shapeid)>1 && isvector(arraydata))
datasize=[shapeid{2}+1, prod(datasize)/(shapeid{2}+1)];
end
ndata=spdiags(reshape(arraydata,min(arraysize),datasize(1)),0:datasize(1)-1,arraysize(2),arraysize(1)).';
if(strcmp(shapeid{1},'lowersymmband'))
diagonal=diag(ndata);
ndata=ndata+ndata.';
ndata(1:arraysize(1)+1:end)=diagonal;
end
elseif(strcmp(shapeid{1},'band'))
if(length(shapeid)>1 && isvector(arraydata))
datasize=[shapeid{2}+shapeid{3}+1, prod(datasize)/(shapeid{2}+shapeid{3}+1)];
end
ndata=spdiags(reshape(arraydata,min(arraysize),datasize(1)),shapeid{2}:-1:-shapeid{3},arraysize(1),arraysize(2));
end
if(opt.fullarrayshape && issparse(ndata))
ndata=cast(full(ndata),data(j).(N_('_ArrayType_')));
end
elseif(isfield(data,N_('_ArraySize_')))
if(iscpx)
ndata=complex(ndata(1,:),ndata(2,:));
Expand Down
72 changes: 67 additions & 5 deletions jdataencode.m
Expand Up @@ -32,6 +32,9 @@
% the original data stored in _ArrayData_, and then flaten
% _ArrayData_ into a row vector using row-major
% order; if set to 0, a 2D _ArrayData_ will be used
% UseArrayShape: [0|1] if set to 1, a matrix will be tested by
% to determine if it is diagonal, triangular, banded or
% toeplitz, and use _ArrayShape_ to encode the matrix
% MapAsStruct: [0|1] if set to 1, convert containers.Map into
% struct; otherwise, keep it as map
% Compression: ['zlib'|'gzip','lzma','lz4','lz4hc'] - use zlib method
Expand Down Expand Up @@ -73,6 +76,7 @@
opt.mapasstruct=jsonopt('MapAsStruct',0,opt);
opt.usearrayzipsize=jsonopt('UseArrayZipSize',1,opt);
opt.messagepack=jsonopt('MessagePack',0,opt);
opt.usearrayshape=jsonopt('UseArrayShape',0,opt) && exist('bandwidth');

jdata=obj2jd(data,opt);

Expand Down Expand Up @@ -156,12 +160,72 @@
%%-------------------------------------------------------------------------
function newitem=mat2jd(item,varargin)

N=@(x) N_(x,varargin{:});

% no encoding for char arrays or non-sparse real vectors
if(isempty(item) || isa(item,'string') || ischar(item) || varargin{1}.nestarray || ...
((isvector(item) || ndims(item)==2) && isreal(item) && ~issparse(item)))
(isvector(item) && isreal(item) && ~issparse(item)))
newitem=item;
if(~(varargin{1}.messagepack && size(item,1)>1))
return;
return;
% 2d numerical (real/complex/sparse) arrays with _ArrayShape_ encoding enabled
elseif(varargin{1}.usearrayshape && ndims(item)==2 && ~isvector(item))
newitem=struct(N('_ArrayType_'),class(item),N('_ArraySize_'),size(item));
newitem.(N('_ArrayIsComplex_'))=~isreal(item);
symmtag='';
if(isreal(item) && issymmetric(double(item)))
symmtag='symm';
item=tril(item);
elseif(~isreal(item) && ishermitian(double(item)))
symmtag='herm';
item=tril(item);
end
[lband,uband]=bandwidth(double(item));
newitem.(N('_ArrayZipSize_'))=[lband+uband+1, min(size(item,1),size(item,2))];
if(lband+uband==0) % isdiag
newitem.(N('_ArrayShape_'))='diag';
newitem.(N('_ArrayData_'))=diag(item).';
elseif(uband==0 && lband==size(item,1)-1) % lower triangular
newitem.(N('_ArrayShape_'))=['lower' symmtag];
item=item.';
newitem.(N('_ArrayData_'))=item(triu(true(size(item)))).';
elseif(lband==0 && uband==size(item,2)-1) % upper triangular
newitem.(N('_ArrayShape_'))='upper';
item=item.';
newitem.(N('_ArrayData_'))=item(tril(true(size(item)))).';
elseif(lband==0) % upper band
newitem.(N('_ArrayShape_'))={'upperband',uband};
newitem.(N('_ArrayData_'))=spdiags(item.',-uband:lband).';
elseif(uband==0) % lower band
newitem.(N('_ArrayShape_'))={sprintf('lower%sband',symmtag),lband};
newitem.(N('_ArrayData_'))=spdiags(item.',-uband:lband).';
elseif(uband<size(item,2)-1 || lband<size(item,1)-1) % band
newitem.(N('_ArrayShape_'))={'band',uband,lband};
newitem.(N('_ArrayData_'))=spdiags(item.',-uband:lband).';
else % full matrix
newitem=item;
end

% serialize complex data at last
if(isstruct(newitem) && ~isreal(newitem.(N('_ArrayData_'))))
item=squeeze(zeros([2, size(newitem.(N('_ArrayData_')))]));
item(1,:)=real(newitem.(N('_ArrayData_'))(:));
item(2,:)=imag(newitem.(N('_ArrayData_'))(:));
newitem.(N('_ArrayZipSize_'))=size(item);
newitem.(N('_ArrayData_'))=item;
end

% wrap _ArrayData_ into a single row vector, and store preprocessed
% size to _ArrayZipSize_ (force varargin{1}.usearrayzipsize=true)
if(isstruct(newitem) && ~isvector(newitem.(N('_ArrayData_'))))
item=newitem.(N('_ArrayData_'));
item=permute(item,ndims(item):-1:1);
newitem.(N('_ArrayData_'))=item(:).';
else
newitem=rmfield(newitem,N('_ArrayZipSize_'));
end

newitem.(N('_ArrayData_'))=full(newitem.(N('_ArrayData_')));
return;
end

zipmethod=varargin{1}.compression;
Expand All @@ -171,8 +235,6 @@
item=uint8(item);
end

N=@(x) N_(x,varargin{:});

newitem=struct(N('_ArrayType_'),class(item),N('_ArraySize_'),size(item));

if(isreal(item))
Expand Down

0 comments on commit fc0b285

Please sign in to comment.