Multiple Outputs37

Posted by Loren Shure,

I just had an interesting exchange with a customer. He was trying to have an anonymous function return multiple outputs.

Inherent Multiple Outputs

You can inherently get multiple outputs from an anonymous function if the function being called returns more than a single output. Here's an example.

fdoubleEig = @(x) eig(2*x)
fdoubleEig =
@(x) eig(2*x)


Let's ask for a single output first.

eOnly = fdoubleEig(magic(3))
eOnly =
30.0000
9.7980
-9.7980


and now let's get 2 outputs, the eigenvalues and the eigenvectors.

[e,v] = fdoubleEig(magic(3))
e =
-0.5774   -0.8131   -0.3416
-0.5774    0.4714   -0.4714
-0.5774    0.3416    0.8131
v =
30.0000         0         0
0    9.7980         0
0         0   -9.7980


Assembling Multiple Outputs

If you want to return multiple outputs and there isn't an existing function to do so, you can assemble the outputs using the function deal.

fmeanVar = @(x) deal(mean(x), var(x))
fmeanVar =
@(x) deal(mean(x), var(x))


Let's try to get a single output.

try
mOnly = fmeanVar(magic(3));
catch
disp('deal requires the exact number of outputs.')
lerr = lasterror;
disp(lerr.message)
end
deal requires the exact number of outputs.
Error using ==> deal
The number of outputs should match the number of inputs.


This doesn't work because deal is picky about the number of outputs it expects to see.

Now let's try with 2 outputs.

[m,v] = fmeanVar(magic(3))
m =
5     5     5
v =
7    16     7


The deal function now sees two left-hand sides and works.

Thoughts?

