【问题标题】:How to represent a 2D array of MATLAB in mex code如何在 mex 代码中表示 MATLAB 的二维数组
【发布时间】:2016-03-29 06:47:03
【问题描述】:

我有一个 MATLAB 代码

%% Inputs are theta and h (size NxM)
alpha=zeros(N,M);
h_tmp=zeros(N,M);
h_tmp(1:N-1,:)=h(2:N ,:);
for i=1:N
    alpha(i,:)=theta.*(h_tmp(i,:)+h(i,:));
end

通过使用向量化的方法,上面的代码可以

alpha = theta .* [h(1:N-1,:) + h(2:N,:); h(N,:)];

为了加快代码速度,我想用 C++ 在 MEX 文件中重写它。 MATLAB 和 C++ 在二维数组中的主要区别是行优先顺序 (MATLAB) 和列优先顺序 (C++)

double  *h, *alpha, *h_temp;
int N,M;
double theta;    
N      = (int) mxGetN(prhs[0]); //cols
M      = (int) mxGetM(prhs[0]); //rows
h      = (double *)mxGetData(prhs[0]);
theta  = (double)*mxGetPr(prhs[1]);
/* Initial zeros matrix*/
plhs[0]   = mxCreateDoubleMatrix(M, N, mxREAL);  alpha = mxGetPr(plhs[0]);
//////////////Compute alpha/////////    
for (int rows=0; rows < M; rows++) {
    //h[N*rows+cols] is h_tmp
    for (int cols=0; cols < N; cols++) {        
         alpha[N*rows+cols]=theta*(h[N*rows+cols+1]+h[N*rows+cols]);
    }
}

我的 Mex 代码和 MATLAB 代码是否等效?如果没有,你能帮我解决它吗?

【问题讨论】:

  • 不是rows+rows*N,是吗?如果我正确理解您的代码,您必须有一个列循环并将行数与列索引相乘。它应该类似于alpha[N*rows+col],其中col 是第二个内部循环的计数器...
  • 代表h和h_tmp怎么样?这是正确的吗。我现在会更正它并再次检查
  • 第二个for循环中的条件不能是rows &lt; N,否则你将无限循环(因为在执行过程中行和N都不会改变)。另外看看this link to the mathworks forums,我认为你在C++中尝试做的事情会更慢,因为Matlab可能已经对你的代码进行了多线程处理。
  • 请注意,MATLAB 向量化工具已经在 C 中。您很可能不会在 mex 文件中使用 3 个基本数学运算来加速 for 循环。最多是一样的速度
  • @FirefoxMetzger:这是错字。我纠正了它。 Ander Biguri:因为上述方法被多次调用(~6000 次)。因此,小幅提高速度会很有用

标签: c++ matlab mex


【解决方案1】:

除了 cmets 对您的问题的更正之外,还有一个细微差别。缺少的是您在 Matlab 代码中跳过 h(N,:),在 C 代码中迭代代码直到 cols &lt; N,这(由于 C 中的 0 索引)也将处理每列中的最后一个元素。

#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double  *h, *alpha, *h_temp;
    int num_columns, num_rows;
    double theta;    
    num_columns = (int) mxGetN(prhs[0]); //cols
    num_rows    = (int) mxGetM(prhs[0]); //rows
    h           = (double *)mxGetData(prhs[0]);
    theta       = (double)*mxGetPr(prhs[1]);
    /* Initial zeros matrix*/
    plhs[0]   = mxCreateDoubleMatrix(num_rows, num_columns, mxREAL);  alpha = mxGetPr(plhs[0]);
    //////////////Compute alpha/////////
    // there are num_rows many elements in each column
    // and num_columns many rows. Matlab stores column first.
    // h[0] ... h[num_rows-1] == h(:,1)
    int idx; // to help make code cleaner
    for (int column_idx=0; column_idx < num_columns; column_idx++) {
        //iterate over each column
        for (int row_idx=0; row_idx < num_rows-1; row_idx++) {// exclude h(end,row_idx)
            //for each row in a column do
            idx = num_columns * column_idx + row_idx;
            alpha[idx]= theta * (h[idx+1] + h[idx]);
        }
    }
    //the last column wasn't modified and set to 0 upon initialization.
    //set it now
    for(int rows = 0; rows < num_rows; rows++) {
        alpha[num_columns*rows+(num_rows-1)] = theta * h[num_columns*rows+(num_rows-1)];
    }
}

请注意,我决定重命名一些变量,以便我认为它更易于阅读。

编辑:删除了 prhs[0] = plhs[0] 的建议,如 cmets 对此答案的建议。在某些情况下可能会侥幸逃脱,但一般而言,在编写 matlab .mex 函数时这不是一个好习惯,它可能会使 Matlab 崩溃。

【讨论】:

  • @user8430 是有意的。我没有为plhs 分配任何空间,也没有创建一个名为alpha 的指针。我在迭代h 时覆盖了曾经存储在h 中的内容。这样,它节省了另一个矩阵的分配和计算时间。进一步halpha 将指向同一个内存块。这可能适合也可能不适合您的应用程序,但这是优化 matlab 编译器过去功能的一种方法。
  • 那么,你确定 h(2:N,:) 等价于 h[N*rows+cols+1]?
  • 将 plhs[0] 设置为等于 prhs[0] 不是一个好主意。您不仅要修改输入变量(这会破坏 MATLAB 的写时复制优化),而且您还告诉 MATLAB 它有一个新的输出变量要管理,但实际上它与输入的内存完全相同。清除或覆盖这两个变量时,我预计会发生崩溃。
  • 确实关心它传递给和从 mex 文件接收的内容的状态。这就是定义的接口的全部内容。尝试清除,并在调用修改输入的 mex 函数之前尝试制作输入变量的简单副本。 IE。 h2 = h; evil_mex_function(h); disp(h); disp(h2); 剧透:h2 将具有您对 h 所做的相同更改。例如:stackoverflow.com/q/9845097/1401351
  • @user8430 是的,最后一行是关闭的。我以为您只是对维度感兴趣,而不是对实际内容感兴趣,以解决您可以做[2*h(1:end-1,:)+diff(h);h(end,:)] 的问题。无论如何,我已经更新了我的答案并删除了任何进一步的建议。另外,我放了一个工作 cpp 示例来说明您想要做什么。我已经在 R2015a 中的各种矩阵上对其进行了测试,并且对于您提供的 matlab 代码、我的 cpp 代码和此评论中的行得到了完全相同的结果。如果这仍然不是您想要的,其他人也许可以提供帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-24
  • 1970-01-01
相关资源
最近更新 更多