How to move matrix elements in mex C ++ functions for MATLAB?

I am trying to index a C ++ external function record for MATLAB using mex to control matrices and cannot use multidimensional indexing. There are examples here , but I have not found how to fix the problem described below. I have a sample matrix:

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

I am currently using a linear index through a matrix that works:

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

This gives:

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

When I change the definition of graph_list and try to perform 2D indexing on graph_list, a compilation error occurs with mex :

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

EDIT: error message received here

 >> 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. 
+6
source share
3 answers

The compiler says it all.

In C, a 2D array is like an array of arrays. Therefore, a 2D array is fundamentally different from a 1D array; it is an array of pointers in which each element contains a pointer to an array (therefore, a bi-directional pointer, double** ).

You ask mxGetPr() to return double** , but it returns double* , for example, a pointer to the first element of an 1D array. This 1D array can only be indexed linearly.

My guess is that MATLAB does this in such a way as to support sequential indexing arrays - do you really expect / want a double**** for a 4-D array?

Furthermore, mxGetPr() cannot be overloaded with a return type (after all, C).

To be able to index the 1D array twice, you can sneak into a small macro:

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

and use it like that

 double *A = mxGetPr(...); int numrows = 4; /* or get with mxGetM() or so) */ double blah = A(3,2); /* call to MACRO */ 

Obviously, as with all macros, there are a few things to look for:

  • no border check
  • C is based on 0 and Matlab 1, which makes all indices different
  • All arrays will need to be called "A"

You can write a function to address these shortcomings:

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

(or use mxCalcSingleSubscript as indicated by Shai ), but this does not improve the expressive power of IMHO:

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

You can also write in C ++, create a class of type Matrix with operator() , build it using a pointer and dimensions from mxGetPr() and mxGetDims() , etc., compile in Matlab using g++ or equivalent, but this introduces a number of other problems and adds much greater complexity than is necessary for most cases.

Therefore, to avoid all this mess, I just always calculate the index in place :)

+7
source

Having a matrix class is the easiest way to deal with such problems. There are many options, so don't bother writing your own. Armadillo is pretty good and also integrates with LAPACK if you use this. http://arma.sourceforge.net/docs.html

See example below.

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

As pointed out by Rody , mxGetPr returns a pointer to a 1D array. Therefore, you cannot consider it as a 2D array in C ++.
What you can do is use mxCalcSingleSubscript to convert ND indices to a single 1D index.

+2
source

All Articles