Using deal
we can write anonymous functions that have multiple output arguments, like for example
minmax = @(x)deal(min(x),max(x));
[u,v] = minmax([1,2,3,4]); % outputs u = 1, v = 4
But if you want to provide a function with its gradient to the optimization function fminunc
this does not work. The function (EDIT: This is not true, you just have to specify whether you actually want to use the gradient or not, using e.g. fminunc
calls the input function sometimes with one and sometimes with two output arguments.optimset('SpecifyObjectiveGradient',true)
. Then within one call it always asks for the same number of arguments.)
We have to provide something like
function [f,g] = myFun(x)
f = x^2; % function
g = 2*x; % gradient
which can be called with one or two output arguments.
So is there a way to do the same inline without using the function
keyword?
The OP's solution is good in that it's concise and useful in many cases.
However, it has one main shortcoming, in that it's less scalable than otherwise possible. This claim is made because all functions ({x^2,2*x,2}
) are evaluated, regardless of whether they're needed as outputs or not - which results in "wasted" computation time and memory consumption when less than 3 outputs are requested.
In the example of this question this is not an issue because the function and its derivatives are very easy to compute and the input x
is a scalar, but under different circumstances, this can be a very real issue.
I'm providing a modified version, which although uglier, avoids the aforementioned problem and is somewhat more general:
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)...
);
Notes:
cellfun
, evalin
and feval
. 'UniformOutput'
argument was only added so that the output of cellfun
is a cell (and can be "unpacked" to a comma-separated list; we could've wrapped it in num2cell
instead).evalin
trick is required since in the myFun
scope we don't know how many outputs were requested from unpacker
.eval
in its various forms (here: evalin
) is usually discouraged, in this case we know exactly who the caller is and that this is a safe operation.