Умные способы превращения функции с двумя входами в функцию с переменной длиной ввода в Matlab - PullRequest
1 голос
/ 18 февраля 2012

Это просто вопрос из интереса.Предположим, у меня есть двоичная функция, которая принимает квадратные матрицы и выводит квадратные матрицы одинакового размера (или, в более общем случае, тип и размер ввода совпадают с типом и размером вывода):

function C = myfunc(A,B)

Примербудет функция Mtimes.Какие есть разные и умные способы превратить это в функцию ввода переменной длины

function C = myfunc_multi(varargin)

, такую, что

myfunc(A{1},myfunc(A{2},myfunc(A{3},...myfunc(A{end-1},A{end})...))) == 
    myfunc_multi(A{:})

?

Это первое общее решение, котороепришел ко мне (редактировать: кроме рекурсии или цикла):

function C = multioutput(functionhandle, varargin)
    n = length(varargin);
    funcstr = functiontostring(functionhandle);
    str = regexprep(arrayfun(@num2str,1:n-1),'(.)',[funcstr '(varargin{$1},']);
    C = eval(sprintf('%svarargin{%d}%s',str,n,repmat(')',1,n-1)));
end

, тогда вы можете проверить это с помощью чего-то вроде

A = {rand(3) rand(3) rand(3) rand(3) rand(3)};
multioutput(@mtimes,A{:})-A{1}*A{2}*A{3}*A{4}*A{5}

, чтобы проверить это.Какие еще способы вы можете придумать?

1 Ответ

5 голосов
/ 18 февраля 2012

Вероятно, нет веской причины избегать очевидной рекурсивной конструкции. Он прост, легко читается и поддерживается, и должен иметь довольно хорошую производительность.

function out = aggregate_inputs(fHandle, varargin)
if nargin>3
    out = fHandle(varargin{1},aggregate_inputs(fHandle,varargin{2:end}));
elseif nargin <= 3
    out = fHandle(varargin{:});
end

Не такой элегантный, но (возможно, *) требующий меньше памяти, - это конструкция цикла

function accumulate = aggregate_inputs(fHandle,varargin)
if nargin<=3
    accumulate  = fHandle(varargin{:});
else
    accumulate = fHandle(varargin{end-1},varargin{end});
    for ix = (length(varargin)-2):-1:1
       acumulate = fHandle(varargin{ix}, accumulate);
    end
end

Конечно, ваш вопрос снял эти конструкции с рассмотрения ... так что на самом деле нет хорошего способа сделать это, что я вижу.


Если говорить о философии на минуту, то верно, что многие операции с Matlab могут выполняться намного быстрее с помощью векторизованных вызовов. Иногда это интерпретируется как «избежать петли любой ценой». Однако избегание циклов с вызовами cellfun, arrayfun или (пожалуйста, нет) eval, как правило, не повышает производительность. Иногда это правильно делать по другим причинам ... но это не помогает "векторизовать ваш код, чтобы сделать его быстрее".


* «Возможно» выше просто потому, что я не уверен, насколько хорошо ленивое копирование при записи Matlab и другие оптимизации предотвратят использование памяти, которое кажется потенциальной опасностью при рекурсивном решении.

...