Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid copying an array when using mexCallMATLAB

I have written a mex file for MATLAB. It calls MATLAB pinv function to calculate the Moore Penrose pseudoinverse. I named this function my_pinv. my_pinv gets an array and returns its pseudoinverse, exactly similar to pinv:

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

In the mex file, however, I have to copy the values of the input array to be able to use mexCallMATLAB. Here is the content of 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 that I skip using memcpy and directly use the input array, prhs[0], in mexCallMATLAB? I actually don't like the fact that the values of input array needs to be copied especially when the input array is very large.

In fact, 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)

rather than

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

Could someone share his/her experiences in this regard?

like image 582
user578 Avatar asked Apr 29 '26 16:04

user578


1 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 marked with the const qualifier. I dont know why... This explains why you get a 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 cast away the constant-ness telling the compiler that we know what we're 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 proves problematic (I doubt it), the safer way is to just duplicate the array using:

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

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

like image 190
Amro Avatar answered May 01 '26 05:05

Amro



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!