如何在MATLAB的mex c ++函数中循环遍历矩阵元素?

Vas*_*ass 7 c++ matlab mex multidimensional-array

我试图索引为MATLAB编写外部c ++函数使用mex来操作矩阵,并且我无法使用多维索引.这里提供一些示例,但我还没有找到如何解决下面描述的问题.我有一个样本矩阵:

>> mat
mat =
 1    10
 2    20
 3    30
 4    40
 5    50
Run Code Online (Sandbox Code Playgroud)

目前我通过矩阵使用线性索引:

#include <mex.h>
#include <iostream>
using namespace std;
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 
{ 
 //1.get pointer to input graph_list and allocate it    
    double *graph_list = mxGetPr(prhs[0]);
    mwSize mrows = mxGetM(prhs[0]);
    mwSize ncols = mxGetN(prhs[0]);  
    cout<< mrows<<" rows\n";
    cout<< ncols<<" cols\n";
    int mm, nn;
    for (nn=0;nn<ncols;nn++) {
        for (mm=0;mm<mrows;mm++){
            cout << graph_list[nn*(mrows) +mm]  <<"\n";            
        }
    }     
}
Run Code Online (Sandbox Code Playgroud)

这会产生:

>> mexTryAlex(mat)    
5 rows
2 cols
1
2
3
4
5
10
20
30
40
50
Run Code Online (Sandbox Code Playgroud)

当我更改graph_list的定义并尝试2D索引到graph_list时,会出现编译错误mex:

double **graph_list = mxGetPr(prhs[0]);
cout << graph_list[nn][mm];
Run Code Online (Sandbox Code Playgroud)

编辑:这是收到的错误消息

>> mex mexTryAlex.cpp
Warning: You are using gcc version "4.4.3-4ubuntu5)".  The version
     currently supported with MEX is "4.3.4".
     For a list of currently supported compilers see: 
     http://www.mathworks.com/support/compilers/current_release/
mexTryAlex.cpp: In function ‘void mexFunction(int, mxArray**, int, const mxArray**)’:
mexTryAlex.cpp:16: error: cannot convert ‘double*’ to ‘double**’ in initialization
mex: compile of ' "mexTryAlex.cpp"' failed.
??? Error using ==> mex at 208
Unable to complete successfully.
Run Code Online (Sandbox Code Playgroud)

Rod*_*uis 9

编译器说明了一切.

在C中,2D数组就像一个数组数组.因此,2D阵列与1D阵列根本不同; 它是一个指针数组,其中每个元素都包含一个指向数组的指针(因此是一个双指针double**).

你要求mxGetPr()返回一个double**,但它返回一个double*,例如,指向一维数组的第一个元素的指针.该1D阵列只能线性索引.

我的猜测是MATLAB以这种方式做到这一点,以保持索引数组的一致性 - 你真的期望/想要double****一个4-D阵列吗?

而且,mxGetPr()不能通过返回类型重载(毕竟它是C).

为了能够对一维数组进行双重索引,你可以潜入一个小宏:

#define A(i,j) A[(i) + (j)*numrows]
Run Code Online (Sandbox Code Playgroud)

并像这样使用它

double *A = mxGetPr(...);
int numrows = 4;   /* or get with mxGetM() or so) */

double blah = A(3,2); /* call to MACRO */
Run Code Online (Sandbox Code Playgroud)

显然,与所有宏一样,需要注意以下几点:

  1. 没有界限检查
  2. C基于0,基于Matlab 1,使所有索引不同
  3. 所有数组都必须被称为'A'

您可以编写一个函数来缓解这些缺点:

double getValue(double** array, int row, int* dims);
Run Code Online (Sandbox Code Playgroud)

(或者mxCalcSingleSubscriptShai所指出的那样使用),但这并没有真正提高表达能力恕我直言:

double blah = getValue(array, 3,4, dims);
/* or the ugliness from mxCalcSingleSubscript(); */
Run Code Online (Sandbox Code Playgroud)

你也可以写在C++中,做一个矩阵型类的operator(),用指针和尺寸构建它mxGetPr()mxGetDims()等,使用编译在Matlab g++或同等学历,但引入了其他问题一大堆,并添加方式更加复杂比大多数情况需要的.

因此,为了避免所有这些混乱,我只是总是在原地计算索引:)


小智 7

具有矩阵类是解决此类问题的最简单方法.有很多可供选择,所以不要费心自己写.犰狳相当不错,如果你使用它也可以与LAPACK集成. http://arma.sourceforge.net/docs.html

见下面的例子

#include <mex.h>
#include <iostream>
#include <armadillo>
using namespace std;
using namespace arma;

//creates an armadillo matrix from a matlab matrix
mat armaMatrix(const mxArray *matlabMatrix[]){
    mwSize mrows = mxGetM(matlabMatrix[0]);
    mwSize ncols = mxGetN(matlabMatrix[0]);
    double *values = mxGetPr(matlabMatrix[0]);

    return mat(values, nrows, ncols);
}

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 
{
    mat graph_list = armaMatrix(prhs);

    //print the matrix
    cout << graph_list<<"\n";
    //print the first column
    cout << graph_list(span::all,0) <<"\n";
}
Run Code Online (Sandbox Code Playgroud)

  • 使用稍多的代码,Armadillo也可以直接使用Matlab矩阵的内存,即.没有复制.查看文档[here](http://arma.sourceforge.net/docs.html#adv_constructors_mat) (3认同)