最有效的方法使用mexCallMATLAB在转换Double*到mxArray*

2次浏览(过去30天)
我正在写一篇 墨西哥人 我需要使用的代码 pinv 函数。我试图找到一种方法来传递类型数组 pinv 使用 mexCallMATLAB 以最有效的方式。为了举例,我们假设数组被命名 G 它的大小是100。
*G = (double*) mxMalloc(100 * sizeof(double))
在哪里
G[0] = g11;G[1] = g12;
G[2] = g21;G[3] = g22;
也就是说G中每四个连续的元素都是a 2×2 矩阵。 G 商店 25 不同的值 2×2 矩阵。
我应该注意这些 2×2 矩阵不是条件良好的,它们的元素中可能全是零。我如何使用 pinv 函数来计算元素中的伪逆 G ?例如,如何将数组传递给 mexCallMATLAB 为了计算第一个的伪逆 2×2 矩阵 G
我想到了以下方法:
mxArray* G_PINV_input= mxCreateDoubleMatrix(2,2, mxREAL)
mxArray* G_PINV_output= mxCreateDoubleMatrix(2,2, mxREAL)
*G_PINV_input_ptr = mxGetPr(G_PINV_input)
memcpy(G_PINV_input_ptr, &G[0], 4 * sizeof(double));
mexCallMATLAB(1, G_PINV_output, 1, G_PINV_input,“pinv”);
我不确定这种方法有多好。复制值一点也不经济,因为其中的元素总数 G 在我的实际应用中是很大的。有办法跳过这个拷贝吗?

答案(1)

詹姆斯Tursa
詹姆斯Tursa 2014年11月6日
编辑:詹姆斯Tursa 2014年11月6日
初步评论:你不应该预先分配G_PINV_output,因为它将由mexCallMATLAB调用本身自动创建。只需要传入未初始化的指针。你用这种方式编码,你实际上有一个内存泄漏,因为你的mxCreateDoubleMatrix调用的结果会被mexCallMATLAB调用清除。
现在来看看真正的问题……
从官方API函数的角度来看,答案是否定的,如果不复制数据,您就无法完成您正在尝试做的事情。唯一可以正式附加到mxArray数据区域的内存地址(例如pr或pi)是来自API分配例程的内存地址。例如,你可以直接将G附加到mxArray数据区(例如使用mxSetPr),因为G直接来自API例程mxMalloc。这样就可以把第一个2x2矩阵传递给pinv。一切都很好。G实际上指向一个更大的数据集并不重要……简单地使用mxSetM和mxSetN来设置2x2的大小就可以了。
当你试图为下一个2x2块做同样的事情时,问题就来了,即从G+4开始。如果您将此地址传递给mxSetPr, MATLAB将以断言错误轰炸。API例程检查传入地址,以确保它们位于已分配内存块的内部列表中。由于G+4不在列表中(它位于已分配块的中间,但G+4地址本身不在列表中),将生成实时故障,MATLAB将爆炸。所以你不能在循环中使用简单的指针算术和mxSetPr来完成这个。你需要复制数据。在那里 一种绕过这个问题的方法是侵入mxArray结构本身,直接设置pr字段,完全绕过mxSetPr调用(并绕过断言检查)。然而,这些细节超出了本文的讨论范围,为了避免MATLAB崩溃,它们会有自己的一组问题,所以我不会在这里发布它们。
我的建议是接受抄袭。这并不是瓶颈。mexCallMATLAB调用开销,加上输出mxArray变量的创建,再加上pinv函数,所有这些都将占用复制4个双精度复制所需的相对少量的时间。如果你真的想加快速度,这对你来说足够重要,那么在你的mex函数中自己手工编写2x2的pinv算法,并完全避免调用mexCallMATLAB。
我还应该指出这个调用有错误:
mexCallMATLAB(1, G_PINV_output, 1, G_PINV_input,“pinv”);
应该是这样的:
mexCallMATLAB(1, &G_PINV_output, 1, &G_PINV_input,“pinv”);
因为你声明了第二个和第四个参数变量为mxArray *而不是mxArray [],您将需要添加&操作符以获得正确的间接级别。

标签

社区寻宝

在MATLAB Central中找到宝藏,并发现社区如何帮助您!

开始狩猎!