function [data, variedname_merged, varied_vals ] = dsAutoMergeVarieds(data,strategy,verbose_on,varargin)
% [data_new, variedname_merged, varied_vals ] = mergeVarieds(data,varied_fields)
%
% Need to write this description.
%
% % % % % % % % % % % % % % % % % % % % %
%
% A1=[1,3,1];A2=[1,5,2]; A3=[2,3,4];
% B1=[6,2,9];B2=[4,5,1]; B3=[1,2,5];
% M = [A1 B1 ; A2 B1 ; A3 B1 ;
% A1 B2; A2 B2; A3 B2;
% A1 B3; A2 B3; A3 B3];
% % % % % % % % % % % % % % % % % % % % %
% auto_gen_test_data_flag argin
options = dsCheckOptions(varargin,{'auto_gen_test_data_flag',0,{0,1}},false);
if options.auto_gen_test_data_flag
varargs = varargin;
varargs{find(strcmp(varargs, 'auto_gen_test_data_flag'))+1} = 0;
varargs(end+1:end+2) = {'unit_test_flag',1};
end
maxiter = 10000;
success_thresh = 0.5;
variedname_merged = {};
varied_vals = {};
if nargin < 3; verbose_on = false; end
% % % % % % % % % % % %
% Add in section for pre-screening for linearly depndence as well
% % % % % % % % % % % %
% Build vary_parms - cell array of varied params (sims x parameters)
N = length(data);
vary_labels = data(1).varied; % data(1).simulator_options.vary;
Nvarieds = length(vary_labels);
for i = 1:N
for j = 1:Nvarieds
vary_params{i,j} = data(i).(vary_labels{j});
end
end
% Convert everything to strings for easier analysis
vary_params = all2str(vary_params);
percent_full = getpercentfull(vary_params);
if percent_full > success_thresh; return; end
[cols2merge] = find_shortest_mergelist(vary_params,success_thresh,maxiter); %
if isempty(cols2merge); cols2merge = 1:size(vary_params,2); end
% Now, see if it is possible to subdivide the merged list
cols_list{1} = cols2merge;
cols_list = subdivide_ind_list(vary_params,cols_list,success_thresh,maxiter);
% Merge eached linked_ind into a single varied statement
vary_labels = data(1).varied; % data(1).simulator_options.vary;
Nlinked = length(cols_list);
variedname_merged = cell(1,Nlinked);
varied_vals = cell(1,Nlinked);
for j = 1:Nlinked
[data, variedname_merged{j}, varied_vals{j} ] = dsMergeVarieds(data,vary_labels(cols_list{j}));
end
% auto_gen_test_data_flag argout
if options.auto_gen_test_data_flag
argout = {linked_indices, non_linked_indices}; % specific to this function
dsUnitSaveAutoGenTestDataLocalFn(argin, argout); % localfn
end
end
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
% % % % % % % % % % % % Main subfunctions % % % % % % % % % %
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
function [cols2merge_out] = find_shortest_mergelist(vary_params,success_thresh,maxiter)
% maxiter = 10000;
% success_thresh = 0.999;
if ~ismatrix(vary_params); error('vary_params cell array must be MxN');end
sz = size(vary_params);
Nparams = sz(2);
% Loop through various options
count = 0;
cols2merge_out = [];
for i = 2:Nparams-1
b = nchoosek(Nparams,i); % Number of possible choices
C = nchoosek(1:Nparams,i); % Combinations
for j = 1:b
count = count + 1;
cols2merge = C(j,:);
vary_merged = mergevary(vary_params,cols2merge);
percent_full = getpercentfull(vary_merged);
if percent_full > success_thresh; cols2merge_out = cols2merge; return; end
if count > maxiter ; cols2merge_out = []; return; end
end
end
end
function cols_list = subdivide_ind_list(vary_params,cols_list,success_thresh,maxiter)
% maxiter = 10000;
% success_thresh = 0.999;
ind_last = cols_list{end};
Nlast = length(ind_last);
if Nlast < 4; return; end % We can't up anything less than 4 columns, since the smallest grouping we can have is 2 (e.g. 3 columns would divide into 2 and 1; but can't merge 1 column)
count = 0;
for i = 2:floor(Nlast/2) % If Nlast it 9, only go up to 4 since choosing 4 will implicitly choose 5 leftover
b = nchoosek(Nlast,i);
C = nchoosek(1:Nlast,i);
for j = 1:b
count = count + 1;
inds2merge1 = C(j,:);
inds2merge2 = setxor(1:Nlast,inds2merge1); % Get complement of chosen inds (e.g. unchosen columns) (see https://www.mathworks.com/matlabcentral/newsreader/view_thread/45631)
colslast1 = ind_last(inds2merge1);
colslast2 = ind_last(inds2merge2);
vary_merged = mergevary(vary_params,cols_list{1:end-1},colslast1,colslast2); % Merge columns as needed (note: need to convert indices to be in terms of vary_params)
percent_full = getpercentfull(vary_merged);
if percent_full > success_thresh
cols_list{end} = inds2merge1;
cols_list{end+1} = inds2merge2;
cols_list = subdivide_ind_list(vary_params,cols_list,success_thres,maxiter); % Recursive call (see if we can subdivide it further).
return;
end
if count > maxiter ; cols2merge_out = []; warning('Aborting: Exceeded maximum iterations; consider increasing maxiter '); return; end
end
end
end
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
% % % % % % % % % % Supporting subfunctions % % % % % % % % %
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
function vary_params = all2str(vary_params)
% Convert all vary_params from numerics to strings
for i = 1:numel(vary_params)
if isnumeric(vary_params{i}); vary_params{i} = num2str(vary_params{i});
elseif ischar(vary_params{i}); % Good
else
error('vary_param entries must be of type numeric or char');
end
end
end
function out = mergevary(in,varargin)
merge_inds_cell = varargin;
sz = size(in);
Ncols = sz(2);
out = in;
for i = 1:length(merge_inds_cell)
out = mergevary_sub(out,merge_inds_cell{i});
end
% Discard cols2merge(2:end), which have been merged into cols2merge(1)
ci = true(1,Ncols);
for i = 1:length(merge_inds_cell)
cols_curr = merge_inds_cell{i};
ci(cols_curr(2:end)) = false;
end
out = out(:,ci);
end
function out = mergevary_sub(in,cols2merge)
if length(cols2merge) < 2; error('Must supply at least 2 cols to merge');
end
sz = size(in);
Nrows = sz(1);
out = in;
for i = 1:Nrows
out{i,cols2merge(1)} = cat_with_underscores(in(i,cols2merge));
end
end
function str_out = cat_with_underscores(cellstr_in)
% Takes in a cell array of chars and concatenates them together with
% underscores separating the original divisions between cells. E.g.
% {'cat','dog'} becomes 'cat_dog'
temp = vertcat(cellstr_in(:)', repmat({'_'},1,length(cellstr_in)));
temp = temp(:)';
str_out = horzcat(temp{1:end-1});
end
function percent_full = getpercentfull(vary_merged)
sz = size(vary_merged);
Nsims = sz(1);
Nparams = sz(2);
vmu = cell(1,Nparams);
for j = 1:Nparams
vmu{j} = uniqueCellGeneralized(vary_merged(:,j));
end
Nuniq = cellfun(@length,vmu);
percent_full = Nsims / prod(Nuniq);
end