MatrixBerryCore
ismemberjointwithnulls.m
Go to the documentation of this file.
1 function [isMemberVec,indMemberVec]=ismemberjointwithnulls(leftCVec,leftIsNullCVec,rightCVec,rightIsNullCVec,dim)
2 import mxberry.core.check.*;
3 import mxberry.core.ismemberjoint;
4 import mxberry.core.throwerror;
5 import mxberry.core.uniquejoint;
6 %% initial actions
7 if nargin<4||nargin>5
8  throwerror('wrongInput','Incorrect number of input arguments');
9 end
10 checkgen(leftCVec,'iscell(x)');
11 checkgen(leftIsNullCVec,['iscell(x)&&isequal(size(x),' ...
12  mat2str(size(leftCVec)) ')']);
13 checkgen(rightCVec,'iscell(x)');
14 checkgen(rightIsNullCVec,['iscell(x)&&isequal(size(x),' ...
15  mat2str(size(rightCVec)) ')']);
16 nElems=numel(leftCVec);
17 %
18 if nElems==0
19  throwerror('wrongInput',...
20  'First four arguments should be non-empty cell arrays');
21 end
22 checkgen(rightCVec,['numel(x)==' num2str(nElems)]);
23 %
24 if nargin<5
25  dim=1;
26 else
27  checkgen(dim,'isnumeric(x)&&numel(x)==1');
28  dim=double(dim);
29  checkgen(dim,'isreal(x)&&floor(x)==x&&x>=1&&isfinite(x)');
30 end
31 %
32 leftCVec=leftCVec(:);
33 leftIsNullCVec=leftIsNullCVec(:);
34 rightCVec=rightCVec(:);
35 rightIsNullCVec=rightIsNullCVec(:);
36 checkgen(leftIsNullCVec,'all(cellfun(''islogical'',x))');
37 checkgen(rightIsNullCVec,'all(cellfun(''islogical'',x))');
38 nDimsCVec=cellfun('ndims',leftIsNullCVec);
39 nMaxDims=max(max(nDimsCVec),dim);
40 isDecrDims=nDimsCVec==2;
41 isDecrDims(isDecrDims)=cellfun('size',leftIsNullCVec(isDecrDims),2)==1;
42 nDimsCVec(isDecrDims)=1;
43 nDimsCVec=num2cell(max(nDimsCVec,dim));
44 isPerm=dim>1;
45 if isPerm
46  permIndVec=[dim 1:dim-1 dim+1:nMaxDims];
47 end
48 [nLeftElem,leftSizeCVec,leftIsNullSizeCVec,...
49  leftCVec,leftIsNullCVec,isnLeftValueVec]=...
51  'left',leftCVec,leftIsNullCVec,nDimsCVec,false(nElems,1));
52 [nRightElem,rightSizeCVec,rightIsNullSizeCVec,...
53  rightCVec,rightIsNullCVec,isnRightValueVec]=...
55  'right',rightCVec,rightIsNullCVec,nDimsCVec,isnLeftValueVec);
56 if isPerm
57  isMemberVec=false(1,nLeftElem);
58  indMemberVec=zeros(1,nLeftElem);
59 else
60  isMemberVec=false(nLeftElem,1);
61  indMemberVec=zeros(nLeftElem,1);
62 end
63 if ~isequal(leftIsNullSizeCVec,rightIsNullSizeCVec)
64  throwerror('wrongInput',...
65  'leftIsNullCVec and rightIsNullCVec are not consistent in size');
66 end
67 if nLeftElem==0||nRightElem==0
68  return;
69 end
70 if all(isnLeftValueVec)
71  rightIsNullMat=all(horzcat(rightIsNullCVec{:}),2);
72  indLeft2RightNullVec=find(rightIsNullMat,1,'last');
73  if ~isempty(indLeft2RightNullVec)
74  isMemberVec(:)=true;
75  indMemberVec(:)=indLeft2RightNullVec;
76  end
77  return;
78 elseif all(isnRightValueVec)
79  leftIsNullMat=all(horzcat(leftIsNullCVec{:}),2);
80  isMemberVec(:)=leftIsNullMat;
81  indMemberVec(leftIsNullMat)=nRightElem;
82  return;
83 end
84 isnSizeVec=~(isnLeftValueVec|isnRightValueVec);
85 if any(isnSizeVec)
86  isnSizeVec(isnSizeVec)=~cellfun(@isequal,...
87  leftSizeCVec(isnSizeVec),rightSizeCVec(isnSizeVec));
88 end
89 %% perform comparison
90 leftIndMat=zeros(nLeftElem,nElems);
91 rightIndMat=zeros(nRightElem,nElems);
92 for iElem=1:nElems
93  if isnLeftValueVec(iElem)
94  isRightNullVec=all(rightIsNullCVec{iElem},2);
95  if ~all(isRightNullVec)
96  isnLeftValueVec(iElem)=false;
97  leftIndMat(:,iElem)=1;
98  rightIndMat(isRightNullVec,iElem)=1;
99  end
100  continue;
101  elseif isnSizeVec(iElem)
102  isLeftNullVec=all(leftIsNullCVec{iElem},2);
103  isRightNullVec=all(rightIsNullCVec{iElem},2);
104  if any(isLeftNullVec)&&any(isRightNullVec)
105  leftIndMat(:,iElem)=double(isLeftNullVec);
106  rightIndMat(:,iElem)=double(~isRightNullVec)+1;
107  continue;
108  else
109  return;
110  end
111  end
112  [leftIsNullMat,~,indLeftNullVec]=mxberry.core.uniquerows(...
113  leftIsNullCVec{iElem},true);
114  [rightIsNullMat,~,indRightNullVec]=mxberry.core.uniquerows(...
115  rightIsNullCVec{iElem},true);
116  [isLeft2RightNullVec,indLeft2RightNullVec]=...
117  mxberry.core.ismemberrows(leftIsNullMat,rightIsNullMat,true);
118  if ~all(isLeft2RightNullVec)
119  indLeft2RightNullVec=indLeft2RightNullVec(isLeft2RightNullVec);
120  leftIsNullMat=leftIsNullMat(isLeft2RightNullVec,:);
121  leftIndVec=cumsum(double(isLeft2RightNullVec),1);
122  leftIndVec(~isLeft2RightNullVec)=0;
123  indLeftNullVec=leftIndVec(indLeftNullVec);
124  end
125  nLeftRows=size(leftIsNullMat,1);
126  if nLeftRows==0
127  return;
128  end
129  iInd=0;
130  leftMat=leftCVec{iElem};
131  rightMat=rightCVec{iElem};
132  for iLeftRow=1:nLeftRows
133  isnNullColVec=leftIsNullMat(iLeftRow,:);
134  isLeftNullVec=indLeftNullVec==iLeftRow;
135  isRightNullVec=indRightNullVec==indLeft2RightNullVec(iLeftRow);
136  if all(isnNullColVec)
137  iInd=iInd+1;
138  rightIndMat(isRightNullVec,iElem)=iInd;
139  leftIndMat(isLeftNullVec,iElem)=iInd;
140  continue;
141  end
142  isnNullColVec=~isnNullColVec;
143  [uniqueRightMat,~,rightIndVec]=uniquejoint(...
144  {rightMat(isRightNullVec,isnNullColVec,:)},1);
145  nInds=max(rightIndVec);
146  rightIndVec=rightIndVec+iInd;
147  rightIndMat(isRightNullVec,iElem)=rightIndVec;
148  [isLeft2RightVec,indLeft2RightVec]=ismemberjoint(...
149  {leftMat(isLeftNullVec,isnNullColVec,:)},...
150  uniqueRightMat,1);
151  if any(isLeft2RightVec)
152  isLeftNullVec(isLeftNullVec)=isLeft2RightVec;
153  leftIndMat(isLeftNullVec,iElem)=...
154  indLeft2RightVec(isLeft2RightVec)+iInd;
155  end
156  iInd=iInd+nInds;
157  end
158 end
159 if any(isnLeftValueVec)
160  leftIndMat(:,isnLeftValueVec)=[];
161  rightIndMat(:,isnLeftValueVec)=[];
162 end
163 %
164 if nargout>1
165  [isMemberVec(:),indMemberVec(:)]=mxberry.core.ismemberrows(...
166  leftIndMat,rightIndMat,true);
167 else
168  isMemberVec(:)=mxberry.core.ismemberrows(leftIndMat,rightIndMat,true);
169 end
170  function [nElems,valueSizeCVec,isNullSizeCVec,valueCVec,isNullCVec,isnValueVec]=checkValueAndIsNullConsistency(nameStr,valueCVec,isNullCVec,nDimsCVec,isnValueVec)
171  import mxberry.core.throwerror;
172  valueSizeCVec=cellfun(@(x,y)[size(x) ones(1,max(y-ndims(x),0))],...
173  valueCVec,nDimsCVec,'UniformOutput',false);
174  isNullSizeCVec=cellfun(@(x,y)[size(x) ones(1,max(y-ndims(x),0))],...
175  isNullCVec,nDimsCVec,'UniformOutput',false);
176  if ~all(cellfun(@(x,y,z)isequal(x(1:z),y(1:z)),...
177  valueSizeCVec,isNullSizeCVec,nDimsCVec))
178  throwerror('wrongInput',...
179  [nameStr 'CVec is not consitent with ' ...
180  nameStr 'IsNullCVec in size']);
181  end
182  nElems=sort(cellfun(@(x)x(dim),isNullSizeCVec));
183  if any(diff(nElems)~=0)
184  throwerror('wrongInput',[...
185  'Cells in ' nameStr 'CVec and ' nameStr 'IsNullCVec '...
186  'must have the same size along dimension dim=%d'],dim);
187  end
188  nElems=nElems(1);
189  if isPerm
190  isNullCVec=cellfun(@(x)reshape(permute(x,permIndVec),nElems,[]),...
191  isNullCVec,'UniformOutput',false);
192  else
193  isCurVec=cellfun('prodofsize',isNullSizeCVec)>2;
194  if any(isCurVec)
195  isNullCVec(isCurVec)=cellfun(@(x)reshape(x,nElems,[]),...
196  isNullCVec(isCurVec),'UniformOutput',false);
197  end
198  end
199  isNullSizeCVec=cellfun(@(x)x([1:dim-1 dim+1:numel(x)]),...
200  isNullSizeCVec,'UniformOutput',false);
201  if all(isnValueVec)
202  return;
203  end
204  isCurVec=~isnValueVec;
205  isCurVec(isCurVec)=~cellfun(@(x)all(x(:)),isNullCVec(isCurVec));
206  isnValueVec=~isCurVec;
207  if all(isnValueVec)
208  return;
209  end
210  nColsVec=num2cell(cellfun('size',isNullCVec(isCurVec),2));
211  if isPerm
212  valueCVec(isCurVec)=cellfun(@(x,y)reshape(permute(x,...
213  [permIndVec nMaxDims+1:ndims(x)]),nElems,y,[]),...
214  valueCVec(isCurVec),nColsVec,'UniformOutput',false);
215  else
216  valueCVec(isCurVec)=cellfun(@(x,y)reshape(x,nElems,y,[]),...
217  valueCVec(isCurVec),nColsVec,'UniformOutput',false);
218  end
219  valueSizeCVec(isCurVec)=cellfun(@(x)x([1:dim-1 dim+1:numel(x)]),...
220  valueSizeCVec(isCurVec),'UniformOutput',false);
221  end
222 end
function num2cell(in inpArray, in varargin)
NUM2CELL is an extension of Matlab built-in function "num2cell" designed to work correctly with empty...
function throwerror(in msgTag, in varargin)
THROWERROR works similarly to built-in ERROR function in case when there is no output arguments but s...
function ismemberjoint(in leftCArr, in rightCArr, in varargin)
ISMEMBERJOINT perform joint ismember operation for two cell arrays.
function uniquejoint(in inpCArr, in varargin)
UNIQUEJOINT perform joint unique operation for cell arrays.
function checkgen(in x, in typeSpec, in varargin)
CHECKGEN checks a generic condition provided by typeSpec string in the following format: &#39;isnumeric(x...
function checkValueAndIsNullConsistency(in nameStr, in valueCVec, in isNullCVec, in nDimsCVec, in isnValueVec)
function ismemberjointwithnulls(in leftCVec, in leftIsNullCVec, in rightCVec, in rightIsNullCVec, in dim)
ISMEMBERJOINTWITHNULLS perform joint ismember operation for two cell arrays for which also cell array...