避免使用mexCallMATLAB时复制数组

问题描述:

我已经写了一个MATLAB MEX文件。它调用MATLAB PINV 函数来计算摩尔彭罗斯伪逆。我命名这个功能 my_pinv my_pinv 得到一个数组,并返回其伪逆,正是类似 PINV

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

在MEX文件,但是,我必须复制输入数组的值可以使用 mexCallMATLAB 。这里的内容 my_pinv.cpp

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");

}

反正是有,我跳过使用的memcpy 并直接使用输入数组, prhs [0] ,在 mexCallMATLAB ?我其实不喜欢需要,特别是当输入数组是非常大的要复制输入数组的值的事实。

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.

其实,我想能够使用像

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)

而不是

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

有人能分享在这方面他/她的经历?

Could someone share his/her experiences in this regard?

mexCallMATLAB 具有以下签名:

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

有关某种原因,RHS数组没有标记常量预选赛。我不知道为什么......这解释了为什么你会得到一个编译错误:

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:

#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");
}

在MATLAB

现在

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).