https://github.com/Data2Dynamics/d2d
Raw File
Tip revision: 4c697ee160f4d91719a65cfcfe3e3b50395b6656 authored by Helge Hass on 29 July 2015, 07:45:33 UTC
new C code version
Tip revision: 4c697ee
arCompare.m
% [same,d1,d2] = arCompare(ar1,ar2,pattern,opt)
% 
%   Comparison of two ar structs/objects
% 
%   ar1       an ar struct, e.g. the global variable "ar"
%   ar2       another ar struct, e.g. "ar" from an workspace
%   pattern   string or cell of strings  
%             patterns are evaluated with regexp.m
%             if pattern is provided, then only a subset of cells are
%             evaluated. Providing patterns is reasonable because the
%             structs often only differ by ar.fevals, ar.info, ...
%   silent    [false]
% 
%   d1,d2   the differences, the structures are similar to 'ar' but not equal
%           since the fields can have different type and should indicate
%           the kind of difference.   
% 
% Examples:
% ar2 = ar;
% ar2.qLog10(:)=~ar.qLog10;
% [same,d1,d2]=arCompare(ar,ar2,'qLog10')
% 
% Check only specific fields:
% ar2 = ar;
% ar2.model(1).data(1).qFit = round(rand(size(ar.model(1).data(1).qFit));
% [same,d1,d2]=arCompare(ar,ar2,{'qLog10','qFit','logfitting'})


function [same,d1,d2] = arCompare(ar1,ar2,pattern,silent)
if(~exist('pattern','var') || isempty(pattern))
    pattern = [];
end
if(~exist('silent','var') || isempty(silent))
    silent = false;
end

% [same,d1,d2] = structcmp(ar1,ar2);
[same,d1,d2] = structcmp2(ar1,ar2,pattern);

if ~silent
    printDifference(d1,d2);
end


function printDifference(d1,d2)
fs = allFields(d1,1);
fs = regexprep(fs,'(\w)\.(\w)','$1(1).$2');
fs = regexprep(fs,'(\w)$','$1(1)');
fs = strrep(fs,'(','{');
fs = strrep(fs,')','}');

for i=1:length(fs)
    fsname = ['ar.',fs{i}];
    fsname = strrep(fsname,'{','(');
    fsname = strrep(fsname,'}',')');
    
    eval(['out1 = d1.',fs{i},';']);
    eval(['out2 = d2.',fs{i},';']);
    if(ischar(out1))
        if(~strcmp(out1,out2))
            fprintf('%40s different: %s vs. %s \n',fsname,out1,out2);
        else
            fprintf('%40s different: %s \n',fsname,out1);
        end
    elseif(isnumeric(out1))
        fprintf('%40s different: %f vs. %f \n',fsname,out1,out2);
    end
end


function [same,d1,d2] = structcmp2(s1,s2,pattern)

same = true;

fn1 = allFields(s1,1);
fn2 = allFields(s2,1);

if(~isempty(pattern))
    if(~iscell(pattern))
        pattern = {pattern};
    end
    use1 = zeros(size(fn1));
    use2 = zeros(size(fn2));
    for i=1:length(pattern)
        use1 = use1 | ~cellfun(@isempty,regexp(fn1,pattern{i}));
        use2 = use2 | ~cellfun(@isempty,regexp(fn2,pattern{i}));
    end
    fn1 = fn1(use1);
    fn2 = fn2(use2);
end

Fn1 = regexprep(fn1,'(\w)\.(\w)','$1(1).$2');
Fn2 = regexprep(fn2,'(\w)\.(\w)','$1(1).$2');
Fn1 = regexprep(Fn1,'(\w)$','$1(1)');
Fn2 = regexprep(Fn2,'(\w)$','$1(1)');

Fn1 = strrep(Fn1,'(','{');
Fn1 = strrep(Fn1,')','}');
Fn2 = strrep(Fn2,'(','{');
Fn2 = strrep(Fn2,')','}');


d1 = struct;
d2 = struct;

notInBoth = setxor(Fn1,Fn2);
if(~isempty(notInBoth))
    same = false;
    notIn1 = setdiff(Fn2,Fn1);
    for i=1:length(notIn1)
        eval(['d2.',notIn1{i},' = ''field only in the 2nd struct'';']);
        eval(['d1.',notIn1{i},' = '''';']);
%         d1.(notIn1{i}) = '';
    end
    notIn2 = setdiff(Fn1,Fn2);
    for i=1:length(notIn2)
%         d1.(notIn2{i}) = 'field only in one 1st struct';
%         d2.(notIn2{i}) = '';
        eval(['d1.',notIn2{i},' = ''field only in the 1st struct'';']);
        eval(['d2.',notIn2{i},' = '''';']);
    end
end


fn = intersect(fn1,fn2);
% fn
% if(~isempty(pattern))
%     fn = intersect(fn,pattern);
% end
Fn = regexprep(fn,'(\w)\.(\w)','$1(1).$2');
Fn = regexprep(Fn,'(\w)$','$1(1)');
Fn = strrep(Fn,'(','{');
Fn = strrep(Fn,')','}');

for i=1:length(fn)
    eval(['val1 = s1.',fn{i},';']);
    eval(['val2 = s2.',fn{i},';']);
    
    if(strcmp(class(val1),class(val2))~=1)
        same = false;
        eval(['d1.',Fn{i},' = sprintf(''class = %s'',class(val1));']);
        eval(['d2.',Fn{i},' = sprintf(''class = %s'',class(val2));']);
        
    elseif(isempty(val1) ~= isempty(val2))
        same = false;
        tmp = sprintf('%i x ',size(val1));
        eval(['d1.',Fn{i},' = ''[size = ',tmp(1:end-2),']'';']);
        tmp = sprintf('%i x ',size(val2));
        eval(['d2.',Fn{i},' = ''[size = ',tmp(1:end-2),']'';']);
        
    elseif(length(size(val1)) ~= length( size(val2)))
        same = false;
        tmp = sprintf('%i x ',size(val1));
        eval(['d1.',Fn{i},' = ''[size = ',tmp(1:end-2),']'';']);
        tmp = sprintf('%i x ',size(val2));
        eval(['d2.',Fn{i},' = ''[size = ',tmp(1:end-2),']'';']);
        
    elseif(sum(abs(size(val1) - size(val2) ))~=0)
        same = false;
        tmp = sprintf('%i x ',size(val1));
        eval(['d1.',Fn{i},' = ''[size = ',tmp(1:end-2),']'';']);
        tmp = sprintf('%i x ',size(val2));
        eval(['d2.',Fn{i},' = ''[size = ',tmp(1:end-2),']'';']);
        
    elseif(isnumeric(val1) || islogical(val1))
        if(sum(abs(val1(:)-val2(:)))>0)
            if(length(val1)<=5)
                eval(['d1.',Fn{i},' = sprintf(''%f '',val1);']);
                eval(['d2.',Fn{i},' = sprintf(''%f '',val2);']);
            else
                eval(['d1.',Fn{i},' = sprintf(''arrays different'');']);
                eval(['d2.',Fn{i},' = sprintf(''arrays different'');']);
            end
            same = false;
        end
        if(sum(abs(isnan(val1(:) ) - isnan( val2(:) ) ))>0)
            same = false;
            eval(['d1.',Fn{i},' = sprintf(''%i NaNs'',sum(isnan(val1(:))));']);
            eval(['d2.',Fn{i},' = sprintf(''%i NaNs'',sum(isnan(val2(:))));']);
        end
    elseif(ischar(val1))
        gleich = strcmp(val1,val2);
        if(~gleich)
            same = false;
            val1 = val1(1:min(length(val1),100));
            val2 = val2(1:min(length(val2),100));
            eval(['d1.',Fn{i},' = val1;']);
            eval(['d2.',Fn{i},' = val2;']);
        end
    elseif(iscell(val1))
        if(isempty(val1) && isempty(val2))
        else
            try
                [csame,reason1,reason2] = cellcmp(val1,val2);
            catch
                csame = 1;
                val1
                val2
            end
            if(~csame)
                same = false;
                eval(['d1.',Fn{i},' = reason1;']);
                eval(['d2.',Fn{i},' = reason2;']);
            end
        end
    elseif(isstruct(val1))
        error('case should not occur.')
%         [same2,dd1,dd2] = structcmp(s1.(fn{i}),val2);
%         if(~same2)
%             same = false;
%             eval(['d1.',Fn{i},' = dd1;
%             d2.(fn{i}) = dd2;
%         end
        
    end
end




function [same,d1,d2] = structcmp(s1,s2)
lmax = max(length(s1),length(s2));

if lmax>1
    same = NaN(size(s1));
    d1 = cell(size(s1));
    d2 = cell(size(s2));
    for i=1:min(10,lmax)
        [same(i),d1{i},d2{i}] = structcmp(s1(i),s2(i));
    end
    for i=(lmax+1):length(s1) % only in s1
        same(i) = false;
        d1{i} = s1(i);
    end
    for i=(lmax+1):length(s2)
        same(i) = false;
        d2{i} = s2(i);
    end
    same = all(same);
    
else
    fn1 = fieldnames(s1);
    fn2 = fieldnames(s2);
    
    same = true;
    
    d1 = struct;
    d2 = struct;
    
    notInBoth = setxor(fn1,fn2);
    if(~isempty(notInBoth))
        same = false;
        notIn1 = setdiff(fn2,fn1);
        for i=1:length(notIn1)
            d2.(notIn1{i}) = 'field only in one 2nd struct';
            d1.(notIn1{i}) = '';
        end
        notIn2 = setdiff(fn1,fn2);
        for i=1:length(notIn2)
            d1.(notIn2{i}) = 'field only in one 1st struct';
            d2.(notIn2{i}) = '';
        end
    end
    
    fn = intersect(fn1,fn2);
    
    for i=1:length(fn)
        if(strcmp(class(s1.(fn{i})),class(s2.(fn{i})))~=1)
            same = false;
            d1.(fn{i}) = sprintf('class = %s',class(s1.(fn{i})));
            d2.(fn{i}) = sprintf('class = %s',class(s2.(fn{i})));
            
        elseif(isempty(s1.(fn{i})) ~= isempty(s2.(fn{i})))
            same = false;
            tmp = sprintf('%i x ',size(s1.(fn{i})));
            d1.(fn{i}) = ['size = ',tmp(1:end-2)];
            tmp = sprintf('%i x ',size(s2.(fn{i})));
            d2.(fn{i}) = ['size = ',tmp(1:end-2)];
            
        elseif(length(size(s1.(fn{i}))) ~= length( size(s2.(fn{i}))))
            same = false;
            tmp = sprintf('%i x ',size(s1.(fn{i})));
            d1.(fn{i}) = ['size = ',tmp(1:end-2)];
            tmp = sprintf('%i x ',size(s2.(fn{i})));
            d2.(fn{i}) = ['size = ',tmp(1:end-2)];
            
        elseif(sum(abs(size(s1.(fn{i})) - size(s2.(fn{i})) ))~=0)
            same = false;
            tmp = sprintf('%i x ',size(s1.(fn{i})));
            d1.(fn{i}) = ['size = ',tmp(1:end-2)];
            tmp = sprintf('%i x ',size(s2.(fn{i})));
            d2.(fn{i}) = ['size = ',tmp(1:end-2)];
            
        elseif(isnumeric(s1.(fn{i})))
            if(sum(abs(s1.(fn{i})(:)-s2.(fn{i})(:)))>0)
                if(length(s1.(fn{i}))<=5)
                    d1.(fn{i}) = sprintf('%f ',s1.(fn{i}));
                    d2.(fn{i}) = sprintf('%f ',s2.(fn{i}));
                else
                    d1.(fn{i}) = sprintf('arrays different');
                    d2.(fn{i}) = sprintf('arrays different');
                end
                same = false;
            end
            if(sum(abs(isnan( s1.(fn{i})(:) ) - isnan( s2.(fn{i})(:) ) ))>0)
                same = false;
                d1.(fn{i}) = sprintf('%i NaNs',sum(isnan(s1.(fn{i})(:))));
                d2.(fn{i}) = sprintf('%i NaNs',sum(isnan(s2.(fn{i})(:))));
            end
        elseif(ischar(s1.(fn{i})))
            gleich = strcmp(s1.(fn{i}),s2.(fn{i}));
            if(~gleich)
                same = false;
                d1.(fn{i}) = s1.(fn{i});
                d2.(fn{i}) = s2.(fn{i});
            end
        elseif(iscell(s1.(fn{i})))
            if(isempty(s1.(fn{i})) && isempty(s2.(fn{i})))
            else
                [csame,reason1,reason2] = cellcmp(s1.(fn{i}),s2.(fn{i}));
                if(~csame)
                    same = false;
                    d1.(fn{i}) = reason1;
                    d2.(fn{i}) = reason2;
                end
            end
        elseif(isstruct(s1.(fn{i})))
            [same2,dd1,dd2] = structcmp(s1.(fn{i}),s2.(fn{i}));
            if(~same2)
                same = false;
                d1.(fn{i}) = dd1;
                d2.(fn{i}) = dd2;
            end
            
        end
    end
    
end


% same = cellcmp(c1,c2)
%
%   Vergleich zwei cell Objekte.
function [same,reason1,reason2] = cellcmp(c1,c2)
same = true;
reason1 = '';
reason2 = '';

if ~isempty(c1)
    isc = find(~cellfun(@isnumeric,c1));
elseif isempty(c1) & isempty(c2)
    return
else
    same = false;
    reason1 = sprintf('isempty=',isempty(c1));
    reason2 = sprintf('isempty=',isempty(c2));
    return
end

if(sum(abs(size(c1)-size(c2)))~=0)
    same = false;
    reason1 = sprintf('size=%i,',size(c1));
    reason2 = sprintf('size=%i,',size(c2));
    return;
elseif sum(abs(cellfun(@iscell,c1(isc))-cellfun(@iscell,c2(isc))))>0
    reason1 = sprintf('cellfun(@iscell,...) different');
    reason2 = sprintf('cellfun(@iscell,...) different');
    same = false;
elseif size(c1,1)==1 && sum(strcmpi(cellfun(@class,c1,'UniformOutput',false), cellfun(@class,c2,'UniformOutput',false))~=1)>0
    reason1 = sprintf('cellfun(@class,...) different');
    reason2 = sprintf('cellfun(@class,...) different');
    same = false;
elseif size(c1,2)==1 && sum(strcmpi(cellfun(@class,c1,'UniformOutput',false)', cellfun(@class,c2,'UniformOutput',false)')~=1)>0
    reason1 = sprintf('cellfun(@class,...) different');
    reason2 = sprintf('cellfun(@class,...) different');
    same = false;
elseif sum(cellfun(@isempty,c1(isc)) - cellfun(@isempty,c2(isc)))>0
    reason1 = sprintf('cellfun(@isempty,...) different');
    reason2 = sprintf('cellfun(@isempty,...) different');
    same = false;
elseif(sum(abs(cellfun('length',c1(isc))-cellfun('length',c2(isc))))>0)
    reason1 = sprintf('length of cell entries');
    reason2 = sprintf('length of cell entries');
    same = false;
    return;
elseif(isempty(c1) && isempty(c2))
elseif(isnumeric(c1{1}))
    c1 = cell2array(c1);
    c2 = cell2array(c2);
    if(sum(abs(c1(:)-c2(:)))~=0)
        reason1 = sprintf('array entries');
        reason2 = sprintf('array entries');
        same = false;
        return;
    end
elseif(ischar(c1{1}))
    [same] = strcmpCell(c1,c2,1);
    reason1 = 'cell of strings different';
    reason2 = 'cell of strings different';
elseif(iscell(c1{1}))
    for i=1:length(c1)
        same = cellcmp(c1{i},c2{i});
        if(~same)
            reason1 = 'nested cell different';
            reason2 = 'nested cell different';
            return;
        end
    end
elseif isstruct(c1)
    same = structcmp(c1,c2);
else
    save error
    class(c1)
    class(c2)
    error('cellcmp(c1,c2) not yet implemented for this class.')
end


% match = strcmpCell(str1,str2)
%
% Vergleicht str1{i} mit str2{j}
%
%   str1        Zelle von Strings z.B. str1 = {'irgendeinstring'}
%   str2        Zelle von Strings z.B. str1 = {'irgendeinstring'}
%   onlyDiagonal    if 1, dann wird nur str1{i} mit str2{i} verglichen
%
%   match       ist eine Matrix length(str1) x length(str2) mit Nullen und Einsen.

function match = strcmpCell(str1,str2,onlyDiagonal)
if(~exist('onlyDiagonal','var') || onlyDiagonal~=1)
    match = NaN(100);
    for i=1:length(str1)
        for j=1:length(str2)
            match(i,j) = strcmp(str1{i},str2{j});
        end
    end
    match = match(1:i,1:j);
else
    match = NaN(1,1000);
    for i=1:length(str1)
        match(i) = strcmp(str1{i},str2{i});
    end
    match = match(1:i);
end



% a = cell2array(c)
%
%     KOnvertiert eine Zelle in einen Array gleicher Dimension.
function a = cell2array(c)
a = NaN*ones(size(c));
c = {c{:}};
cl = cellfun('length',c);

if(sum(cl==1)==length(cl))
    for i=1:length(c)
        try
            a(i) = c{i};
        catch
            c{i}
            length(c{i})
            class(c{i})
        end
    end
elseif(sum((cl==1) | cl==0)==length(cl))
    for i=1:length(c)
        if(~isempty(c{i}))
            a(i) = c{i};
        else
            a(i) = NaN;
        end
    end
else
    a = NaN*ones(1,sum(cl));
    ind = 0;
    for i=1:length(c)
        a(ind+(1:cl(i))) = c{i};
        ind = ind+cl(i);
    end
end


function fns = allFields(s,onlyFinal)
if(~exist('onlyFinal','var') || isempty(onlyFinal))
    onlyFinal = 0;
end

fns = cell(50000,1);
ii=0;

for is = 1:length(s)
    if(isstruct(s(is)))
        
        fn = fieldnames(s(is));
        for i=1:length(fn)
            if(isstruct(s(is).(fn{i})))
                for j=1:length(s(is).(fn{i}))
                    fns_tmp = allFields(s(is).(fn{i})(j));
                    for k=1:length(fns_tmp)
                        ii=ii+1;
                        fns{ii} = [fn{i},'(',int2str(j),').',fns_tmp{k}];
%                         fns{ii} = sprintf('%s(%i).%s',fn{i},j,fns_tmp{k});
                    end
                end
            elseif(iscell(s(is).(fn{i})) && ~isempty(s(is).(fn{i})) && isstruct(s(is).(fn{i}){1}))
                for j=1:length(s(is).(fn{i}))
                    fns_tmp = allFields(s(is).(fn{i}){j});
                    for k=1:length(fns_tmp)
                        ii=ii+1;
                        fns{ii} = [fn{i},'{',int2str(j),'}.',fns_tmp{k}];
%                         fns{ii} = sprintf('%s{%i}.%s',fn{i},j,fns_tmp{k});
                    end
                end
            else
                ii=ii+1;
                fns{ii} = fn{i};
            end
        end
        
        % else
        %     s(is)
        %     error('allFields.m: No struct provided');
    end
end

fns = fns(1:ii);
back to top