Выполнить все возможные перестановки входных параметров (логика двоичного стиля)
Я пытаюсь написать код, который передает функцию с неизвестным количеством параметров. Идея состоит в том, чтобы передать функции минимальное, среднее и максимальное значение в пределах возможного диапазона значений.
Например:
- Если функция принимает 3 параметра
- Параметр 1 может принимать диапазон от 0 до 10
- Параметр 2 может принимать диапазон от 20 до 40
- Параметр 3 может принимать диапазон от 6 до 66
моя функция (пара1, пара2, пара3)
MyFunction (мин, мин, мин)
MyFunction (мин, не менее, в середине)
MyFunction (мин, мин, макс)
MyFunction (мин, в середине, мин)
MyFunction (мин, в середине, в середине)
MyFunction (мин, в середине, макс)
так далее...
Итак, используя наш пример выше:
Первый раз, когда он зацикливается, мне нужно запустить
моя функция (0, 20, 0)
в следующий раз он зацикливается, нужно запустить
моя функция (0, 20, 36)
в следующий раз он зацикливается, нужно запустить
моя функция (0, 20, 66)
так далее...
Для всех возможных комбинаций (в данном случае всего 27).
Однако, если число параметров изменяется, чтобы принять 4, оно должно быть в состоянии приспособиться к этому и так далее. Я решил сделать это как цикл или рекурсивно, но я думал, что цикл будет легче понять, но любой из них будет действительно полезным.
Я не хочу делать это вручную, поэтому любая помощь будет высоко ценится.
3 ответа
Для произвольного количества параметров (не фиксированных до 3) вы можете использовать следующий код. Он использует разделенные запятыми списки, которые являются мощным инструментом для работы с переменным количеством параметров.
Пусть n будет количеством параметров. Тогда число комбинаций равно 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
result
переменная представляет собой массив ячеек размером 1 x N, где каждая ячейка содержит результат вызова myFun
с комбинацией из n параметров.
Пример 1: myFun
вывод просто повторяет ввод (как в ответе @thewaywewalk). params
определяется как указано выше, поэтому есть 3 параметра:
>> 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
и т.п.
Пример 2: случай с 2 параметрами: params = {linspace(0,2,3), linspace(0,10,3)}
, Снова, myFun
просто повторяет ввод:
>> 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
и т.п.
Метод может быть далее обобщен на произвольное (и, возможно, различное) число значений для каждого параметра, просто заменяя строку N = 3^n;
от
N = prod(cellfun(@numel, params)); %// number of combinations
Пример 3: есть 2 параметра; первый с 3 значениями, а второй с 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
Подумайте о чем-то вроде этого:
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
вы наконец получаете массив ячеек с результатами функции myfunction для всех ваших комбинаций параметров. В этом случае я просто передал параметры на выход:
>> 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
Вот как бы я решил это:
%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)) ');']);
С помощью eval
это грязное решение, но я не нахожу альтернативу, которая допускает переменный размер ввода.