Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return variable number of outputs from mex function

Is there any way to return a variable number of outputs from a mex function?

One might pack them into a cell, but I wondered wether there is a way, so that they are expanded directly in the output list. Something like

a = mymex(arg1, arg2);

[a, b, c] = mymex(arg1, arg2, 'all');
like image 236
embert Avatar asked Mar 18 '23 03:03

embert


1 Answers

Of course you can, just like any other MATLAB function:

test_mex.cpp

#include "mex.h"

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    for (int i=0; i<nlhs; i++) {
        plhs[i] = mxCreateDoubleScalar(i);
    }
}

MATLAB

>> [a,b,c] = test_mex()
a =
     0
b =
     1
c =
     2

You will have to determine how many arguments to return depending on the inputs/outputs, or issue an error if the function is called incorrectly (not enough input, too many outputs, etc..). The example above just accepts any number of output arguments (including none or zero outputs)

Take comma separated lists, which allow use to call functions in interesting ways:

>> out = cell(1,20);
>> [out{:}] = test_mex()
out = 
  Columns 1 through 11
    [0]    [1]    [2]    [3]    [4]    [5]    [6]    [7]    [8]    [9]    [10]
  Columns 12 through 20
    [11]    [12]    [13]    [14]    [15]    [16]    [17]    [18]    [19]

This is like calling the function with 20 output variables:

>> [x1,x2,...,x20] = test_mex()

EDIT:

Just to clarify, MEX-functions act like regular M-functions defined with variable number of inputs and outputs (think function varargout = mymex(varargin)), and the same rules apply; it is up to you to manage access to inputs and create necessary outputs.

For example the previous code can be written as a regular M-function called the same way as before:

function varargout = test_fcn(varargin)
    for i=1:nargout
        varargout{i} = i-1;
    end
end

The difference is that in MEX-files you could crash MATLAB if you try to access something out-of-range, or try to write output beyond what is actually allocated.

Take this example:

#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    for (int i=0; i<30; i++) {    // <--- note 30 as value
        plhs[i] = mxCreateDoubleScalar(i);
    }
}

Calling the above as:

>> test_mex    % careful!

will most likely cause an immediate MATLAB crash. While the same thing done in M-code, will just create unnecessary extra output variables that are destroyed after the call.

As @chappjc explained in his answer, for MEX-files you are always guaranteed to have space for at least one output (plhs is an array of mxArray* of length 1 at a minimum, so it's safe to assign plhs[0] no matter what). If the caller specifies a LHS variable then the output goes into it, otherwise the output is assigned to the special ans variable (of course you can still assign nothing, in case of zero outputs).

The opposite case of not assigning enough output variables is fortunately caught by MATLAB, and throws a regular catch-able error with ID MATLAB:unassignedOutputs (in both MEX and M-functions).

Also, accessing out-of-range inputs will cause an access violation (MATLAB will inform you of that with a big scary dialog, and the prompt will turn to "please restart MATLAB" message). Doing the same in regular M-code, will just throw a regular error "Index exceeds matrix dimensions.", nothing serious!

As you can see, it is very easy for things to go wrong in MEX world (in an unrecoverable way), so you have to pay special attention to validating input/output arguments.

like image 127
Amro Avatar answered Apr 01 '23 06:04

Amro