7

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

>> mat
mat =
 1    10
 2    20
 3    30
 4    40
 5    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";            
        }
    }     
}

这会产生:

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

当我更改 graph_list 的定义并尝试对 graph_list 进行 2D 索引时,会出现以下编译错误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.
4

3 回答 3

10

编译器说明了一切。

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

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

我的猜测是 MATLAB 这样做是为了保持索引数组的一致性——你真的期望/想要double****一个 4-D 数组吗?

而且,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 的,而 Matlab 是基于 1 的,使得所有索引都不同
  3. 所有数组都必须称为“A”

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

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

(或如ShaimxCalcSingleSubscript所指出的那样使用),但这并不能真正提高表现力恕我直言:

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

您也可以用 C++ 编写,用 . 创建一个 Matrix 类型的类,operator()用指针和维度等构造它mxGetPr()mxGetDims()在 Matlab 中使用g++或等效编译,但这会引入一大堆其他问题并增加更多复杂性大多数情况下都不需要。

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

于 2013-04-22T12:14:48.390 回答
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";
}
于 2013-08-10T10:34:24.983 回答
2

正如Rody所指出的,mxGetPr返回一个指向一数组的指针。因此,您不能将其视为 C++ 中的二维数组。
您可以做的是使用mxCalcSingleSubscript函数将ND下标转换为单个 1D 索引。

于 2013-04-22T12:10:14.563 回答