在matlab中将双输入函数转换为可变长度输入函数的巧妙方法

时间:2012-02-17 21:54:10

标签: function matlab arguments

这只是一个有趣的问题。假设我有一个二进制函数,它接受方形矩阵并输出相同大小的方形矩阵(或者更一般地说,它的输入类型和大小与其输出类型和大小相同):

function C = myfunc(A,B)

一个例子是mtimes funcion。将此变为可变长度输入函数有哪些不同且巧妙的方法

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 个答案:

答案 0 :(得分:5)

可能没有充分的理由避免明显的递归构造。它简单易读,易于维护,性能非常好。

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的懒惰写入和其他优化会如何阻止内存使用,这似乎是递归解决方案的潜在危险。