2013-04-22 95 views
5

我想索引编写MATLAB的外部C++函数使用mex操纵矩阵,我不能够使用多维索引。有提供的例子here,但我还没有找到如何解决我下面描述的问题。 我有一个样品基质:当我改变graph_list的定义如何循环遍历mex的C++函数中的矩阵元素?

>> mexTryAlex(mat)  
5 rows 
2 cols 
1 
2 
3 
4 
5 
10 
20 
30 
40 
50 

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

这产生:

>> mat 
mat = 
1 10 
2 20 
3 30 
4 40 
5 50 

目前我通过其工作的矩阵使用线性指数并尝试2D索引到graph_list有一个编译错误mex

double **graph_list = mxGetPr(prhs[0]); 
cout << graph_list[nn][mm]; 

编辑:这里是接收的错误消息

>> 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. 
+1

编译错误是...? – 2013-04-22 11:24:35

+0

嗯,我想'mxGetPr(prhs [0])'是一个指针(而不是一个指针指针),你会得到一个'double dereference'类型的错误? – 2013-04-22 11:26:36

+0

@RodyOldenhuis,我在*编辑*中添加了错误信息我只是把 – Vass 2013-04-22 12:00:35

回答

6

编译器说这一切。在C中,2D数组就像一个数组数组。因此,二维数组与一维数组基本上是不同的;它是一个指针数组,每个元素包含一个指向数组的指针(因此是一个双指针,double**)。

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

我的猜测是MATLAB用这种方法来保持索引数组的一致性 - 你真的希望/想要一个4维数组的double****吗?

而且,mxGetPr()不能被返回类型重载(毕竟它是C)。

为了能够双指数一维数组,你可以在一个小宏潜行:

#define A(i,j) A[(i) + (j)*numrows] 

,并使用它像这样

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

double blah = A(3,2); /* call to MACRO */ 

显然,与所有宏,有几件事情看出来:

  1. 没有边界检查
  2. C是基于0和基于1 MATLAB,使得不同
  3. 所有指数全部阵列将被称为“A”

你可以写一个函数来减轻这些缺点:

double getValue(double** array, int row, int* dims); 

(或使用mxCalcSingleSubscriptShai指出的),但并没有真正提高表现力恕我直言:

double blah = getValue(array, 3,4, dims); 
/* or the ugliness from mxCalcSingleSubscript(); */ 

你也可以用C++编写,制作一个带有operator()的矩阵类,使用指针和尺寸从mxGetPr()mxGetDims()等构建它,在Matlab中使用g++或等价物进行编译,但是会引入一系列其他问题并增加了大多数情况下所需的复杂度。

因此,为了避免这一切混乱的,我只是一直在计算,地方:)

+0

哇,谢谢,我与那场战斗太久了 – Vass 2013-04-22 12:20:27

+0

@Vass:很高兴帮助。通常StackOverflow是当你卡住时最快和最好的解决方案:) – 2013-04-22 12:44:35

+0

我知道去年的这个答案,但我很难解决为什么它是'numRows/mxGetM'而不是'numCols/mxGetN'在' #define A(i,j)A [(i)+(j)* numrows]' – 2014-11-06 02:58:10

2

正如所指出的RodymxGetPr返回一个指向一个1D阵列。因此,您不能将它视为C++中的2D数组。
您可以使用mxCalcSingleSubscript函数将N-D下标转换为单个1D索引。

+0

@Sahi,我不知道我明白。我想使用ND下标,但它们不起作用 – Vass 2013-04-22 12:13:46

+1

@Vass-C++意义上的ND下标(即'graph_list [mm] [nn]')将不起作用,因为'graph_list'是一维C++数组(无论它是从中派生出来的'mxArray'的维数)。您可以使用'mxCalcSingleSubscripts'来绕过这个限制 - 有关更多详细信息,请参阅此命令的doc。 – Shai 2013-04-22 12:16:14

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"; 
} 
+3

随着代码略多,Armadillo也可以直接使用Matlab矩阵的内存,即。没有复制。查看文档[here](http://arma.sourceforge.net/docs.html#adv_constructors_mat) – mtall 2013-08-12 08:29:41