2013-04-22 97 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