繁体   English   中英

如何使用可变数量的输出参数编写匿名函数?

[英]How to write an anonymous function with a variable number of output arguments?

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

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

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

我们必须提供类似的东西

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

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

那么有没有办法在不使用function关键字的情况下进行同样的内联?

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

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);

OP的解决方案很好,因为它在许多情况下简洁而有用。

然而,它有一个主要的缺点,因为它的可扩展性低于其他可能的。 之所以提出这个主张,是因为所有函数( {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的输出是一个单元格(并且可以“解包”到以逗号分隔的列表 ;我们可以将它包装在num2cell )。
  3. evalin技巧是必需的,因为在myFun范围内,我们不知道从unpacker请求了多少输出。
  4. 虽然通常不鼓励各种形式的eval (这里: evalin ),但在这种情况下,我们确切地知道调用者是谁,这是一个安全的操作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM