Skip to Main Content Skip to Search
File Exchange
MATLAB Newsgroup
Link Exchange
  Blogs  
 Contest 
MathWorks.com

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

21 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

Leave a Reply


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.

  • Ulla Vainio: That error bar width adjustment was extremely useful and I would never have figured it out myself....
  • Peter Perkins: Jessee, there is a property that you can use to tag variables with units. For example, >> load...
  • Jessee: I could potentially see myself using dataset for casually looking at data, but from an application standpoint...
  • Loren: Oktay- It very much depends on the details of the calculations you are doing. Vectorization can sometimes...
  • Oktay: Hello, Is there any significant difference between using: - Vectorization inside a subfunction - Benefiting...
  • Loren: Clare- Yes, sum can sum a double vector: x = [.3 .4 pi/3] y = sum(x) x = 0.3 0.4 1.0472 y = 1.7472 You must...
  • Clare J: R2007a - Student Version When I use sum to sum a vector of type double I get this error message: ???...
  • Sarah Zaranek: Hi Jacob, Sorry about the slow response. You are correct that the code would be slower without the...
  • Navaneethan Santhanam: Thanks a lot, Loren! That worked perfectly.
  • Mike N: Should it be OK to use “persistent 221; variables in a deployed application? What if I have two...

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

Related Topics