Loren on the Art of MATLAB

January 31st, 2007

Multiple Outputs

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

Contents

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

24 Responses to “Multiple Outputs”

  1. Ben replied on :

    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.

  2. Loren replied on :

    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

  3. Urs (us) Schwarz replied on :

    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

  4. Urs (us) Schwarz replied on :

    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

  5. Dan K replied on :

    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

  6. Wolfgang Stamm replied on :

    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.

  7. Loren replied on :

    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

  8. lehalle replied on :

    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’, [])})

  9. Ben replied on :

    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.

  10. Wolfgang Stamm replied on :

    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

  11. Loren replied on :

    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

  12. Loren replied on :

    Charles-

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

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

    –Loren

  13. Patrik replied on :

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

  14. Jon replied on :

    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.

  15. Loren replied on :

    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

  16. C Rose replied on :

    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.

  17. Wes Campaigne replied on :

    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.

  18. Wes Campaigne replied on :

    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.

  19. Timothee replied on :

    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

  20. Loren replied on :

    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

  21. Brad Phelan replied on :

    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.

    A quick example from the download package

    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

  22. Alan Jennings replied on :

    There’s advise in

    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

    http://books.google.com/books?id=NekrOjT8oSIC&pg=PA97&lpg=PA97&dq=matlab+anonymous-function+multiple+outputs&source=bl&ots=kc7oseDDOX&sig=LSEKpU0tOO8hL0zs2rdNb_Es-jw&hl=en&ei=My-kSaGqBKKBtwfLwOTTBA&sa=X&oi=book_result&resnum=4&ct=result#PPA97,M1

    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.

  23. sumit replied on :

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

  24. Steve Eddins replied on :

    Sumit—No, I don’t think so.

Leave a Reply

Wrap code fragments inside <pre> tags, like this:

<pre class="code">
a = magic(3);
sum(a)
</pre>

If you have a "<" character in your code, either follow it with a space or replace it with "&lt;" (including the semicolon).


Loren Shure works on design of the MATLAB language at The MathWorks. She writes here about once a week on MATLAB programming and related topics.

  • Jun: I totally can not believe it, Loren. You are really helpful. Thank you so much, MATLAB master!
  • Loren: Wow folks- Always lots of interest when there’s a quickie to try out! I will only make 2 general...
  • Loren: Jun- ismember is your friend here: >> [aa,ind] = ismember(Array2,Arra y1) aa = 1 1 1 1 1 1 1 ind = 1 2 1 4 4 3...
  • Dan: I like the first way better than the second way. Combining the arrays into one and running any is nice, although...
  • James Myatt: How about I = (a == 0 | b == 0); a(I) = []; b(I) = [];
  • Tunc: Hello Loren, love your blog because of such inspiring and challenging comments to such ’small’...
  • Pekka Kumpulainen: Here is my tradeoff. I usually want to keep the original variables as they are most probably...
  • Iain: Followup: Of course, to allow NaNs (counting them as non-zero): mask = (a~=0) & (b~=0); The mask says “a...
  • Matt Fig: I would usually go with something like this: y = a&b; x = a(y); y = b(y); But I was surprised to find...
  • kk: c=all([a;b]) a(c) a(b)

These postings are the author's and don't necessarily represent the opinions of The MathWorks.