使用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
关键字的情况下进行同步内联?
答案 0 :(得分:9)
是的,它涉及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);
答案 1 :(得分:5)
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)...
);
注意:
cellfun
,evalin
和feval
。 'UniformOutput'
参数,以便cellfun
的输出是一个单元格(可以“解压缩”到comma-separated list;我们可以将其包装在{{} 1}}代替)。num2cell
诀窍是必需的,因为在evalin
范围内,我们不知道myFun
请求了多少输出。unpacker
(此处:eval
),但在这种情况下,我们确切地知道调用者是谁以及这是安全的操作。