I am trying to index write an external c++ function for MATLAB using mex to manipulate matrices, and am not able to use multidimensional indexing. There are examples provided here, but I have not found how to fix the problem I describe below. I have a sample matrix:
>> mat
mat =
1 10
2 20
3 30
4 40
5 50
Currently I use a linear index through the matrix which 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 produces:
>> 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 2D indexing to graph_list there is a compilation error with mex
:
double **graph_list = mxGetPr(prhs[0]);
cout << graph_list[nn][mm];
EDIT: here is the error message received
>> 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.
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's an array of pointers, in which each element contains a pointer to an array (hence a double-pointer, double**
).
You're asking mxGetPr()
to return a double**
, but it returns a double*
, e.g., a pointer to the first element of a 1D array. This 1D array can only be indexed linearly.
My guess is that MATLAB does this it this way to keep indexing arrays consistent -- would you really expect/want a double****
for a 4-D array?
Moreover, mxGetPr()
cannot be overloaded by return type (it's C after all).
In order to be able to double-index a 1D array, you could sneak in a little macro:
#define A(i,j) A[(i) + (j)*numrows]
and use it like so
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's a few things to look out for:
You could write a function to mitigate these drawbacks:
double getValue(double** array, int row, int* dims);
(or use mxCalcSingleSubscript
as pointed out by Shai), but that doesn't really improve expressive power IMHO:
double blah = getValue(array, 3,4, dims);
/* or the ugliness from mxCalcSingleSubscript(); */
You could also write in C++, make a Matrix-type class with an operator()
, construct it with the pointer and dimensions from mxGetPr()
and mxGetDims()
etc., compile in Matlab using g++
or equivalent, but that introduces a whole host of other problems and adds way much more complexity than needed for most cases.
Therefore, to avoid all of this mess, I just always compute the index in-place :)