我已经为MATLAB编写了一个mex文件。它调用MATLAB pinv
函数计算穆尔彭罗斯伪逆。我把这个函数命名为my_pinv
。my_pinv
获取数组并返回其伪逆,与pinv
完全类似。
A = magic(8); A = A(:,1:6)
b = 260*ones(8,1)
x = my_pinv(A)*b
但是,在mex文件中,我必须复制输入数组的值才能使用mexCallMATLAB
。以下是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
并直接使用mexCallMATLAB
中的输入数组prhs[0]
?实际上,我不喜欢输入数组的值需要复制的事实,特别是当输入数组非常大的时候。
事实上,我希望能用
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");
有人能分享他/她在这方面的经验吗?
发布于 2014-10-28 15:41:42
mexCallMATLAB
具有以下签名:
int mexCallMATLAB(int nlhs, mxArray *plhs[], int nrhs,
mxArray *prhs[], const char *functionName);
由于某些原因,RHS数组没有使用const
限定符进行标记。我不知道为什么。这解释了为什么您会得到一个编译错误:
// 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
解决方案是显式地抛弃常量,告诉编译器我们知道我们在做什么:
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");
}
现在在MATLAB中:
>> x = rand(4,3);
>> my_pinv(x) - pinv(x)
ans =
0 0 0 0
0 0 0 0
0 0 0 0
如果由于某种原因,而且在某些角落的情况下,这是有问题的(我对此表示怀疑),则更安全的方法是使用以下方法复制数组:
mxArray *in = mxDuplicateArray(prhs[0]);
mexCallMATLAB(1, plhs, 1, &in, "pinv");
mxDestroyArray(in);
如果您绝对希望避免创建深拷贝,则有无证函数创建共享数据副本(其中只创建了一个新的数组头,但数据是共享的)。
发布于 2014-10-28 16:04:50
像Amro已经说过的那样,抛开const直接将prhs
输入到mexCallMATLAB
是如何最有效地处理这个问题的。虽然mexCallMATLAB
的声明肯定不能保证输入数组不会被修改(声明为mxArray *prhs[]
),但是如果您调用的函数行为良好,并且遵循MathWorks关于永远不要修改右侧参数的严厉建议,这不是一个问题。
关于plhs
的mexCallMATLAB
分配,这就像任何其他的mexCallMATLAB
函数一样。如果你这样做,就没有什么区别了:
% in MATLAB
x = pinv(A);
或
% in MEX
mxArray *x; % no mxArray allocated, just a pointer
mexCallMATLAB(1, &x, 1, const_cast<mxArray**>(prhs), "pinv"); % pinv creates *x
mexCallMATLAB
(或者更确切地说是pinv
)创建输出数组。不要浪费时间来创建左手边。如果这让您感到困扰,请创建一个空的mxArrary
。
mxArray *x = mxCreateDoubleMatrix(0, 0, mxREAL); % but not necessary
pinv
会把它清除掉,做一个新的,就像你在MATLAB中做的那样:
x = [];
x = pinv(A);
无论哪种方式,MATLAB内存管理器都拥有数组。当MEX函数返回或从内存中清除时,不会蒸发。
来自内存管理问题 at MathWorks:
当MEX文件将控制返回给MATLAB时,它会在输出参数中返回其计算结果--包含在左侧参数plhs[]中的plhs[]。MATLAB破坏由MEX文件创建的任何不在此参数列表中的mxArray . 但是,当源MEX-文件中的mxArray是: *传递给右侧列表prhs[]中的MEX-文件 *返回左侧列表plhs[] *由mexGetVariablePtr归还 *用于创建结构
https://stackoverflow.com/questions/26619947
复制相似问题