Data from MEX-File to MATLAB

조회 수: 4 (최근 30일)
Jay
Jay 2011년 7월 5일
Hi folks!
Suppose I want to find all divisors of an input to a MEX-File and return them to the user within MATLAB.
I have written the following simple program (I know it is not the most efficient implementation):
int i;
int counter = 0;
for(i=1;i <=input;i++){
if((input% i) == 0){
plhs[counter] = mxCreateDoubleScalar(i);
counter++;
}
}
Unfortunately, this does not seem to work. What am I doing wrong? What do I need to do to add multiple scalars to the output and why?
Thanks a lot, Jay
  댓글 수: 3
Jan
Jan 2011년 7월 6일
Please explain, what "this does not seem to work" means. Does it only seem, that it does not work, but it works? What results do you get? How do you call the function? How many outputs do you try to export?
Jay
Jay 2011년 7월 6일
Hi James, hi Jan!
Sorry if I was being unclear.
My full code at the moment looks like this:
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){
int i;
int counter = 0;
int input;
input = (int)(mxGetScalar(prhs[0]));
for(i=1;i <=input;i++){
if((input%i) == 0){
plhs[counter] = mxCreateDoubleScalar(i);
counter++;
}
}
}
I am trying to write a mex-file, which receives one input (e.g. 10) and then returns all divisors of 10 in a vector (and maybe additionally I could try to return all divisors as separate scalars?)
So if I'd do: divisors(10) MATLAB would return [1 2 5 10].
Right now MATLAB returns 1 for divisors(10) which I don't understand.
@James: Why would my code return *input* number of variables? And how does the requested number of outputs influence my program?
Thanks a lot guys!
Jay

댓글을 달려면 로그인하십시오.

채택된 답변

James Tursa
James Tursa 2011년 7월 6일
Regarding your crash question, consider this line:
plhs[0] = mxCreateNumericArray((input/2)+1,mxGetDimensions(prhs[0]),mxDOUBLE_CLASS, mxREAL);
Here the mxCreateNumericArray function is expecting the first argument to be the desired number of dimensions. Suppose your input was the single number 10 as in your earlier example. Then you would be telling mxCreateNumericArray that the desired number of dimensions of your output will be (10/2)+1 = 6. Now look at the second argument. This needs to be an array of at least size 6, or a pointer to a memory location with at least 6 elements. But what did you pass it? You passed it a pointer to a memory location that has only 2 elements, namely the 1 x 1 dimensions of your input. So mxCreateNumericArray tried to read 6 elements where there were only 2 elements, reads past valid memory, and bombs.
  댓글 수: 1
James Tursa
James Tursa 2011년 7월 6일
P.S. To use dims properly you need to match it up in size with the ndims parameter. e.g.,
mwSize ndims = 3;
mwSize dims[3] = {2,3,4};
plhs[0] = mxCreateNumericArray(ndim,dims,mxDOUBLE_CLASS,mxREAL);
The above would create a 3D double array of size 2 x 3 x 4 initially filled in with zeros.

댓글을 달려면 로그인하십시오.

추가 답변 (2개)

James Tursa
James Tursa 2011년 7월 6일
The prhs[ ] is an array of input variables, and plhs[ ] is an array of output variables. MATLAB will allocate a fixed number of them based on the calling sequence. You can't go over that amount in your C code. e.g., for the calling sequence on the MATLAB side:
[A B C] = mymexfunction(X,Y)
you will get a prhs array that has been allocated to contain exactly two variables. prhs[0] will be the X input and prhs[1] will be the Y input. The nrhs will tell you how many inputs were on the function call on the MATLAB side, 2 in this case. Likewise, the plhs array will have been allocated to contain exactly three variables, which need to be filled in by you the programmer. So nlhs would be 3 and you would need to create plhs[0], plhs[1], and plhs[2] in your C code and then they would become A, B, and C once the mex functioins returns to MATLAB. In this loop that you show above:
for(i=1;i <=input;i++){
if((input%i) == 0){
plhs[counter] = mxCreateDoubleScalar(i);
counter++;
}
If you pass in a single value of 10 you would end up creating outputs for plhs[1], plhs[2], plhs[5], and plhs[10]. i.e., the user would have had to request 11 separate outputs for this to make sense (and even then you would not be setting 7 other outputs).
What you should be doing instead is creating a single output vector, plhs[0], then use mxGetPr on that to get a pointer to the data area, then use that to fill in values. The tricky part for you will be determining how large to make the output vector. This won't necessarily be easy for a large input value. If this is just a practice mex function you are writing then I would suggest doing something slightly different that has a size that is easy to calculate up front and then work that problem instead.

Jay
Jay 2011년 7월 6일
Hi James! Great answer, thanks. Cleared some stuff up. However I am still not able to get this running. You are right, this is just a practice mex function, however I will have the size problem with the function I need to do after as well, so I might as well tackle it here I guess.
Changed my code now to: #include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){
int i;
int counter = 0;
int input;
double *outputPointer;
input = (int)(mxGetScalar(prhs[0]));
plhs[0] = mxCreateNumericArray((input/2)+1,mxGetDimensions(prhs[0]),mxDOUBLE_CLASS, mxREAL);
outputPointer = mxGetPr(plhs[0]);
for(i=1;i <=input;i++){
if((input%i) == 0){
outputPointer[counter] = i;
counter++;
}
}
}
And it destroys my memory :-(
1. Since my results can only be whole numbers, I should probably use int *outputPointer. However then I wouldnt know which of the mxUINT16_CLASS or mxUINT32_CLASS etc to use.
2. Is mxCreateNumericArray the right function to use here? I just said the size would be (input/2)+1 as a upper boundry. Its okay if I just allocate more memory than I need, isn't it?
3. I am not quite sure what that "const mwSize *dims" in the parameter list of mxCreateNumericArray means. So I tried to hack a bit with mxGetDimensions. I also tried stuff like [1 1] which was wrong I guess ;-)
What of this causes my program to crash?
  댓글 수: 2
Jay
Jay 2011년 7월 6일
I changed the code to:
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){
int i;
int counter = 0;
double input;
double *outputPointer;
input = mxGetScalar(prhs[0]);
plhs[0] = mxCreateDoubleMatrix(1,input, mxREAL);
outputPointer = mxGetPr(plhs[0]);
for(i=1;i <=input;i++){
if(((int)(input)%i) == 0){
outputPointer[counter] = i;
counter++;
}
}
}
(inspired by http://www.codeproject.com/KB/cpp/mexFunction.aspx)
This basically works, however since my output always has size 1xInput I get the correct result and many zeros after.
Whats the best way to really get only the output I want? I mean I could do the computation twice and the first time remember the number of divisors found, but that doesnt seem like a very elegant way to do it.
Thanks!
P.S. Still interested on what I did wrong in the first approach!
James Tursa
James Tursa 2011년 7월 6일
Add this line at the end:
mxSetN(plhs[0],counter);
That will set the size to what you want, but of course the memory is still being used. This will not cause any problems in MATLAB that will crash, but it does use more memory than necessary. If you want to you could copy the data to a new smaller memory block. I would normally advise using mxRealloc in conjunction with mxGetPr and mxSetPr here, but mxRealloc has a bug for some versions of MATLAB and will not recover the memory. So you may need to do this manually via mxMalloc and memcpy.

댓글을 달려면 로그인하십시오.

카테고리

Help CenterFile Exchange에서 Write 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