Code covered by the BSD License  

Highlights from
Compare Structures

Compare Structures

by

 

21 Jan 2009 (Updated )

Compares two structured variables recursively and notes where the two structures are different.

comp_struct(s1,s2,n1,n2,p,tol)
function [fs1, fs2, er] = comp_struct(s1,s2,n1,n2,p,tol)
% check two structures for differances - i.e. see if strucutre s1 == structure s2
% function [fs1, fs2, er] = comp_struct(s1,s2,n1,n2,p,tol)
%
% inputs  6 - 5 optional
% s1      structure one                              class structure
% s2      structure two                              class structure - optional
% n1      first structure name (variable name)       class char - optional
% n2      second structure name (variable name)      class char - optional
% p       pause flag (0 / 1)                         class integer - optional
% tol     tol default tolerance (real numbers)       class integer - optional
%
% outputs 3 - 3 optional
% fs1     non-matching feilds for structure one      class cell - optional
% fs2     non-matching feilds for structure two      class cell - optional
% er      error flag (value)                         class 
%
% example:	[r1 r2] = comp_struct(data1,data2,'data1','data2',1)
% michael arant - april 5 2003
%
% hint:
% passing just one structure causes the program to copy the structure
% and compare the two.  This is an easy way to list the structure

if nargin < 1; help comp_struct; error('I / O error'); end
if nargin < 2; s2 = s1; end
if nargin < 3; n1 = 's1'; end
if nargin < 4; n2 = 's2'; end
if nargin < 5; p = 0; elseif p ~= 1 && p ~= 0; p = 0; end
if nargin < 6; tol = 1e-6; end

% define fs
fs1 = {}; fs2 = {}; er = {};

% are the variables structures
if isstruct(s1) && isstruct(s2)
%	both structures - get the field names
	fn1 = fieldnames(s1);
	fn2 = fieldnames(s2);
%	loop through structure 1 and match to structure 2
	pnt1 = zeros(1,length(fn1));
	for ii = 1:length(fn1)
		for jj = 1:length(fn2)
			if strcmp(fn1(ii),fn2(jj)); pnt1(ii) = jj; end
		end
	end
	pnt2 = zeros(1,length(fn2));
	for ii = 1:length(fn2)
		for jj = 1:length(fn1)
			if strcmp(fn2(ii),fn1(jj)); pnt2(ii) = jj; end
		end
	end
%	get un-matched fields
	for ii = find(~pnt1)
		fs1 = [fs1; {[char(n1) '.' char(fn1(ii))]}];
		fs2 = [fs2; {''}]; er = [er; {'Un-matched'}];
	end
	for ii = find(~pnt2)
		fs2 = [fs2; {[char(n2) '.' char(fn2(ii))]}];
		fs1 = [fs1; {''}]; er = [er; {'Un-matched'}];
	end
% %	look for non-matched fields fs1 to fs2
% 	fs1a = fn1(~pnt1);
% 	fs2a = setxor(pnt1,1:length(fn2));
% 	if ~isempty(fs2a); fs2a = fs2a(fs2a ~= 0);
% 		if ~isempty(fs2a)
% 			for kk = 1:length(fs2a)
% 				fs2 = [fs2; {[char(n2) '.' char(fn2(fs2a(kk)))]}];
% 				er = {'Un-matched'}; fs1 = [fs1; {''}];
% 			end
% 		end
% 	end
% 	if isempty(fs2); fs2 = cell(0,1); end
%	now evaluate the matching fields  remove "bad" matched
%	loop through structure fields
	pnt1i = find(pnt1); pnt2i = find(pnt2);
	for ii=1:numel(pnt1i)
%		added loop for indexed structured variables
		for jj = 1:size(s1,2)
%			clean display - add index if needed
			if size(s1,2) == 1
				n1p = [n1 '.' char(fn1(pnt1i(ii)))];
				n2p = [n2 '.' char(fn2(pnt2i(ii)))];
			else
				n1p = [n1 '(' num2str(jj) ').' char(fn1(ii))]; ...
							n2p = [n2 '(' num2str(jj) ').' char(fn2(pnt2(ii)))];
			end
			[fss1 fss2 err] = comp_struct(getfield(s1(jj),char(fn1(pnt1i(ii)))), ...
								getfield(s2(jj),char(fn2(pnt2i(ii)))),n1p,n2p,p);
			if ~iscell(err); err = cellstr(err); end
			fs1 = [fs1; fss1]; fs2 = [fs2; fss2]; er = [er; err];
		end
	end
elseif isstruct(s1) ~= isstruct(s2)
%	one structure, one not
	disp(sprintf('%s	%s		Type mismatch - NOT equal',n1,n2));
	fs1 = cell(0,1); fs2 = fs1;
	if p; disp('Paused .....'); pause; end
