MATLAB Answers

HELP....mxCallMATLAB output assignment to variable???

1 view (last 30 days)
HiWave
HiWave on 23 May 2013
I've spent a week on the following problem and I can't for the life of me figure it out! I'm going to be as brief as possible with the code and chop out irrelevant lines but it should be clear as to my problem. For starters, I'm using Matlab in combination with C, which communicates via mex files. Without further ado...
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
static double *U
plhs[4] = mxCreateNumericArray(2,dims,mxDOUBLE_CLASS,mxREAL);
U = (double*)mxGetPr(plhs[4]);
/* C code which solves for "U" based on a number of other input variables*/
solve(U,...,...,...)
/* C code which solves for "U" based on a number of other input variables*/
derivative(U,...,...,...)
}
After execution, everything works fine and I have the value for the derivative of "U". I then wanted to compare solvers so I'm swapping out the "solve(U)" for a Matlab function which I call via "mexCallMATLAB". Here is where I get lost
(Again I removed irrelevant variables)
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
static double *U
plhs[4] = mxCreateNumericArray(2,dims,mxDOUBLE_CLASS,mxREAL);
U = (double*)mxGetPr(plhs[4]);
/* Call MATLAB solver */
mxArray *Uin[8],*Uout[2];
Uin[0] = mxCreateNumericArray(2,dims,mxSINGLE_CLASS,mxREAL);
memcpy(mxGetPr(Uin[0]),(some variable),m*n*sizeof(float));
yes there are 8 inputs...I just removed for simplicity
mexCallMATLAB(2,Uout,8,Uin,"my_matlab_solver");
I then check the results of "Uout" with the following:
mexCallMATLAB(0,NULL,1,&Uout[0],"plot_variable");
Everything works out great, but the "C" code that later calls on the variable "U" to find it's derivative does not work.
plhs[4] = Uout[0];
/* C code which solves for "U" based on a number of other input variables*/
derivative(U,...,...,...)
}
I can not figure out how to assign "Uout[0]" to "U". I thought by setting plhs[4] = Uout[0] then U would point to the results from "my_matlab_solver" but it does not. There are no compile errors.
Is there easier way where I can assign the output of "my_matlab_solver" directly to "U" with out having to make a mxArray for the output? This whole MEX thing seems a lot more complicated than it needs to be. Thanks for you help!
************************************************************************** ************************************************************************** **************************************************************************
EDIT: I'm going to be very blunt
I have a variable called "U" which is defined as follows
U = (double*)mxGetPr(plhs[4]);
How do I assign the output from this mexCallMATLAB
mexCallMATLAB(2,Uout,8,Uin,"my_matlab_solver");
to "U"? I tried this; plhs[4] = Uout[0]; but it does not work. Don't worry about the rest of the code it's fine. My problem is strictly related to assigning the output of mexCallMATLAB to a variable defined as "U" is above.
  5 Comments
Jan
Jan on 25 May 2013
You cannot and should assign the output of the Matlab call to U. The output of the Matlab call is an mxArray variable and U is a pointer to a double array. Perhaps you want to obtain another pointer to the data of the output.
It seems, like the concept of the mxArray variables and the pointers to their contents is not clear to you already.
It is hard for me to give advices of the code, because the code is posted in parts and distributed over several comments and sections. I do not think that the rest of the code is fine, because the confusion with the mxArray plhs[4] and pointers to data appear repeatedly.

Sign in to comment.

Accepted Answer

James Tursa
James Tursa on 26 May 2013
Edited: James Tursa on 26 May 2013
Try this. It works for me with some simple test code for FILLAB, my_matlab_solver, and plot_variable. I added some comments where you have memory leaks and type issues, and put in some code for variable class and size checks.
/* Did you include string.h? (for memcpy) */
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
static double *A,*B;
mwSize dims[2] = {5,10}; // Use mwSize here, not int.
static double *U,*V;
mxArray *APPLE[1];
mxArray *Uin[2],*Uout[2];
if( nlhs < 2 ) {
mexErrMsgTxt("Not enough outputs.");
}
A = mxGetPr(mxCreateNumericArray(2,dims,mxDOUBLE_CLASS,mxREAL)); // MEMORY LEAK!
B = mxGetPr(mxCreateNumericArray(2,dims,mxDOUBLE_CLASS,mxREAL)); // MEMORY LEAK!
// In the above two lines, you lose the pointers to the mxArrays! Bad practice!
/* C code which fills A and B */
FILLAB(A,B);
Uin[0] = mxCreateNumericArray(2,dims,mxDOUBLE_CLASS,mxREAL);
Uin[1] = mxCreateNumericArray(2,dims,mxDOUBLE_CLASS,mxREAL);
memcpy(mxGetPr(Uin[0]),A,5*10*sizeof(double));
memcpy(mxGetPr(Uin[1]),B,5*10*sizeof(double));
Uout[0] = mxCreateNumericArray(2,dims,mxDOUBLE_CLASS,mxREAL); // MEMORY LEAK!
Uout[1] = mxCreateNumericArray(2,dims,mxDOUBLE_CLASS,mxREAL); // MEMORY LEAK!
// In the above two lines, the mxArrays created are lost by the subsequent
// call to mexCallMATLAB, which OVERWRITES the pointers in Uout[0] and Uout[1].
// This is not good programming practice! Just DELETE these two lines entirely!
mexCallMATLAB(2,Uout,2,Uin,"my_matlab_solver"); // This CREATES new outputs in Uout.
// Note, you could use plhs in the 2nd argument above and skipped the following
// two lines assigning Uout to plhs.
plhs[0] = Uout[0];
plhs[1] = Uout[1]; // Need nlhs >= 2 in order for this to work.
U = mxGetPr(plhs[0]);
V = mxGetPr(plhs[1]); // Need nlhs >= 2 in order for this to work.
APPLE[0] = mxCreateNumericArray(2,dims,mxDOUBLE_CLASS,mxREAL);
if( !mxIsDouble(plhs[1]) || mxIsSparse(plhs[1]) || mxGetNumberOfElements(plhs[1]) < 50 ) {
mexErrMsgTxt("plhs[1] is not full double class with 50 or more elements");
}
if( !mxIsDouble(plhs[0]) || mxIsSparse(plhs[0]) || mxGetNumberOfElements(plhs[0]) < 50 ) {
mexErrMsgTxt("plhs[0] is not full double class with 50 or more elements");
}
memcpy(mxGetPr(APPLE[0]),V,5*10*sizeof(double));
/*APPLE[0] = plhs[1]; */
mexCallMATLAB(0,NULL,1,&APPLE[0],"plot_variable");
// Note, you can just use APPLE in the 3rd argument above. No need to use &APPLE[0].
}
  1 Comment
