MatrixBerryCore
ismemberjoint.m
Go to the documentation of this file.
1 function [isThereVec,indThereVec]=ismemberjoint(leftCArr,rightCArr,varargin)
2 import mxberry.core.uniquejoint;
3 import mxberry.core.throwerror;
4 import mxberry.core.ismembersortableobj;
5 %
6 if nargin<2
7  throwerror('wrongInput',...
8  'incorrect number of input arguments');
9 end
10 %
11 if ~iscell(leftCArr)||~iscell(rightCArr)
12  throwerror('wrongInput',...
13  'both arguments should be cell arrays');
14 end
15 %
16 [reg,prop]=parseparams(varargin);
17 nReg=numel(reg);
18 if nReg<1
19  dim=[];
20 else
21  dim=reg{1};
22  isnWrong=isnumeric(dim)&&numel(dim)==1;
23  if isnWrong
24  dim=double(dim);
25  isnWrong=isreal(dim)&&floor(dim)==dim&&dim>=1&&isfinite(dim);
26  end
27  if ~isnWrong
28  throwerror('wrongInput',...
29  'scalar number expected as the third argument');
30  end
31 end
32 %
33 leftCArr=leftCArr(:);
34 rightCArr=rightCArr(:);
35 %
36 nLeft=length(leftCArr);
37 %
38 if nLeft~=length(rightCArr)
39  throwerror('wrongInput',...
40  'both arguments should have the same size');
41 end
42 %
43 if nLeft==0
44  throwerror('wrongInput',...
45  'both arguments should be non-empty cells');
46 end
47 %
48 leftTypeCell=cellfun(@class,leftCArr,'UniformOutput',false);
49 rightTypeCell=cellfun(@class,rightCArr,'UniformOutput',false);
50 isEqualType=cellfun(@(x,y)isequal(x,y),leftTypeCell,rightTypeCell);
51 if ~all(isEqualType)
52  throwerror('wrongInput',...
53  'types of corresponding input cell content should be the same');
54 end
55 %
56 if isempty(dim)
57  isEmptyVec=cellfun('isempty',leftCArr)&cellfun('isempty',rightCArr);
58  leftCArr(isEmptyVec)=[];
59  rightCArr(isEmptyVec)=[];
60  nLeftComp=length(leftCArr);
61  if nLeftComp==0
62  isThereVec=false(0,1);
63  indThereVec=zeros(0,1);
64  return;
65  end
66  leftSize=size(leftCArr{1});
67  isEqualLeftSize=mxberry.core.checksize(leftCArr{:},leftSize);
68  if ~isEqualLeftSize
69  throwerror('wrongInput',...
70  'size of all items of the first cell array should be the same');
71  end
72  %
73  rightSize=size(rightCArr{1});
74  isEqualRightSize=mxberry.core.checksize(rightCArr{:},rightSize);
75  if ~isEqualRightSize
76  throwerror('wrongInput',...
77  'size of all items of the second cell array should be the same');
78  end
79  %
80  nLeftElem=numel(leftCArr{1});
81  lengthLeft=length(leftCArr{1});
82  %
83  nRightElem=numel(rightCArr{1});
84  lengthRight=length(rightCArr{1});
85  %
86  if (nLeftElem~=lengthLeft)||(nRightElem~=lengthRight)
87  throwerror('wrongInput',...
88  'all cell items should be either columns or rows ');
89  end
90  %
91  if nLeftElem==0
92  isThereVec=false(leftSize);
93  indThereVec=nan(leftSize);
94  return;
95  end
96  leftCArr=cellfun(@(x)x(:),leftCArr,'UniformOutput',false);
97  rightCArr=cellfun(@(x)x(:),rightCArr,'UniformOutput',false);
98 else
99  if nReg<2
100  checkSizeIfEmpty=true;
101  else
102  checkSizeIfEmpty=reg{2};
103  end
104  %
105  nLeftElem=size(leftCArr{1},dim);
106  %
107  %cellfun('size',...,dim) doesn't work properly for cell arrays of
108  %enums so we are forced to use a slower variant here: cellfun(@(x)...)
109  isEqualLeftSize=all(cellfun(@(x)size(x,dim),leftCArr(:))==nLeftElem);
110  if ~isEqualLeftSize
111  throwerror('wrongInput',...
112  ['size of all items in leftCArr along %d-th ',...
113  'dimension should be the same'],dim);
114  end
115  %
116  nRightElem=size(rightCArr{1},dim);
117  %
118  %cellfun('size',...,dim) doesn't work properly for cell arrays of
119  %enums so we are forced to use a slower variant here: cellfun(@(x)...)
120  isEqualRightSize=all(cellfun(@(x)size(x,dim),rightCArr)==nRightElem);
121  if ~isEqualRightSize
122  throwerror('wrongInput',...
123  ['size of all items in rightCArr along %d-th ',...
124  'dimension should be the same'],dim);
125  end
126  %
127  if checkSizeIfEmpty||(nLeftElem>0&&nRightElem>0)
128  if dim>1
129  permVec=[dim 1:dim-1 dim+1:max(vertcat(...
130  cellfun('ndims',leftCArr(:)),cellfun('ndims',rightCArr(:))))];
131  leftCArr=cellfun(@(x)permute(x,permVec),leftCArr,'UniformOutput',false);
132  rightCArr=cellfun(@(x)permute(x,permVec),rightCArr,'UniformOutput',false);
133  end
134  leftSize=cellfun(@size,leftCArr,'UniformOutput',false);
135  rightSize=cellfun(@size,rightCArr,'UniformOutput',false);
136  %
137  if ~isequal(cellfun(@(x)x(2:end),leftSize,'UniformOutput',false),...
138  cellfun(@(x)x(2:end),rightSize,'UniformOutput',false))
139  throwerror('wrongInput',[...
140  'sizes of all items in leftCArr and rightCArr '...
141  'along all dimensions save %d-th one should be the same'],dim);
142  end
143  end
144  %
145  if nLeftElem==0
146  if dim>1
147  isThereVec=false(1,0);
148  indThereVec=nan(1,0);
149  else
150  isThereVec=false(0,1);
151  indThereVec=nan(0,1);
152  end
153  return;
154  end
155  %
156  if nRightElem==0
157  if dim>1
158  isThereVec=false(1,nLeftElem);
159  indThereVec=zeros(1,nLeftElem);
160  else
161  isThereVec=false(nLeftElem,1);
162  indThereVec=zeros(nLeftElem,1);
163  end
164  return;
165  end
166  %
167  isReshape=max(cellfun('length',leftSize),cellfun('length',rightSize))>2;
168  if any(isReshape)
169  leftCArr(isReshape)=cellfun(@(x)reshape(x,nLeftElem,[]),...
170  leftCArr(isReshape),'UniformOutput',false);
171  rightCArr(isReshape)=cellfun(@(x)reshape(x,nRightElem,[]),...
172  rightCArr(isReshape),'UniformOutput',false);
173  end
174  nLeftComp=length(leftCArr);
175 end
176 %
177 %use iterative unique operation
178 leftIndMat=zeros(nLeftElem,nLeftComp);
179 rightIndMat=zeros(nRightElem,nLeftComp);
180 for iRow=1:nLeftComp
181  leftMat=leftCArr{iRow};
182  rightMat=rightCArr{iRow};
183  if isa(rightMat,'function_handle')
184  leftMat=func2str(leftMat);
185  rightMat=func2str(rightMat);
186  end
187  if isnumeric(rightMat)||islogical(rightMat)||ischar(rightMat)
188  [rightMat,~,rightIndMat(:,iRow)]=mxberry.core.uniquerows(rightMat,false,prop{:});
189  [~,leftIndMat(:,iRow)]=mxberry.core.ismemberrows(leftMat,rightMat,false,prop{:});
190  else
191  isCharStr=iscellstr(rightMat);
192  if iscell(rightMat)&&~isCharStr
193  isCharStr=all(cellfun('isclass',rightMat(:),'function_handle'));
194  if isCharStr
195  leftMat=cellfun(@func2str,leftMat,'UniformOutput',false);
196  rightMat=cellfun(@func2str,rightMat,'UniformOutput',false);
197  end
198  end
199  if isCharStr
200  nCols=size(rightMat,2);
201  leftIndColMat=nan(nLeftElem,nCols);
202  rightIndColMat=nan(nRightElem,nCols);
203  for iCol=1:nCols
204  [rightVec,~,rightIndColMat(:,iCol)]=unique(rightMat(:,iCol));
205  [~,leftIndColMat(:,iCol)]=ismember(leftMat(:,iCol),rightVec);
206  end
207  if nCols==1
208  leftIndMat(:,iRow)=leftIndColMat;
209  rightIndMat(:,iRow)=rightIndColMat;
210  else
211  [rightIndColMat,~,rightIndMat(:,iRow)]=mxberry.core.uniquerows(rightIndColMat,true,prop{:});
212  [~,leftIndMat(:,iRow)]=mxberry.core.ismemberrows(leftIndColMat,rightIndColMat,true,prop{:});
213  end
214  else
215  isLeftOpaque=isa(leftCArr{1},'opaque');
216  isRightOpaque=isa(rightCArr{1},'opaque');
217  %
218  isSortMethodDefined=ismethod(leftCArr{1},'sort')&&...
219  ismethod(rightCArr{1},'sort');
220  %
221  isBothOpaque=isLeftOpaque&&isRightOpaque;
222  %
223  if isBothOpaque
224  if isSortMethodDefined
225  [~,leftIndMat(:,iRow)]=ismembersortableobj(...
226  leftCArr{1},rightCArr{1});
227  else
228  [~,leftIndMat(:,iRow)]=...
229  mxberry.core.ismemberbyfunc(leftCArr{1},rightCArr{1});
230  end
231  nRightElems = numel(rightCArr{iRow});
232  rightIndMat(:,iRow)=1:nRightElems;
233  else
234  [leftUniqCell,~,leftIndMat(:,iRow),isLeftSorted]=...
235  uniquejoint(leftCArr(iRow),1);
236  [rightUniqCell,~,rightIndMat(:,iRow),...
237  isRightSorted]=uniquejoint(rightCArr(iRow),1);
238  leftUniqMat=leftUniqCell{1};
239  rightUniqMat=rightUniqCell{1};
240  if ~isequaln(leftUniqMat,rightUniqMat)
241  if isLeftSorted&&isRightSorted
242  nElems=size(leftUniqMat,1);
243  [~,~,curInd]=uniquejoint({vertcat(leftUniqMat,rightUniqMat)},1);
244  [~,curInd]=ismember(curInd(1:nElems),curInd(nElems+1:end),'legacy');
245  else
246  [~,curInd]=mxberry.core.ismemberbyfunc(...
247  leftUniqMat,rightUniqMat);
248  end
249  leftIndMat(:,iRow)=curInd(leftIndMat(:,iRow));
250  end
251  end
252  end
253  end
254 end
255 %
256 isInd=nargout>1;
257 if nLeftComp==0
258  isThereVec=true(nLeftElem,1);
259  indThereVec=nRightElem*ones(nLeftElem,1);
260 elseif nLeftComp==1
261  if isInd
262  [isThereVec,indThereVec]=ismember(leftIndMat,rightIndMat,'legacy');
263  else
264  isThereVec=ismember(leftIndMat,rightIndMat,'legacy');
265  end
266 else
267  if isInd
268  [isThereVec,indThereVec]=mxberry.core.ismemberrows(leftIndMat,...
269  rightIndMat,true,prop{:});
270  else
271  isThereVec=mxberry.core.ismemberrows(leftIndMat,rightIndMat,...
272  true,prop{:});
273  end
274 end
275 %
276 if isempty(dim)
277  isThereVec=reshape(isThereVec,leftSize);
278  if nargout>1
279  indThereVec=reshape(indThereVec,leftSize);
280  end
281 elseif dim>1
282  isThereVec=reshape(isThereVec,1,[]);
283  if isInd
284  indThereVec=reshape(indThereVec,1,[]);
285  end
286 end
287 end
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 ismembersortableobj(in firstVec, in secVec)
ISMEMBER implementation strictly for sortable entities i.e. for those that have 1) full order defined...
function uniquerows(in inpMat, in isInteger, in forceMode)
UNIQUEROWS finds unique rows in input matrix, i.e. the more effective version of UNIQUE(. . .,&#39;rows&#39;)
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 unique(in inpVec)
UNIQUE for arrays of any type.
function ismember(in leftVec, in rightVec, in varargin)
ISMEMBER - ismember implementation for arrays of any type.
function parseparams(in args, in propNameList, in nRegExpected, in nPropExpected)
PARSEPARAMS behaves exactly as a built-in Matlab function apart from the incorrect behavior of Matlab...