0001 function [pop_diff,conn_diff] = dsSpecDiff(spec1,spec2,verbose)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 debug_mode = 0;
0020
0021 if nargin < 3
0022 verbose = true;
0023 end
0024
0025
0026 if ~exist('MDD','class')
0027 fprintf('This function requires the class MDD. Make sure this is in your MATLAB path.\n');
0028 fprintf('It can be downloaded from the following links: \n.');
0029 fprintf('1. https://github.com/davestanley/nDDims \n');
0030 fprintf('2. https://www.mathworks.com/matlabcentral/fileexchange/61656-multidimensional-dictionaries\n');
0031 error('Missing dependency');
0032 end
0033
0034
0035
0036
0037
0038 [val1,pop_name1,property1] = extract_pop_lists(spec1.populations);
0039 [val2,pop_name2,property2] = extract_pop_lists(spec2.populations);
0040
0041
0042 if debug_mode
0043
0044 table = horzcat(pop_name1,property1,val1);
0045 table
0046 end
0047
0048
0049
0050 val = vertcat(val1,val2);
0051 pop_names = vertcat(pop_name1,pop_name2);
0052 properties = vertcat(property1,property2);
0053 specID = vertcat(1*ones(length(val1),1), 2*ones(length(val2),1));
0054
0055 if debug_mode
0056
0057 table = horzcat(pop_name1,property1,specID,val1);
0058 table
0059 end
0060 clear val1 val2 pop_name1 pop_name2 propert1 property2
0061
0062
0063
0064 nd = MDD;
0065 nd = nd.importDataTable(val,{pop_names,properties,specID});
0066 nd.axis(1).name = 'Populations';
0067 nd.axis(2).name = 'Properties';
0068 nd.axis(3).name = 'SpecID';
0069
0070 if debug_mode
0071 nd.printAxisInfo
0072 end
0073
0074 if verbose; run_comparison(nd); end
0075 if nargout > 0; pop_diff = return_comparison(nd); end
0076
0077 if verbose; fprintf('\n\n'); end
0078
0079
0080
0081
0082 if isfield(spec1, 'connections')
0083 [val1,pop_name1,property1] = extract_conn_lists(spec1.connections);
0084 else
0085 val1 = {}; pop_name1 = {}; property1 = {};
0086 end
0087
0088 if isfield(spec2, 'connections')
0089 [val2,pop_name2,property2] = extract_conn_lists(spec2.connections);
0090 else
0091 val2 = {}; pop_name2 = {}; property2 = {};
0092 end
0093
0094
0095
0096 val = vertcat(val1,val2);
0097 pop_names = vertcat(pop_name1,pop_name2);
0098 properties = vertcat(property1,property2);
0099 specID = vertcat(1*ones(length(val1),1), 2*ones(length(val2),1));
0100
0101 clear val1 val2 pop_name1 pop_name2 propert1 property2
0102
0103
0104
0105 if ~isempty(val)
0106 nd = MDD;
0107 nd = nd.importDataTable(val,{pop_names,properties,specID});
0108 nd.axis(1).name = 'Connections';
0109 nd.axis(2).name = 'Properties';
0110 nd.axis(3).name = 'SpecID';
0111
0112 if debug_mode
0113 nd.printAxisInfo
0114 end
0115
0116 if verbose; run_comparison(nd); end
0117 if nargout > 1; conn_diff = return_comparison(nd); end
0118
0119 else
0120 conn_diff = struct();
0121 end
0122
0123 end
0124
0125
0126
0127 function [val,pop_name,properties] = extract_pop_lists(s)
0128
0129
0130
0131
0132 Nparams = arrayfun(@(x) length(x.parameters),s) / 2;
0133 Nproperties = Nparams + 3;
0134 val = cell(sum(Nproperties),1);
0135 pop_name = val;
0136 properties = val;
0137
0138 N = length(s);
0139
0140 k=0;
0141 for i = 1:N
0142 k=k+1; field = 'size'; pop_name{k} = s(i).name; properties{k} = ['spec_' field]; val{k} = s(i).(field);
0143 k=k+1; field = 'equations'; pop_name{k} = s(i).name; properties{k} = ['spec_' field]; val{k} = s(i).(field);
0144 k=k+1; field = 'mechanism_list'; pop_name{k} = s(i).name; properties{k} = ['spec_' field]; val{k} = s(i).(field);
0145 param_names = s(i).parameters(1:2:end);
0146 param_vals = s(i).parameters(2:2:end);
0147 for j = 1:length(param_names)
0148 k=k+1; pop_name{k} = s(i).name; properties{k} = param_names{j}; val{k} = param_vals{j};
0149 end
0150 end
0151 end
0152
0153
0154 function [val,pop_name,properties] = extract_conn_lists(s)
0155
0156
0157
0158
0159 Nparams = arrayfun(@(x) length(x.parameters),s) / 2;
0160 Nproperties = Nparams + 1;
0161 val = cell(sum(Nproperties),1);
0162 pop_name = val;
0163 properties = val;
0164
0165 N = length(s);
0166
0167 k=0;
0168 for i = 1:N
0169 k=k+1; field = 'mechanism_list'; pop_name{k} = s(i).direction; properties{k} = ['spec_' field]; val{k} = s(i).(field);
0170 param_names = s(i).parameters(1:2:end);
0171 param_vals = s(i).parameters(2:2:end);
0172 for j = 1:length(param_names)
0173 k=k+1; pop_name{k} = s(i).direction; properties{k} = param_names{j}; val{k} = param_vals{j};
0174 end
0175 end
0176 end
0177
0178
0179
0180 function out = mycompare(x,y)
0181 if isempty(x) && isempty(y)
0182 out = -3;
0183 elseif isempty(x) && ~isempty(y)
0184 out = -1;
0185 elseif ~isempty(x) && isempty(y)
0186 out = -2;
0187 else
0188
0189 if isnumeric(x) && isnumeric(y)
0190 out = x == y;
0191 elseif ischar(x) && ischar(y)
0192 out = strcmp(x,y);
0193 elseif iscell(x) && iscell(y)
0194 if length(x) == length(y)
0195 temp = cellfun(@(x2,y2) mycompare(x2,y2),x,y);
0196 out = any(temp == 1);
0197 else
0198 out = -4;
0199 end
0200 else
0201 out = -5;
0202 end
0203 end
0204
0205 out = double(out);
0206 end
0207
0208
0209 function fprintf_cells(string,cells2print)
0210 if ~isempty(cells2print)
0211 cells2print = cellfunu(@(x) [x ' '], cells2print);
0212 fprintf([string ' ' cells2print{:} '\n']);
0213 end
0214
0215 end
0216
0217
0218 function [str_merged,ind1,ind2] = compare_string_cells(string1,string2)
0219 str_merged = vertcat(string1(:),string2(:));
0220 str_merged = unique(str_merged);
0221
0222 Nstr = length(str_merged);
0223
0224 ind1 = false(1,Nstr);
0225 ind2 = false(1,Nstr);
0226 for i = 1:length(str_merged)
0227 ind1(i) = any(strcmp(str_merged{i},string1));
0228 ind2(i) = any(strcmp(str_merged{i},string2));
0229 end
0230
0231 end
0232
0233
0234 function run_comparison(nd)
0235
0236
0237
0238 allpops = nd.axis(1).values';
0239 Npops = length(allpops);
0240 spec1_pops = nd.axis(1).values(any(~cellfun(@isempty,nd.data(:,:,1)),2))';
0241 spec2_pops = nd.axis(1).values(any(~cellfun(@isempty,nd.data(:,:,2)),2))';
0242
0243
0244
0245 ind1 = false(1,Npops);
0246 ind2 = false(1,Npops);
0247
0248 for i = 1:length(allpops)
0249 ind1(i) = any(strcmp(allpops{i},spec1_pops));
0250 ind2(i) = any(strcmp(allpops{i},spec2_pops));
0251 end
0252
0253 name = lower(nd.axis(1).name);
0254 fprintf('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n');
0255 fprintf(['~~~~~~~~~~~~~~~~~~~~~~~~Comparison of ' name ' ~~~~~~~~~~~~~~~~~~~~~~~~~\n']);
0256 fprintf('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n');
0257 fprintf_cells('Populations only in spec1:', allpops(ind1 & ~ind2));
0258 fprintf_cells('Populations only in spec2:', allpops(~ind1 & ind2));
0259 fprintf_cells('Populations in both:', allpops(ind1 & ind2));
0260 fprintf('\n');
0261
0262
0263
0264
0265 inds_both = find(ind1 & ind2);
0266
0267
0268
0269 params1 = nd.data(:,:,1);
0270 params2 = nd.data(:,:,2);
0271
0272 inds = cellfunu(@(x,y) mycompare(x,y), params1,params2);
0273 inds2 = cell2mat(inds);
0274
0275
0276
0277 for i = inds_both
0278
0279 inds_curr = inds2(i,:);
0280 inds_different = inds_curr ~= 1;
0281 inds_different(inds_curr == -3) = 0;
0282
0283 if any(inds_different)
0284
0285 fprintf('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n');
0286 fprintf(['Comparing mechs in ' name ' ' nd.axis(1).values{i} ' \n']);
0287
0288
0289
0290
0291 nd1 = nd.subset(i,'spec_mechanism_list',1);
0292 nd2 = nd.subset(i,'spec_mechanism_list',2);
0293 [str_merged,ind1,ind2] = compare_string_cells(nd1.data{:},nd2.data{:});
0294 fprintf_cells('Mechs only in spec1:', str_merged(ind1 & ~ind2));
0295 fprintf_cells('Mechs only in spec2:', str_merged(~ind1 & ind2));
0296
0297
0298
0299
0300
0301 temp = inds_curr == -1; fprintf_cells(['Parameters present in spec1 but missing in spec2:' ], nd.axis(2).values(temp));
0302 temp = inds_curr == -2; fprintf_cells(['Parameters present in spec2 but missing in spec1:' ], nd.axis(2).values(temp));
0303 temp = inds_curr == -4; fprintf_cells(['Parameters are incomparable because they are cell arrays of different lengths:' ], nd.axis(2).values(temp));
0304 temp = inds_curr == -5; fprintf_cells(['Parameters are incomparable because they are different data types (e.g. one is string, one is numeric):' ], nd.axis(2).values(temp));
0305
0306 temp = inds_curr == 0; fprintf_cells(['Parameters differing between ' nd.axis(1).values{i} ':' ], nd.axis(2).values(temp));
0307
0308
0309 ind_diff = find(inds_curr == 0);
0310 for j = ind_diff
0311 val1 = nd.data{i,j,1};
0312 val2 = nd.data{i,j,2};
0313 if isnumeric(val1); val1 = num2str(val1); end
0314 if isnumeric(val2); val2 = num2str(val2); end
0315 if ischar(val1) && ischar(val2)
0316 fprintf(['Mechanism ' nd.axis(2).values{j} ' is ' val1 ' for spec1 and ' val2 ' for spec2 \n']);
0317 end
0318 end
0319
0320 fprintf('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n');
0321 end
0322
0323 end
0324 end
0325
0326 function s = return_comparison(nd)
0327
0328 sz = size(nd.data);
0329 Npop = sz(1);
0330
0331 for i = 1:Npop
0332 s(i).name = nd.axis(1).values(i);
0333 temp = horzcat(nd.axis(2).values, nd.data(i,:,1)', nd.data(i,:,2)');
0334 inds = cellfun(@(x,y) isempty(x) && isempty(y),temp(:,2), temp(:,3));
0335 temp = temp(~inds,:);
0336 s(i).parameter_names_values = temp;
0337
0338 str = 'spec_size'; ind = strcmp(nd.axis(2).values,str); if any(ind); s(i).([str '1']) = nd.data{i,ind,1}; s(i).([str '2']) = nd.data{i,ind,2}; end
0339 str = 'spec_equations'; ind = strcmp(nd.axis(2).values,str); if any(ind); s(i).([str '1']) = nd.data{i,ind,1}; s(i).([str '2']) = nd.data{i,ind,2}; end
0340 str = 'spec_mechanism_list'; ind = strcmp(nd.axis(2).values,str); if any(ind); s(i).([str '1']) = nd.data{i,ind,1}; s(i).([str '2']) = nd.data{i,ind,2}; end
0341 end
0342
0343
0344 end