I suspect you now understand this (for those who didn't already), but I suspect I can hear protests about how MATLAB should be smarter about this. If you have some concrete thoughts, I'd love to hear them here.

Get the MATLAB code

Published with MATLAB® 7.3

Ben replied on : 1 of 37

The last try…catch block runs without error for me, despite the extra parentheses in the anonymous function. I don’t quite understand the point, because the extra () seems to change nothing.

Loren replied on : 2 of 37

Ben-

You are right! I don’t know what I was seeing when I wrote the blog and got to that part (because it was giving me an error earlier). I updated the blog appropriately.

–Loren

Urs (us) Schwarz replied on : 3 of 37

rather than multiple outputs, a user may want to collect various results into one container, which he/she can peruse/split later – this approach saves him/her the trouble of knowing the nargout parameter

% all output vals numeric -and- of the same size
fnum=@(x) [
numel(x)
mean(x)
std(x)
];
% eg,
r=fnum(1:10)

% output vals of different classes/sizes
fcel=@(x) {
sprintf(‘class: %s’,class(x));
sprintf(‘number of elements: %-1d’,numel(x))
mean(x)
};
% eg,
r=fcel(uint16(magic(4)))
r{end}

just a thought
us

Urs (us) Schwarz replied on : 4 of 37

this got chopped, sorry

% output val is a structure
fstr=@(x) [
struct(‘class’,class(x),…
‘n’,numel(x),…
‘mean’,mean(x))
];
r=fstr(int8(magic(4)))
r=fstr(rand(3))

us

Dan K replied on : 5 of 37

Loren,
Thank you for this discussion, and also thank you to us, since being able to return a variable number of arguments is particularly important to me.

Loren, as a side request, would you mind doing a blog on the subject of why we MatLab is OK with expressions like [1xN].*[1×1] but not with [1xN].*[Nx1]. Or even better, why I can’t use an expression like:
CenteredData=Data-mean(Data,1); where Data is an [MxN] matrix. I don’t think there is any way to misinterpret this command. I guess what I am trying to deal with is why MatLab can handle mismatched matrices when all dimensions of one of them are singleton, but not when only some of them are singleton. Thanks,
Dan

Wolfgang Stamm replied on : 6 of 37

Hi Loren,

thank you for your last post. Incidentally I’m working on a problem which seems related to this topic. Although I don’t want to abuse you as my debugger I’m going to describe the problem here, ’cause anybody reading the topic of this blog entry might know my current problem already.

In short terms, the problem is:
When using

odeset(‘Events’,@(t,y)myEventFun(t,y,var1,var2))

with a workspace generated from scratch during program execution, everything works fine. Note that var1 and var2 are structures containing other anonymous function handles.

When attempting the odeset call with the same workspace loaded from a .mat-file, I get the error

??? Insufficient number of outputs from right hand side of equal sign to satisfy assignment.

in the line where odeset is called. I removed any assignment in this line, therefore I suspect the error to occur during execution of odeset (no error hierarchy is reported).

More surprisingly, I inserted a ‘pause’ command just one line above the ‘odeset’, then hit Ctrl-C to abort program execution at this point, and pasted the odeset manually to the command line. This time, the code executes without error. Because MATLAB comes with a nice debugging tool, I tried the same setting breakpoints: And yes, still the odeset worked fine from the keyboard prompt (K>>) and causes an error when I return to m-file execution.

So, I’m dealing with an error related to multiple outputs of anonymous functions, but I don’t understand it quite much at the moment. Which particularly puzzles me is the fact that the same line of code executed in an m-file and in the command window causes an error in the first case and doesn’t cause an error in the second case.

Well, when I got this tracked down, I’ll post another comment to tell you what the solution was. I’ll go on searching. And maybe this problem sounds familiar to anyone reading this.

Loren replied on : 7 of 37

Dan-

I will consider writing that blog post. You may also want to look at this prior one where I wrote about such expansion ideas. Finally, if you are using the MATLAB 2007a Prerelease, you can use the function bsxfun.

–Loren

lehalle replied on : 8 of 37

thanks for this post Loren,

I usually use cellarrays to perform multiple operations in anonymous function.

It is too bad that every matlab function does not return a value. the set function for graphical objects does not return anything o I cannot write:

no_ticks=@()({set(gca,’xtick’, []), set(gca,’ytick’, [])})

Ben replied on : 9 of 37

Is there a way to explicitly “request” a certain number of output arguments? I can build an arbitrary number of inputs to a function in a cell array, and call the function as func(arg_list{:}), but I can’t build an automatic number of outputs, for instance saying cell(1,nargs_out) = func(args_list).

To Dan K:
I think why [1xN].*[Nx1] doesn’t work is that the size of the output is ambiguous to MATLAB. It could be defined that the output takes the shape of the first argument. But if you knew what size output you wanted you could code it fine with
A.*B(:).’.

The tradeoff is that automagic things would seem nice for your case, but in other cases, subtracting a vector from a matrix and showing the behavior you suggest would be masking a actual error.

Wolfgang Stamm replied on : 10 of 37

OK, I promised to write again when I resolved my problem. Actually, I didn’t resolve it, instead I have to live with a workaround. I wasn’t able to find a confirmed reason why the line

odeset(’Events’,@(t,y)myEventFun(t,y,var1,var2))

causes an error when the structures var1 and var2 are read from .mat-file whereas there’s no error when *the same* (yes, I checked that) structures are created during run-time. Especially I didn’t find a reason for the error to appear during run-time but not to appear in debug mode. The workaround I found out to work for me reads as follows: When interrupting the ODE solver during integration, I copy the data from structures var1 and var1 to single variables (no function handles, just plain data), and save those variables to a .mat-file. When resuming integration, I construct var1 and var2 from an empty workspace (containing anonymous function handles), load the collection of unstructured data from my .mat-file to workspace and replace some entries in the newly constructed var1 and var2 with the saved data. When executing the odeset, no error is reported.

This workaround is ugly, but accebtable. I can only suspect what really happened with the original error. I guess it has to do with shadowing on the MATLAB path. The anonymous function handles were pointing at functions on the path. This path gets modified between single sessions of the main program, and maybe the anonymous function handles saved in the .mat-file were corrupt, because the shadowed functions on the path have been reloaded in between.

Thanks,
Wolfgang

Loren replied on : 11 of 37

Ben-

If you know you want a certain number of outputs, you can ask for them in a cell array and use a comma-separated list:

[out{1:3}] = deal(1,2,3)


–Loren

Loren replied on : 12 of 37

Charles-

Have you tried this – combining the set commands and calling with no inputs?

no_ticks=@() set(gca,{'xtick' 'ytick'}, {[],[]});
no_ticks()


–Loren

Patrik replied on : 13 of 37

To define anonymous functions that behave like ordinary functions with respect to multiple output arguments, you could just define a utility function

function varargout = flexOutput(varargin)
varargout = varargin;

once and for all. Then you can write

fmeanVar = @(x) flexOutput(mean(x), var(x))

and the following all work:

[m,v] = fmeanVar(magic(3))
m = fmeanVar(magic(3))
fmeanVar(magic(3))

Jon replied on : 14 of 37

Is it possible to somehow implement some ‘if’ logic or essentially use anonymous functions in a way similar to lambda functions? I would like to be able to use multiple lines in an anonymous function.

Loren replied on : 15 of 37

Jon-

You could use logical operators to help out. E.g.,

f = @(x) (x>0).*(x+1) + (x< =0)*0
f([-1 0 2 4])
ans =
0     0     3     5


--Loren

C Rose replied on : 16 of 37

Contrary to many commenters, I think that multiple return values are one of Matlab’s (few) weaknesses.

I can see the desire to obtain multiple return values, but the vector-like syntax relies on developers maintaining the ordering of return values; a change in return value order results in a bug. This makes code maintenance harder.

The same criticism can be levelled at Matlab (and other languages’) use of argument lists (where argument position carries meaning). This problem can be solved using keyword arguments; indeed, many Matlab functions use name-value pairs which can appear in any order, but Matlab seems to lack a standard way of constructing functions to use this feature (am I correct?).

The following example shows why named arguments can be less error-prone than ordered arguments. Which of the following function calls might be incorrect?

a = f(n, a)
a = f(a, n)
a = f(‘Age’, a, ‘Height’, h)
a = f(‘Height’, a, ‘Age’, h)
a = f(‘Height’, h, ‘Age’, a)

The problem of multiple return values can be solved simply be returning a structure, which is again essentially a list of name-value pairs. The advantage is that each value has a unique name associated with it, and this is much less error prone that relying on a particular value appearing at a particular place in a list.

Another problem with multiple return values is that often one only wants the n-th value, and it can be clumsy to achieve this. It would be nice if there was a way to specify the particular return values one is interested in It might be possible for the JIT compiler to be extended to be able to work out how to compute only those values. In some cases this could dramatically improve program run time.

When teaching Matlab, I advise people to write all of their functions to take arguments as either name-value pairs or structs, and to only return a single value (but to return a struct if multiple values must be returned); a returned struct can then be fed straight into a function that accepts a struct with compatible argument names.

Wes Campaigne replied on : 17 of 37

What could be useful in some situations is a sloppy version of deal, that drops excess inputs rather than complaining. Essentially, it would be:

varargout = varargin{1:nargout};

I’m also interested in ways of forcing a certain value of nargout on a function without having to list a set of parameters — and, ideally, a way of assigning only certain output variables and dropping the rest from memory. I can’t count the number of times I’ve done things like:

[junk, ind] = max( A );

and was left with junk variables to clear or just ignore. One possible form of bracketing is ”; lt and gt aren’t defined for cell arrays so I don’t think parsing this new operator would break backwards compatibility.

Oh, by the way: C Rose: R2007a adds nearly the exact feature you’re looking with the “inputParser” class. It parses and validates (among other things) lists of name-value pairs, and returns it the results appropriately as a struct. It even supports automatically parsing a passed struct parameter in place of the name-value pairs — just as you advise.

Wes Campaigne replied on : 18 of 37

Ahh, part of my post got eaten because I didn’t escape >. Oh well, doesn’t matter, since now that I think about it, it’s actually quite simple to half-implement what I was asking in a function:

function varargout = dealfun( f, N, v )

[results{1:N}] = f();

if nargin == 3,
results = results( v );
end;

if nargout == length(results) || (nargout==0 && length(results)==1)
varargout = results;
else
varargout{1} = results;
end;

with f as a parameterless function handle, so it’s used as
[s,v] = dealfun( @()svd(x), 3, 2:3 );

(Incidentally, the same trick can be used to create a 3-line wrapper function that lets you index directly into the matrix output by a function.)

I can’t quite make it do everything I want, since Matlab functions can’t actually return comma-separated lists — they can only assign to them. In other words, there’s no nice way of doing something like

[C{1:3}] = svd(x);
z = myfunc( C{:} );

in one line — you MUST explicitly store the values of C in variables, to be able to pass them on as a comma-separated list.

Timothee replied on : 19 of 37

Is there a way to combine multiple commands in anonymous functions?
ex1:
fun=@(A)([V,D]=eig(A); A*V-V*D)
ex2: more generally:
fun=@(A)([a,b]=my_fun1(A);[c,d]=my_fun2(a,b); my_fun3(a,b,c,d))
this doesn’t work, although I don’t see why it is not supported.
if there is no GENERAL workaround (cf post 15 is not very general), this would be one of the most useful features to include in matlab. This would avoid having to write lots of small functions, especially for development phase

Loren replied on : 20 of 37

Timothee-

Anonymous functions can only be a single (complicated) expression. You might be able to do what you want using deal with anonymous functions:

f = @(x,y,z) deal(fun(x,y),fun2(x,z), fun3(x,y,z));


That assumes that none of the calculations depends on the others in the expressions you provide. Another similar idea is to concatenate results:

f = @(x,y,z) [fun(x,y), fun2(x,z), fun3(x,y,z)];


The first version produces multiple outputs, the second a single vector output.

–Loren

Brad Phelan replied on : 21 of 37

Hi Tim,

I understand where you are coming from. It is my one pet annoyance with Matlab, the lack of multi line anonymous functions. Practically every one of Loren’s blog posts covers a topic that could be more elegantly solved with such a capability. However I don’t think you are going to see the capability in the language anytime soon.

You may be interested in this however. In 2005 I wrote a text generator for Matlab. It is a tool that falls into the same category of text templating tools such as PHP(php), JSP(java), ERUBY(ruby), CHEETAH(python) etc. Essentially you embed bits of Matlab code into a text file to generate more complicated text. Generally that is all irrelevant to this thread but to make the text generation more powerful I implemented multi line anonymous functions by transparently translating every multi line anonymous function into a named nested function.

http://xtargets.com/cms/Tutorials/Matlab-Programming/MTemplate-Matlab-Code-Generation-and-Text-Templating.html

The section “ADVANCED TEMPLATE PROGRAMMING” gives details on this feature.

The point being is that this feature is simple to add to Matlab as it is just a trivial translation into language features that already exist.

An example input file
http://pastie.caboo.se/pastes/195636

and an example output file
http://pastie.caboo.se/pastes/195637

Note that BLOCK_FUN_1 and BLOCK_FUN_2 are automatically generated nested functions arising from the anonymous functions at line 17 and 21 in the input file [http://pastie.caboo.se/195636 ]

It was quite a lot of fun writing this tool. Essentially a small compiler project. The compiler could be modified to translate normal matlab code ( instead of text template code ) with multi line anonymous functions into standard Matlab. Feel free to give it a go.

Cheers

B

Alan Jennings replied on : 22 of 37

A Guide to MATLAB By Brian R. Hunt, Ronald L. Lipsman, Jonathan Rosenberg, Kevin R. Coombes, John E. Osborn, Garrett J. Stuck on page 97

on how to accomplish different number of outputs. The eval(str) command evaluate the string str. With multiple inputs, eval(str1, str2, …, strN) tries str1 and if fails trys str2, and so on until a string doesn’t fail. So

FunctionX= @(x) eval(‘deal(funt1(x), …, funtN(x))’, ‘deal(funt1, …, funt(N-1)(x))’, …, ‘deal(funt1(x), funt2(x))’, ‘funt1(x)’);

will try for the most outputs, then one less (sorry for bad notation), and so on until it finds the proper deal.

I see this getting messy very fast and agree with Jon reply 14 that it would be nice to put for and if loops in an inline or anonymous function. What I plan to do with this is make a handle that can return the nonlinear constraints for fmincon with out needing an external file.

sumit replied on : 23 of 37

would it be possible to get such multiple outputs if blockproc were used together with the above function (top process the image blockwise)

Steve Eddins replied on : 24 of 37

Sumit—No, I don’t think so.

Artur Palha replied on : 25 of 37

Patrik:

Nice trick that one of the flexOuput, thanks!

Joan replied on : 26 of 37

Hi Loren, thanks for having this blog!

I have a collection of functions having similar but not coincident APIs, with different number of inputs and outputs, and I want to wrapp them in a new function that accepts a handle to those former ones. My wrapped function is intended to give me one particular output of the formers, and I want to specify which output I want:

For instance, if I want output C in [A,B,C] = f(x, y, z) I want to write:

C = getNthOut(@f, 3, x, y, z)


that is, give me the third output of function f(x, y, z). I haven’t been able to do it with cell arrays because the number of outputs of f() is not known a priori. Therefore I cannot use the solution you give to Ben above (your reply #11). Post 16 also rises this problem, with no answer.

I would like an implementation of getNthOut which looks smarter than the one I wrote:

function out = getNthOut(f, n, varargin)
switch (n)
case 1
out = f(varargin{:});
case 2
[a,out] = f(varargin{:});
case 3
[a,b,out] = f(varargin{:});
case 4
[a,b,c,out] = f(varargin{:});
% ... and so on ...
end


For instance, I could not make this code work:

function out = getNthOut(f, n, varargin)[mout{0:n}]=f(varargin{:});
out = mout{n};

Loren replied on : 27 of 37

Joan-

Look into the function varargout, the kin to varargin. You can rewrite your code without a switch with something like this.

[varargout{1:n}] = f(varargin{:}];


–Loren

Joan replied on : 28 of 37

Hi Loren, thanks for this. It looks really neat — and it looks just standard plain Matlab… maybe next time I can come with a cleverer question!
Joan

Tristan replied on : 29 of 37

deal

function!

Doug Weathers replied on : 30 of 37

Hi Loren,

Thanks for the tip on using DEAL to produce inline anonymous functions that produce multiple outputs.

However, it doesn’t work in the case of an event function passed to an ODE solver:

tilde = @(q) [   0  -q(3)  q(2)
q(3)    0  -q(1)
-q(2)  q(1)    0  ];
sigma0 = [0 0 0];
omega = [1, 0.5, -0.7]';
I = eye(3);
sdot = @(t, s) 1/4 * ((1-dot(s,s))*I + 2*tilde(s) + 2*s*s') * omega;
t = [0 5];
events = @(t,y) deal(norm(y)-1, 1, 1);
options = odeset('Events', events);
[tevent, sevent] = ode45(sdot, t, sigma0, options);

??? Error using ==> deal at 38
The number of outputs should match the number of inputs.

Error in ==> @(t,y)deal(norm(y)-1,1,1)

Error in ==> odeevents at 29
eventValue = feval(eventFcn,t0,y0,eventArgs{:});

Error in ==> ode45 at 207
[haveEventFcn,eventFcn,eventArgs,valt,teout,yeout,ieout] = ...

Error in ==> example at 11
[tevent, sevent] = ode45(sdot, t, sigma0, options);


It looks like somewhere along the line, ODE45 is trying to get something other than three outputs from my event function, and DEAL complains.

Some desultory debugging seems to indicate that my anonymous events function is advertising that its nargout is only 1, which is a DEAL-breaker.

It works fine if I use an external function file (as is usually done) as my events function.

Any thoughts?

Thanks,

Doug

Loren replied on : 31 of 37

Doug-

I don’t know for sure and don’t have access to MATLAB right now. I think you should contact support to identify where the problem lies.

–Loren

jiro replied on : 32 of 37

@Doug,
It seems like you’re looking at the issue itself in one of the error messages:

Error in ==> odeevents at 29
eventValue = feval(eventFcn,t0,y0,eventArgs{:});


That command is only requesting one output, as you suspect. In another place in the code, it is requesting all 3.

Doug Weathers replied on : 33 of 37

@Loren,

I posted a bug report. Thanks!

@jiro,

I did some debugging with “step in” and saw the anonymous event function fail a test to see if nargin == nargout. I think. I’ve slept since then.

Doug Weathers replied on : 34 of 37

I got a reply from Support, explaining why it doesn’t work. However, the tech included a piece of code that contained the seed of a workaround.

events = @(t,y) deal(norm(y)-1, 1, 1);



use

mydeal = @(x) x{:};
evt = @(t,y) mydeal({norm(y)-1, 1, 1});



and all is well.

I still think that DEAL is broken, though. Lots of other people complain about this inflexibility of DEAL, as I discovered while researching this issue. Loren seemed to think so in 2007, when she wrote the original post!

Thanks everyone!

– Doug

Keith replied on : 35 of 37

Hi.

I am trying to make some dumb function anonymous. The following is easily put in an m-file and does what I want:

function varargout = enumerate()
varargout = num2cell(1:nargout);


Since it’s just a single line, I figure it would work, but it generates the error:

>> enum = @() varargout = num2cell(1:nargout);
??? enum = @() varargout = num2cell(1:nargout);
|
Error: The expression to the left of the equals sign is not a valid target for
an assignment.


I guess it doesn’t work because anonymous functions can’t have variable numbers of outputs, but is there some trick I haven’t thought of to accomplishing the same task anonymously?

Loren replied on : 36 of 37

Keith-

You can’t have an assignment inside anonymous function definition.

Try something like:

enum = @(x)num2cell(x);


Then call it like this:

c = enum([1 2 3])


Not sure what you are doing with nargout, but you need it to used with a function that has more than one output.

Anonymous functions CAN have multiple outputs. Try using deal in one, for example.

enum = @(x)deal(x{:});
x = { 1 2 3};
[a,b,c] = enum(x)


–Loren

Brad Stiritz replied on : 37 of 37

@C Rose : thanks for your clear argument in favor of returning a single struct with multiple fields, rather than returning a vector of multiple return values.

I’m working on a complex “function stack” at the moment, of several very similar, complex function signatures. I reached a sort-of emotional tipping point, where the cognitive cost of keeping track of slightly different multiple-return-value vectors as I read & step through & maintain this code just isn’t worth the effort anymore. It’s so much more readable to have a canonical form:

stOutput = function_xxx(…)

That said, there’s no question that in many simpler contexts, such as utility functions, it’s highly convenient & value-added to return a single, principal output value & one or more “trailing, optional values”.

So I don’t think this choice is cut-and-dried, but I do agree that students should be taught to keep the trade-off in mind & to go with struct output when they feel things are getting “too complex”.