Avoid copying an array when using mexCallMATLAB

I wrote a mex file for MATLAB. It calls a MATLAB function pinv

to compute the Moore Penrose pseudoinverse. I named this function my_pinv

. my_pinv

gets an array and returns it pseudo-inverse, exactly like pinv

:

A = magic(8); A = A(:,1:6)
b = 260*ones(8,1)
x = my_pinv(A)*b

      

In the mex file, however, I need to copy the values โ€‹โ€‹of the input array to be able to use mexCallMATLAB

. Here is the content my_pinv.cpp

:

#include <matrix.h>
#include <mex.h>
#include <string.h>

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    #define PRHS_A prhs[0]
    #define PLHS_X plhs[0] 

    int M = mxGetM( PRHS_A ); // Get the dimensions of  A.
    int N = mxGetN( PRHS_A );

    double *A_ptr = mxGetPr( PRHS_A );
    mxArray *PINV_A =  mxCreateDoubleMatrix(M, N,  mxREAL);  /* Put input in an mxArray */
    memcpy(mxGetPr(PINV_A), A_ptr,  sizeof(double)*M*N);

    PLHS_X = mxCreateDoubleMatrix(N, M, mxREAL);  // Create the output matrix.

    mexCallMATLAB(1, &PLHS_X, 1, &PINV_A, "pinv");

}

      

Is there anyway I am skipping with memcpy

and using the input array directly,, prhs[0]

in mexCallMATLAB

? I really don't like the fact that the values โ€‹โ€‹of the input array need to be copied, especially when the input array is very large.

Actually, I would like to be able to use something like

mexCallMATLAB(1, &PLHS_X, 1, &RHS_A, "pinv"); // (I know it is not right and the compiler would not like it but it is for the sake of example)

      

but not

mexCallMATLAB(1, &PLHS_X, 1, &PINV_A, "pinv");

      

Can anyone share their experience in this regard?

+3


source to share


2 answers


mexCallMATLAB

has the following signature:

int mexCallMATLAB(int nlhs, mxArray *plhs[], int nrhs,
    mxArray *prhs[], const char *functionName);

      

For some reason, the RHS array is not qualified const

. I don't know why ... This explains why you are getting compilation error:

// this is from Visual C++ 2013
error C2664: 'int mexCallMATLAB(int,mxArray*[],int,mxArray *[],const char *)' :
cannot convert argument 4 from 'const mxArray *[]' to 'mxArray *[]'
    Conversion loses qualifiers

      

The solution is to explicitly discard the constant telling the compiler that we know what we are doing:

my_pinv.cpp

#include "mex.h"

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    // validate arguments
    if(nrhs != 1 || nlhs > 1)
        mexErrMsgIdAndTxt("mex:error", "Wrong number of arguments.");
    //perhaps do more validations here..

    // out = pinv(in)
    mexCallMATLAB(1, plhs, 1, const_cast<mxArray**>(prhs), "pinv");
}

      



Now in MATLAB:

>> x = rand(4,3);
>> my_pinv(x) - pinv(x)
ans =
     0     0     0     0
     0     0     0     0
     0     0     0     0

      


If for some reason and in some corner case this turns out to be problematic (I doubt it), a safer way is to simply duplicate the array using:

mxArray *in = mxDuplicateArray(prhs[0]);
mexCallMATLAB(1, plhs, 1, &in, "pinv");
mxDestroyArray(in);

      

If you absolutely don't want to create a deep copy, there are undocumented functions that create a copy of the shared data (where only a new header array is created, but the data is shared).

+4


source


By dropping the constant on the input prhs

directly to mexCallMATLAB

, as Amro already said, how to handle this most efficiently. While declaring for mexCallMATLAB

certainly does not guarantee that the input array will not be changed (declared as mxArray *prhs[]

), if the function you are calling is behaving well and following MathWorks' strict advice to never change the right-hand side arguments, this is not a problem.

With regard to highlighting plhs

on mexCallMATLAB

, this is done just like any other MATLAB function. It makes no difference if you do this:

% in MATLAB
x = pinv(A);

      

or

% in MEX
mxArray *x;  % no mxArray allocated, just a pointer
mexCallMATLAB(1, &x, 1, const_cast<mxArray**>(prhs), "pinv");  % pinv creates *x

      

mexCallMATLAB

(or rather pinv

) creates an output array. Don't waste time creating the left side. If this bothers you, create an empty one mxArrary

:



mxArray *x = mxCreateDoubleMatrix(0, 0, mxREAL); % but not necessary

      

pinv

will destroy it and make a new one, as if you did it in MATLAB:

x = [];
x = pinv(A);

      

In any case, the MATLAB memory manager owns the array. It does not evaporate when the MEX function returns or is cleared from memory.

From Memory Management Issues in MathWorks:

When a MEX file returns control to MATLABยฎ, it returns the results of its calculations in the output arguments - mxArrays, contained in the left arguments of plhs []. MATLAB destroys any mxArray created by the MEX file that is not in this argument list.

However, do not destroy the mxArray in the original MEX file if it is: * passed to the MEX file in the right list prhs []
 * returned in the left list plhs []
 * returned by mexGetVariablePtr
 * used to create the structure

+2


source







All Articles