elseif isa(s1,'sym') && isa(s2,'sym')
%	compare two symbolic expresions
%	direct compare
	[ss1 r] = simple(s1); [ss2 r] = simple(s2);
	t = isequal(simplify(ss1),simplify(ss2));
	if ~t
%		could still be equal, but not able to reduce the symbolic expresions
%		get factors
		f1 = findsym(ss1); f2 = findsym(ss2);
		w = warning; 
		if isequal(f1,f2)
%			same symbolic variables.  same eqn?
			temp = [1 findstr(f1,' ') + 1]; tres = NaN * zeros(1,30);
			for jj = 1:1e3
				ss1e = ss1; ss2e = ss2;
				for ii = 1:length(temp);
					tv = (real(rand^rand)) / (real(rand^rand));
					ss1e = subs(ss1e,f1(temp(ii)),tv);
					ss2e = subs(ss2e,f2(temp(ii)),tv);
				end
	%			check for match
				if isnan(ss1e) || isnan(ss2e)
					tres(jj) = 1;
				elseif (double(ss1e) - double(ss2e)) < tol
						tres(jj) = 1;
				end
			end
%			now check symbolic equation results
			if sum(tres) == length(tres)
%				symbolics assumed to be the same equation
				t = 1;
			end
		else
%			different symbolic variables
		end
		warning(w)
	end
	if t
		disp(sprintf('%s	%s		match',n1,n2))
	else
		disp(sprintf('%s	%s		do NOT match',n1,n2))
		fs1 = n1; fs2 = n2; er = 'Symbolic disagreement';
	end
else
%	neither structure - compare
	if isequal(s1,s2);
		disp(sprintf('%s 	%s		match',n1,n2))
	else
%		check for "false" failures
%		check structure size
		if strcmp(num2str(size(s1)),num2str(size(s2)));
%			structures are same size - check for precision error if numbers
			if ischar(s1) || iscell(s1) || ...
				(max(max(max(abs(s1 - s2)))) > tol * (max(max(max([s1 s2]))) ...
				- min(min(min([s1 s2])))))
%				same size, diferent values or not numbers
				disp(sprintf('%s	%s		do NOT match',n1,n2))
				fs1 = [fs1; {n1}]; fs2 = [fs2; {n2}]; er = [er; {'?'}];
				if ischar(s1)
					er1 = sprintf('%s is char - %s',n1,char(s1)); disp(er1);
				end
				if ischar(s2)
					er2 = sprintf('%s is char - %s',n2,char(s2)); disp(er2);
				end
				if exist('er1','var') && exist('er2','var')
					er = [er; {[er1 ' ---> ' er2]}];
				end
				if ~ischar(s1) && ~iscell(s1);
					er = sprintf('Max error (%%) = %g%%', ...
							max(max(max(abs(s1 - s2)))) / ...
							(max(max(max([s1 s2]))) - min(min(min([s1 s2])))));
					disp(er);
				end
				if p; disp('Paused .....'); pause; end
			else
%				tolerance agreement
				disp(sprintf('%s 	%s		tolerance match',n1,n2))
			end
		else
%			size difference
			disp(sprintf('%s	%s		do NOT match - DIFFERENT SIZES',n1,n2))
			fs1 = [fs1; {n1}]; fs2 = [fs2; {n2}]; er = [er; {'String size error'}];
			if p; disp('Paused .....'); pause; end
		end
	end
%	fs1 = cell(0,1); fs2 = fs1;
end

% display non matching fields
if 1
	if ~isempty(fs1)
		for ii = 1:length(fs1)
			if strcmp(n1,fs1(ii))
				disp(sprintf('First Structure non-matched fields:	 %s',[n1]))
			else
% 				if isempty(findstr(n1,char(fs1(ii))))
% 					disp(sprintf('First Structure non-matched fields:	 %s', ...
% 									[n1 '.' char(fs1(ii))]))
% 				else
% 					disp(sprintf('First Structure non-matched fields:	 %s', ...
% 									[n1  strrep(char(fs1(ii)),n1,'')]))
% 				end
			end
			if p; disp('Paused .....'); pause; end
		end
	end
	if ~isempty(fs2)
		for ii = 1:length(fs2)
			if strcmp(n2,fs2(ii))
				disp(sprintf('Second Structure non-matched fields:	 %s',[n2]))
			else
% 				if isempty(findstr(n2,char(fs2(ii))))
% 					disp(sprintf('Second Structure non-matched fields:	 %s', ...
% 									[n2 '.' char(fs2(ii))]))
% 				else
% 					disp(sprintf('Second Structure non-matched fields:	 %s', ...
% 									[n2  strrep(char(fs2(ii)),n2,'')]))
% 				end
			end
			if p; disp('Paused .....'); pause; end
		end
	end
end

Contact us