Home > utils > compare_cells.m

compare_cells

PURPOSE ^

this function compares the structure and contents of multi-dimensional and nested cells

SYNOPSIS ^

function [cellsAreEqual,firstViolation,violationReason] = compare_cells(cell1,cell2)

DESCRIPTION ^

 this function compares the structure and contents of multi-dimensional and nested cells
 
 this function has been modeled after compare_structs.m (S. Tomic)
 
 cell1 and cell2 are the only required arguments
 
 the rest of the arguments are maintained for compatibility with
 compar_struct, and are passed onto compare_struct in the event that cell
 contents are of class 'struct'. tag,value pairs that specify how the
 structs will be compared.
 supported tags and values:
 
    'values' (true or false): specifies whether field values will be
       compared or not.
    'substruct' (true or false): specifies whether to check only whether
       struct1 is contained in struct2 (struct2 simply has more fields and
       values than struct1 but otherwise are equal). Otherwise the structs
       will be compared for an exact match.
    'types' (true or false): specifies whether or not to check the type
       (class) of the fields for a positive match. This can only be set to
       false if 'values' is also false. Otherwise, types will
       automatically be checked.
 
 this function first checks to see if both inputs are cells, and then
 compares the structure (# dimensions and size in each dimension) of the
 provided cells. Any inequality in # of dimensions or size in any
 dimension will be viewed as a cell inequality. If cells are of identical
 structure, they will be converted to a vector [new_vect = cellN(:)], and
 then each element from both cells will be compared on variable class and
 then content.
 
  OUTPUTS
   cellsAreEqual - 1 or 0, whether or not cell equality is true
   firstViolation - the index in the vector-transformed cells where the
       first inequality of content or variable class was found. In the
       case of cells within cells, this function is called recursively.
       when recursing on self, upon finding an error, the index in the
       topmost parent cell where the inequality was found is returned in
       firstViolation. In the case that the structure of the cells
       differs, or the case that either or both of the inputs are not
       cells, firstViolation = 0;
   violationReason - provides a concise descriptor of the type of
       violation that occurred.
 
 NOTE: if one cell is a transposition of the other, they will be found
 unequal, either by size, or by contents

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function [cellsAreEqual,firstViolation,violationReason] = compare_cells(cell1,cell2)
0002 
0003 % this function compares the structure and contents of multi-dimensional and nested cells
0004 %
0005 % this function has been modeled after compare_structs.m (S. Tomic)
0006 %
0007 % cell1 and cell2 are the only required arguments
0008 %
0009 % the rest of the arguments are maintained for compatibility with
0010 % compar_struct, and are passed onto compare_struct in the event that cell
0011 % contents are of class 'struct'. tag,value pairs that specify how the
0012 % structs will be compared.
0013 % supported tags and values:
0014 %
0015 %    'values' (true or false): specifies whether field values will be
0016 %       compared or not.
0017 %    'substruct' (true or false): specifies whether to check only whether
0018 %       struct1 is contained in struct2 (struct2 simply has more fields and
0019 %       values than struct1 but otherwise are equal). Otherwise the structs
0020 %       will be compared for an exact match.
0021 %    'types' (true or false): specifies whether or not to check the type
0022 %       (class) of the fields for a positive match. This can only be set to
0023 %       false if 'values' is also false. Otherwise, types will
0024 %       automatically be checked.
0025 %
0026 % this function first checks to see if both inputs are cells, and then
0027 % compares the structure (# dimensions and size in each dimension) of the
0028 % provided cells. Any inequality in # of dimensions or size in any
0029 % dimension will be viewed as a cell inequality. If cells are of identical
0030 % structure, they will be converted to a vector [new_vect = cellN(:)], and
0031 % then each element from both cells will be compared on variable class and
0032 % then content.
0033 %
0034 %  OUTPUTS
0035 %   cellsAreEqual - 1 or 0, whether or not cell equality is true
0036 %   firstViolation - the index in the vector-transformed cells where the
0037 %       first inequality of content or variable class was found. In the
0038 %       case of cells within cells, this function is called recursively.
0039 %       when recursing on self, upon finding an error, the index in the
0040 %       topmost parent cell where the inequality was found is returned in
0041 %       firstViolation. In the case that the structure of the cells
0042 %       differs, or the case that either or both of the inputs are not
0043 %       cells, firstViolation = 0;
0044 %   violationReason - provides a concise descriptor of the type of
0045 %       violation that occurred.
0046 %
0047 % NOTE: if one cell is a transposition of the other, they will be found
0048 % unequal, either by size, or by contents
0049  
0050 % Copyright (c) 2009-2012 The Regents of the University of California
0051 % All Rights Reserved.
0052 %
0053 % FB 2009.02.24
0054 % PJ 29Dec2014 - added check to see if both cells are empty
0055 
0056 %
0057 % initialize variables
0058 %
0059 cellsAreEqual = 0;
0060 firstViolation = 0;
0061 violationReason = '';
0062 
0063 numberTypes = {'int8','uint8','int16','uint16','int32','uint32','int64',...
0064     'uint64','double'};
0065 
0066 if (nargin > 2)
0067   for iarg = 1:nargin-2
0068     switch(varargin{iarg})
0069      case 'values'
0070       checkValues = varargin{iarg+1};
0071      case 'substruct'
0072       checkSubstruct = varargin{iarg+1};
0073      case 'types'
0074       checkTypes = varargin{iarg+1};
0075     end
0076   end
0077 end
0078 
0079 if ~exist('checkValues','var'),    checkValues = true; end
0080 if ~exist('checkSubstruct','var'), checkSubstruct = true; end
0081 if ~exist('checkTypes','var'),     checkTypes = true; end
0082 
0083 %
0084 % check to see if inputs are cells
0085 %
0086 if ~iscell(cell1) && ~iscell(cell2)
0087   violationReason = 'neither input is of type ''cell''';
0088   return
0089 elseif ~iscell(cell1)
0090   violationReason = 'cell1 is not of type ''cell''';
0091   return
0092 elseif ~iscell(cell2)
0093   violationReason = 'cell2 is not of type ''cell''';
0094   return
0095 end
0096 
0097 %
0098 % Check to see if they are both empty
0099 % It turns out that empty cells can have different sizes, e.g. 0x0 or 1x0
0100 %
0101 % Both are empty, return equality
0102 if isempty(cell1) && isempty(cell2)
0103   cellsAreEqual = 1;
0104   return
0105 end
0106 
0107 %
0108 % compare sizes of cells
0109 %
0110 s1 = size(cell1);
0111 s2 = size(cell2);
0112 
0113 % if cells are not the same exact size, they will be treated as unequal
0114 % NOTE: transposed cell arrays will not be treated as equal
0115 if length(s1) ~= length(s2)
0116   violationReason = 'cells have different number of dimensions';
0117   return
0118 end
0119 
0120 sm = (s1 == s2);
0121 if ~all(sm)
0122   violationReason = 'cells have different sizes in one or more dimension';
0123   return
0124 end
0125 
0126 % convert cells to vectors
0127 v1 = cell1(:);
0128 v2 = cell2(:);
0129 nv1 = length(v1);
0130 nv2 = length(v2);
0131 if nv1 ~= nv1
0132   violationReason = 'vectors (converted cells) have different sizes';
0133   return
0134 end
0135 
0136 % step through cells, compare at each index
0137 for i=1:nv1
0138     
0139   % compare cell class
0140   c1 = class(v1{i});
0141   c2 = class(v2{i});  
0142   if isempty(strmatch(c1,c2,'exact'))
0143     firstViolation = i;
0144     violationReason = sprintf(['cell contents have different class at '...
0145         'index %d'],i);
0146     return
0147   end
0148 
0149   % compare cell contents
0150   same = 1;
0151   switch c1     
0152       case numberTypes
0153         if any(size(v1{i}) ~= size(v2{i})) || ~all(v1{i} == v2{i})
0154           same = 0;
0155           subVioReason = sprintf('%s differed',c1);
0156         end
0157       case 'char'
0158         if ~strcmp(v1{i},v2{i})
0159           same = 0;
0160           subVioReason = 'strings differed';
0161         end
0162       case 'struct'
0163         [structsAreEqual,subStructVio,subVioReason] = compare_structs(...
0164             v1{i},v2{i},'values',checkValues,'substruct',checkSubstruct,...
0165             'types',checkTypes);
0166         if ~structsAreEqual, same = 0; end
0167       case 'cell'
0168         [subCellsEqual,subCellVio,subVioReason] = compare_cells(v1{i},v2{i});
0169         if ~subCellsEqual, same = 0; end
0170       case 'logical'
0171         if v1{i} ~= v2{i}
0172           same = 0;
0173           subVioReason = sprintf('logical vars differed');
0174         end          
0175       otherwise
0176         same = 0;
0177         subVioReason = sprintf('class %s not supported',c1);
0178   end
0179 
0180   if ~same
0181     firstViolation = i;
0182     violationReason = sprintf('cell contents differed (%s)',subVioReason);
0183     return
0184   end
0185 end % for i=1:nv1
0186 
0187 % no differences found, return equality
0188 cellsAreEqual = 1;

Generated on Wed 20-Sep-2023 04:00:50 by m2html © 2003