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?
source to share
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).
source to share
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
source to share