【问题标题】:How to write an anonymous function with a variable number of output arguments?如何编写具有可变数量输出参数的匿名函数?
【发布时间】:2018-07-04 16:32:59
【问题描述】:

使用deal,我们可以编写具有多个输出参数的匿名函数,例如

minmax = @(x)deal(min(x),max(x));
[u,v] = minmax([1,2,3,4]); % outputs u = 1, v = 4

但是如果你想为优化函数fminunc提供一个带有梯度的函数,这是行不通的。 函数fminunc 调用输入函数有时用一个,有时用两个输出参数。 (编辑:这不是真的,你只需要指定你是否真的想使用渐变与否,使用例如optimset('SpecifyObjectiveGradient',true)。然后在一次调用中它总是要求相同数量的参数。)

我们必须提供类似的东西

function [f,g] = myFun(x)
 f = x^2; % function
 g = 2*x; % gradient

可以用一个两个输出参数调用。

那么有没有办法在不使用 function 关键字的情况下执行相同的内联操作?

【问题讨论】:

  • 旁注:与您的 minmax 类似的函数最近 (R2017a) 以 bounds 的名称添加到 MATLAB。

标签: matlab output variadic-functions anonymous-function function-handle


【解决方案1】:

是的,它涉及this question 中使用的关于递归匿名函数的技术。首先我们定义一个辅助函数

helper = @(c,n)deal(c{1:n});

它接受可能输出的单元数组c 以及表示我们需要多少输出的整数n。要编写我们的实际函数,我们只需要定义元胞数组并将nargout(预期输出参数的数量)传递给helper

myFun = @(x)helper({x^2,2*x,2},nargout);

现在调用 fminunc 时可以完美运行:

x = fminunc(myFun,1);

【讨论】:

    【解决方案2】:

    OP's solution 的优点在于它简洁且在许多情况下有用。

    但是,它有一个主要缺点,那就是它的可扩展性不如其他方式。提出此声明是因为对所有函数 ({x^2,2*x,2}) 进行了评估,无论它们是否需要作为输出 - 当请求的输出少于 3 个时,这会导致“浪费”计算时间和内存消耗。

    在这个问题的例子中,这不是问题,因为函数及其导数很容易计算,输入 x 是一个标量,但在不同的情况下,这可以是一个非常现实的问题。

    我提供了一个修改版,虽然比较丑,但避免了上述问题,而且更通用:

    funcs_to_apply = {@(x)x.^2, @(x)2*x, @(x)2};
    unpacker = @(x)deal(x{:});
    myFun = @(x)unpacker(cellfun(@(c)feval(c,x),...
                                 funcs_to_apply(1:evalin('caller','nargout')),...
                                 'UniformOutput',false)...
                        );
    

    注意事项:

    1. 我使用的附加函数是cellfunevalinfeval
    2. 仅添加了 'UniformOutput' 参数,以便 cellfun 的输出是一个单元格(并且可以“解压缩”到 comma-separated list;我们可以将其包装在 num2cell 中)。李>
    3. evalin 技巧是必需的,因为在 myFun 范围内,我们不知道从 unpacker 请求了多少输出。
    4. 虽然 eval 的各种形式(此处为:evalin)通常不被鼓励,但在这种情况下,我们确切地知道调用者是谁,这是一个安全的操作。

    【讨论】:

      猜你喜欢
      • 2018-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多