using matlab engine from c++: How to convert a int** into mxArray*

1 view (last 30 days)
Hi,
I am opening matlab engine from c++, and I want to find the inverse matrix of a matrix. I have tried to convert the int** matrix into mxArray* in different ways, without success:
S = mxCreateDoubleMatrix(v->getCols(), v->getRows(), mxREAL);
memcpy(mxGetPr(S), v->getOpSet(), sizeof(v->getOpSet()));
or:
S = mxCreateDoubleMatrix(v->getCols(), v->getRows(), mxREAL);
mxSetPr(S,(double*)v->getOpSet());
double *acc =mxGetPr(S);
for(p=0;p<mxGetM(S); p++){
for(p1=0 ; p1<mxGetN(S) ; p1++){
cout<< acc[mxGetM(S)*p1+p];
}
}
cout<<endl;
On my first try, the first 2 elements are exponential and weird, and the rest of the matrix is 0.
on my second try, all of the elements are weird, and I get segmentation fault.
have someone have some experience with this and knows how to make the convertion?
another problem I have is that I can't get the result in an array, only as string. meaning,how can I get 'x' as a double array (not mxArray) after this:
buffer[BUFSIZE] = '\0';
engOutputBuffer(ep, buffer, BUFSIZE);
engEvalString(ep, "x = mldivide(S,T)");
(after this code, buffer contains the right result, but if I do:
D=engGetVariable(ep, "x");
D doesn't contain the right result.
is there a way to do this right?
thank you.

Accepted Answer

James Tursa
James Tursa on 29 Aug 2011
Repeating your comment above for how you allocate opSet:
opSet = new double*[columns];
for (p=0; p<columns ; p++)
opSet[p] = new double[rows];
Since you allocate it this way, it is NOT guaranteed to be contiguous in memory as you claim. What you have done is first allocate an array of row pointers, and then each row pointer gets allocated a row of memory and those rows are NOT required to be next to each other in memory. They might happen to be for a particular run, but they might not be for another run. This is not a good way to allocate a matrix. What you should be doing is allocate the entire matrix as one contiguous block, and then if you want row pointers you can set them to point as desired. e.g., something like this:
opSet = new double*[columns];
opSet[0] = new double[rows*columns];
for (p=1; p<columns ; p++)
opSet[p] = opSet[p-1] + rows;
That way you are guaranteed that the matrix is contiguous in memory and you can reliably use memcpy etc to copy the entire contents at once by just using the address in opSet[0]. Also, it is easier to clean up since you only have to delete opSet[0] and opSet (i.e., you don't need a for loop to delete opSet[1] through opSet[columns-1] since they were not separately allocated).
On the memcpy side, be sure you are using the v->opSet()[0] address, not just v->opSet() as you show above. The first is the address of the double data, while the second is the address of the row pointer array (not what you want to copy).
For the number of bytes to copy, you also incorrectly use sizeof(v->getOpSet()), which will give you the size of a pointer (typically 4 or 8 depending on your system). You should be using something like v->getCols() * v->getRows() instead.
  1 Comment
Meytal
Meytal on 29 Aug 2011
Hi James,
I just wanted to thank you for all your help. I finally succeeded.
thank you again.

Sign in to comment.

More Answers (2)

Pierre
Pierre on 29 Aug 2011
I didn't really get your posted code as it requires some guessing, but let me point out a few things:
1. While you might be used to row-major order from C++ code/libraries, MATLAB uses column-major order. This requires you to manually reorganize data when passing from one representation to the other one. (And, most likely it should be mxCreateDoubleMatrix(v->get Rows(), v->get Cols(), mxREAL);
2. To be honest, I didn't check that explicitely, but after years of excessive C++ coding, I'd personally never expect the canonical casting of an array's content to work: Casting an int to double, is something different than casting an int* to a double* !!!
int i = 1234;
double d = (double)i; // d=1234.0
but
int* i_ptr = new int;
*i_ptr = 1234;
double* d_ptr = (double*) i_ptr; // (*d_ptr) = ???
(*d_ptr) will read out the integer represenation of 1234 as if it was stored as a double in memory.
  1 Comment
Meytal
Meytal on 29 Aug 2011
hi,
1. yes, I know about the difference, but my matrixes are square, so it doesn't matter.
2. I don't think this is what making all the trouble, but i'll check it.
thank you.

Sign in to comment.


Meytal
Meytal on 29 Aug 2011
I tried what pierre suggested, and the convertion still does not work.
I get something like this: 1 2.10535e-314 0 0 0 0 4 1 0 0 4.21457e-302 0 0 0 0 0 0 1 0 2.122e-314 0 0 0 0 0 0 1 4.24399e-314 0 0 0 0 1 -7.84591e+298 0 0 0 0 0 0 0 0 0 1.27625e-303 0 0 0 0 0 0 1 1.66952e-308 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -7.84591e+298 0 0 0 0 0 0 0 -7. 84591e+298 0 0 0 0 0 0 2.10535e-314 0 0 0 0 0 0 0 0 4.24396e-302 0 1 0 0 1 0 1 4.2066e-302 0 0 0 0 0 0 0 1 2.122e-314 0 0 0 0 0 0 0 0 0 2.10535e-314 0 0 0 0 0 0 4.2286e-302 0 0 0 1 0 0 1.27629e-303 4 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -7.84591e+298 0 0 0 0 0 0 0 0 0 1.66944e-308 0 0 0 0 0 0 2.1 0535e-314 0 0 0 0 1 0 4.23599e-302 0 0 0 0 0 1 0 0 2.122e-314 0 0 0 0 1 0
instead of this: 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Does anyone else have an idea?
  4 Comments
James Tursa
James Tursa on 29 Aug 2011
What does the (double **) value that is returned by getOpSet point to? E.g., if I do this: double **x = v->getOpSet(), then what does x point to? What does *x point to? Is your array data contiguous in memory, and if so how would I get the starting address of the data from x?
Meytal
Meytal on 29 Aug 2011
the double** value points to the matrix I want to convert. It's supposed to be contiguous in memory, it is allocated this way:
opSet = new double*[columns];
for (p=0; p<columns ; p++)
opSet[p] = new double[rows];

Sign in to comment.

Categories

Find more on Creating and Concatenating Matrices in Help Center and File Exchange

Tags

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!