function [effective_vary_indices, linked_indices] = dsCheckCovary(vary_lengths, vary_params, varargin)
  %CHECKCOVARY - TODO I assume this checks if any varied parameters are covaried?
 
  %% localfn output
  if ~nargin
      effective_vary_indices = localfunctions; % output var name specific to this fn
      return
  end
  
  %% 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};
      argin = [{vary_lengths}, {data_length}, varargs]; % specific to this function
  end
  
  %% Function start.
  data_length = size(vary_params, 1);

  % Remove any vary statements used to set parameter values.
  non_singleton_vary_indices = vary_lengths > 1;
  non_singleton_vary_lengths = vary_lengths(non_singleton_vary_indices);
  non_singleton_vary_params = vary_params(:, non_singleton_vary_indices);
  n_varied = length(non_singleton_vary_lengths);

  %% Check all combinations of varied parameters to see if the product of the number
  % of their unique values describes the amount of data simulated.
  full_rank_choices = {};
  index = 1;

  for n_chosen = 1:n_varied
    % Check all pairs, then all triplets...
    choices = nchoosek(1:n_varied, n_chosen);
    n_choices = nchoosek(n_varied, n_chosen);

    % For each subset of varied parameters, see if the product of the numbers of
    % unique parameters equals data_length.
    for choice = 1:n_choices
      estimated_data_length = prod(non_singleton_vary_lengths(choices(choice, :)));
      if estimated_data_length == data_length
        full_rank_choices{index} = choices(choice, :);
        index = index + 1;
      end
    end

  end

  linked_indices = {};
  
  %% Parse the results of finding "full rank" choices.
  if isempty(full_rank_choices)
    % No combination of varied parameters equals total data length,
    % so treat data as linear.
    linked_indices{1} = 1:n_varied;

  else
    % If one or more combinations of varied parameters describes the total data length,
    % we need to link covaried parameters.
    no_full_rank_choices = length(full_rank_choices);

    % Create a matrix in which each row represents a full rank choice of varied parameters.
    full_rank_participation = zeros(no_full_rank_choices, n_varied);
    for frc = 1:no_full_rank_choices
      full_rank_participation(frc, full_rank_choices{frc}) = 1;
    end
    
    % If a certain parameter is not involved in any "full rank" product,
    % consider it linked.
    index = 1;
    non_participating_parameters = find(all(full_rank_participation == 0, 1));
    if ~isempty(non_participating_parameters)
        linked_indices{index} = [0 non_participating_parameters];
        index = index + 1;
    end

    if no_full_rank_choices > 1
        %%
        % If more than one combination of varied parameters describes the total
        % data length, we have to figure out which of these varied
        % parameters is co-varied.
        param_indices = find(sum(full_rank_participation, 1) > 0);
        
        iteration_number = 1;
        while length(param_indices) > 1
            [linked_set, param_indices] = find_linked_params(param_indices, non_singleton_vary_params, varargin{:});
            
            if ~isempty(linked_set)
                linked_indices{index} = linked_set;
                index = index + 1;
            end
            
            iteration_number = iteration_number + 1;
            if iteration_number > 10
                return
            end
        end
        
    end

  end

  % Remove linked sets of parameters from effective_vary_lengths.
  marked_for_removal = zeros(size(non_singleton_vary_lengths));
  for l = 1:length(linked_indices)
    marked_for_removal(linked_indices{l}(2:end)) = 1;
  end
  % effective_vary_lengths = non_singleton_vary_lengths;
  % effective_vary_lengths(logical(marked_for_removal)) = [];
  effective_non_singleton_vary_indices = ~marked_for_removal;
  
  effective_vary_indices = false(size(vary_lengths));
  
  effective_vary_indices(non_singleton_vary_indices) = logical(effective_non_singleton_vary_indices);
  
  %% auto_gen_test_data_flag argout
  if options.auto_gen_test_data_flag
      argout = {effective_vary_lengths, linked_indices}; % specific to this function
      
      dsUnitSaveAutoGenTestData(argin, argout);
  end

end

function [linked_indices, non_linked_indices] = find_linked_params(param_indices, vary_params, varargin)

%% 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};
  argin = [{param_indices},{vary_params}, varargs];
end

param1_index = param_indices(1);

if iscellstr(vary_params)
    params_at_value1 = vary_params(strcmp(vary_params(:, param1_index),vary_params(1, param1_index)), :);
    
%params_at_value1 = vary_params(cellfun(@(x) isequal(x, vary_params(1, param1_index)),vary_params(:, param1_index)), :);
elseif isnumeric(vary_params)
    params_at_value1 = vary_params(vary_params(:, param1_index) == vary_params(1, param1_index), :);
elseif iscellnum(vary_params)
    vary_params2 = cell2mat(vary_params);
    params_at_value1 = vary_params(vary_params2(:, param1_index) == vary_params2(1, param1_index), :);
else
    try
        params_at_value1 = vary_params(vary_params(:, param1_index) == vary_params(1, param1_index), :);
    catch
        error('case not implemented. vary_params must all cell array of chars of all numeric');
    end
end

no_values_at_value1 = nan(size(param_indices));

no_values_at_value1(1) = 1;

for p = 2:length(param_indices)
  
  param_index = param_indices(p);
  
  no_values_at_value1(p) = length(unique(params_at_value1(:, param_index)));
  
end

linked_indices = param_indices(no_values_at_value1 == 1);

non_linked_indices = param_indices(no_values_at_value1 > 1);


%% 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