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

1 回表示 (過去 30 日間)
HiWave
HiWave 2013 年 5 月 23 日
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 件のコメント
James Tursa
James Tursa 2013 年 5 月 24 日
Yep ... I was mislead by the mxGetPr (returns a double *) and failed to notice the mxSINGLE_CLASS in the construction.
Jan
Jan 2013 年 5 月 25 日
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.

サインインしてコメントする。

採用された回答

James Tursa
James Tursa 2013 年 5 月 26 日
編集済み: James Tursa 2013 年 5 月 26 日
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 件のコメント
HiWave
HiWave 2013 年 5 月 29 日
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!!!!

サインインしてコメントする。

その他の回答 (2 件)

James Tursa
James Tursa 2013 年 5 月 24 日
編集済み: James Tursa 2013 年 5 月 24 日
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 件のコメント
HiWave
HiWave 2013 年 5 月 25 日
What is the difference between these two:
V = mxGetPr(plhs[1]);
memcpy(mxGetPr(APPLE[0]),V,5*10*sizeof(double));
VS
APPLE[0] = plhs[1];
James Tursa
James Tursa 2013 年 5 月 26 日
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.

サインインしてコメントする。


Jan
Jan 2013 年 5 月 23 日
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 件のコメント
HiWave
HiWave 2013 年 5 月 23 日
U = (double*)mxGetPr(plhs[4]);
is a pointer to the 5th output argument of the function. Originally I would pass that argument into a C function and solve for U. The variable U could then be passed into other functions and everything works fine. Now I am replacing the C function that solves for U with a mexCallMATLAB to solve for U. I need to assign the output from the mexCallMATLAB to the variable U, which is defined in the first line of this comment. Not sure how to do that?
Jan
Jan 2013 年 5 月 25 日
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.

サインインしてコメントする。

カテゴリ

Help Center および File ExchangeWrite C Functions Callable from MATLAB (MEX Files) についてさらに検索

Community Treasure Hunt

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

Start Hunting!

Translated by