HiWave
HiWave on 29 May 2013
OK...I found out my problem! Your insight to check the following helped me understand:
if( !mxIsDouble(Uout[1]) || mxIsSparse(Uout[1]) || mxGetNumberOfElements(Uout[1]) < 50 ) {
mexErrMsgTxt("Uout[1] is not full double class with 50 or more elements");
Here was the problem: I was originally casting everything as a float or a mxSINGLE_CLASS which worked fine up until I tried to assign another pointer to the output of the mxCallMATLAB, in this case "U" and "V". But in the call mxCallMATLAB to "my_matlab_solver", the output variables I was assigning to "Uout" (within the function) were actually doubles. This is why the following two statements weren't working:
U = mxGetPr(Uout[0]);
V = mxGetPr(Uout[1]);
I then went into the actual matlab script called "my_matlab_solver" and cast the outputs to a single, to be consistent with the rest of the code and it worked. NOTE to self...be sure matlab script uses same casting as C-code! While this is apparently trivial now, it was not so before. Thanks for all your help James!!!!

Sign in to comment.

More Answers (2)

James Tursa
James Tursa on 24 May 2013
Edited: James Tursa on 24 May 2013
Your words from above:
EDIT: I'm going to be very blunt
I have a variable called "U" which is defined as follows
U = (double*)mxGetPr(plhs[4]);
How do I assign the output from this mexCallMATLAB
mexCallMATLAB(2,Uout,8,Uin,"my_matlab_solver");
to "U"? I tried this;
plhs[4] = Uout[0];
but it does not work. Don't worry about the rest of the code it's fine. My problem is strictly related to assigning the output of mexCallMATLAB to a variable defined as "U" is above.
-----------------------------------------------------------------------------
If Uout[0] is indeed assigned by the mexCallMATLAB call, then the plhs[4] = Uout[0] line should have worked, assuming that you do the U = mxGetPr(plhs[4]) line after assigning plhs[4]. In orher words, this order should work:
mexCallMATLAB(2,Uout,8,Uin,"my_matlab_solver");
plhs[4] = Uout[0];
U = mxGetPr(plhs[4]);
And, as Jan has already pointed out, you need to delete a couple of lines related to your first plhs[4] = etc to avoid a memory leak.
  5 Comments
James Tursa
James Tursa on 26 May 2013
The difference between the two above is as follows:
> V = mxGetPr(plhs[1]);
This gets the data pointer from the mxArray plhs[1], which must have a valid mxArray in it or the routine will probably crash MATLAB. This data pointer value is assigned to the variable V. I.e., this statement is just a pointer value assignment to a variable. The data itself is not examined or copied.
> memcpy(mxGetPr(APPLE[0]),V,5*10*sizeof(double));
This copies 50 double values from V into the data memory of the mxArray APPLE[0]. V must point to valid double memory of at least 50 elements and APPLE[0] must already be created to have at least 50 double elements of data or MATLAB will crash.
> APPLE[0] = plhs[1];
This copies the pointer value of plhs[1] into the pointer value of APPLE[0]. It doesn't do anything more. Nothing is checked, no attempt is made to examine the underlying mxArray, and no data is examined or copied. The statement is simply the assignment of a pointer value to a variable.

Sign in to comment.


Jan
Jan on 23 May 2013
I do not understand, what you want to achieve:
plhs[4] = mxCreateNumericArray(2,dims,mxDOUBLE_CLASS,mxREAL);
U = (double*)mxGetPr(plhs[4]);
Now U is the pointer to the data of the 5th output argument.
plhs[4] = Uout[0];
Now the 5th output is overwritten, which means a memory leak (which is caught automatically when the mex function is left fortunately).
But what does >>assign "Uout[0]" to "U"<< mean now? Do you want to get the pointer to the data of Uout[0] again?
U = mxGetPr(Uout[0]);
Btw., mxGetPr replies a double * already, such that you do not have to cast it.
  2 Comments
Jan
Jan on 25 May 2013
No, U is not a pointer to the 5th output. It points to the data of the 5th output and this is an important difference.

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!