Frage

I am trying to write some code which feeds a function with an unknown number of parameters. The idea is to feed the function the minimum, middle and maximum value within the possible range of values.

For example:

  • If the function takes 3 parameters
  • Parameter 1 can accept a range of 0 - 10
  • Parameter 2 can accept a range of 20 - 40
  • Parameter 3 can accept a range of 6 - 66

myfunction(para1, para2, para3)
myfunction(min,min,min)
myfunction(min,min,mid)
myfunction(min,min,max)
myfunction(min,mid,min)
myfunction(min,mid,mid)
myfunction(min,mid,max)
etc...

so using our example above:

The first time it loops I need to run
myfunction(0, 20, 0)
next time it loops it needs to run
myfunction(0, 20, 36)
next time it loops it needs to run
myfunction(0, 20, 66)
etc...

For all possible combinations (in this case all 27).
However, if the number of parameters changes to accept 4, it needs to be able to accommodate that and so on. I've looked into doing it as a loop or recursively, but I thought as a loop would be easier to understand, but either would be really helpful.

I don't want to have to do this manually so any help will be much appreciated.

War es hilfreich?

Lösung

For an arbitrary number of parameters (not fixed to 3), you can use the following code. It makes use of comma-separated lists, which is a powerful tool to handle a variable number of parameters.

Let n be the number of parameters. Then the number of combinations is N = 3^n.

params = {linspace(0,10,3), linspace(20,40,3), linspace(6,66,3)};
%// cell array with arbitrary number of elements. Each cell contains a 3-vector
%// which defines min, mid, max of one parameter.

n = numel(params); %// number of parameters
N = 3^n; %// number of combinations
paramCombs = cell(1,n); %// initialization for output of ndgrid
[paramCombs{end:-1:1}] = ndgrid(params{end:-1:1}); %// generate all combinations
%// in desired order. Gives n matrices, each containing values of one parameter
paramCombs = cellfun(@(c) c(:), paramCombs, 'uni', 0); %// linearize matrices
%// into n column vectors, each with N rows.
paramCombs = [paramCombs{:}]; %// concat column vectors into N x n matrix
paramCombs = mat2cell(paramCombs,ones(N,1),ones(n,1)); %// convert to
%// N x n cell array. Each row contains a combination of parameter values
result = arrayfun(@(n) myFun(paramCombs{n,:}), 1:N, 'uni', 0); %// call myFun
%// with each combination of parameter values

The result variable is a 1 x N cell array, where each cell contains the result of calling myFun with a combination of the n parameters.

Example 1: myFun's output simply replicates the input (as in @thewaywewalk's answer). params is defined as given above, so there are 3 parameters:

>> result{1}
ans =
     0    20     6
>> result{2}
ans =
     0    20    36
>> result{3}
ans =
     0    20    66
>> result{4}
ans =
     0    30     6
>> result{5}
ans =
     0    30    36

etc.

Example 2: case with 2 parameters: params = {linspace(0,2,3), linspace(0,10,3)}. Again, myFun simply replicates the input:

>> result{1}
ans =
     0     0
>> result{2}
ans =
     0     5
>> result{3}
ans =
     0    10
>> result{4}
ans =
     1     0
>> result{5}
ans =
     1     5

etc.

The method can be further generalized to an arbitrary (and possibly different) number of values for each parameter, just replacing the line N = 3^n; by

N = prod(cellfun(@numel, params)); %// number of combinations

Example 3: there are 2 parameters; the first with 3 values, and the second with 2: params = {[1 2 3], [10 20]};:

>> result{1}
ans =
     1    10
>> result{2}
ans =
     1    20
>> result{3}
ans =
     2    10
>> result{4}
ans =
     2    20
>> result{5}
ans =
     3    10
>> result{6}
ans =
     3    20

Andere Tipps

Think about something like this:

function result = permfunction() 

% I assume you every parameter-range is defined by 3 values: min, mid, max
% you can define every triple as follows:
para1 = linspace(0,10,3);
para2 = linspace(20,40,3);
para3 = linspace(6,66,3);

% all possible parameters
parameters = [para1(:),para2(:),para3(:)];

% possible combinations of parameters-indices
a = perms(1:3);  
% transformed into a cell array with linear indices, to achieve this +3 and +6 
% are added to the 2nd and 3rd row.

idx = mat2cell( [a(:,1) , a(:,2)+3 , a(:,3)+6] , ones(length(a),1) );

% all parameter combinations
combinations = cellfun(@(x) parameters(x),idx,'uni',0');

% apply to your function myfunction (custom)
result = cellfun(@myfunction, combinations,'uni',0' );

end

function y = myfunction( parametertriple )

%just pass the input to the output
y = parametertriple;

end

you finally get a cell array with the results of myfunction for all your combinations of parameters. In this case I just passed the parameters to the output:

>> celldisp(ans)

ans{1} =

    10    30     6

ans{2} =

    10    20    36

ans{3} =

     5    40     6

ans{4} =

     5    20    66

ans{5} =

     0    30    66

ans{6} =

     0    40    36

This is how I would solve it:

%dummy function
testfun=@(a,b,c)fprintf('call function for %d,%d,%d\n',a,b,c);
%functon name
testfunname='testfun';
%intended inputs
input={[0,5,10],[20,30,40],[6,36,66]};
%generate all inputs
eval(['[' sprintf('a{%d} ',1:numel(input)) ']=meshgrid(input{:});']);
%call function
eval(['arrayfun(' testfunname sprintf(',a{%d} ',1:numel(input)) ');']);

Using eval is a dirty solution, but I don't find an alternative which allows variable input size.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top