How to return a 2D double array in Mex

  • Follow


I have one question related to the Mex problem as follows:
-------------------------------------------------------------------------------------------
double **candidates; 
candidates = new double*[num_candidates];
for(int i=0; i<num_candidates; i++)	
			candidates[i] = new double[dim];
-------------------------------------------------------------------------------------------
Then after some operation in C code. 

I would like to output candidates with double pointer. how to do it? 

My code is :
-------------------------------------------------------------------------------------------
plhs[0] = mxCreateDoubleMatrix(num_candidates, dim, mxREAL);
double *candi = new double[num_candidates*dim];
	for(int i=0; i<num_candidates; i++)
	{
		memcpy(&candi[dim*i], candidates[i], sizeof(double)*dim);
	}

	mwSize dims_candidates[2];
	dims_candidates[0] = num_candidates;
	dims_candidates[1] = dim; 
	mxSetPr	        (plhs[0], candi);
	mxSetDimensions (plhs[0], dims_candidates, 2);
-------------------------------------------------------------------------------------------
But it seems doesn't work.  Please help me. 
0
Reply Alex 1/29/2011 3:29:07 PM

Dear Alex,

> plhs[0] = mxCreateDoubleMatrix(num_candidates, dim, mxREAL);
Now copy the values in the array obtained by mxGetPr(plhs[0]):

> double *candi = mxGetPr(plhs[0]);
> 	for(int i=0; i<num_candidates; i++)
> 	{
> 		memcpy(&candi[dim*i], candidates[i], sizeof(double)*dim);
> 	}

That's it. No further setting of mxsetPr or mxSetN.

Good luck, Jan
0
Reply Jan 1/29/2011 4:39:04 PM


"Jan Simon" wrote in message <ii1fr7$7rv$1@fred.mathworks.com>...
> Dear Alex,
> 
> > plhs[0] = mxCreateDoubleMatrix(num_candidates, dim, mxREAL);
> Now copy the values in the array obtained by mxGetPr(plhs[0]):
> 
> > double *candi = mxGetPr(plhs[0]);
> > 	for(int i=0; i<num_candidates; i++)
> > 	{
> > 		memcpy(&candi[dim*i], candidates[i], sizeof(double)*dim);
> > 	}
> 
> That's it. No further setting of mxsetPr or mxSetN.
> 
> Good luck, Jan

It works now, thank you so much. Jan. Regards.
0
Reply Alex 1/29/2011 4:52:03 PM

"Alex Lu" <luzhaojin@gmail.com> wrote in message <ii1bo3$hip$1@fred.mathworks.com>...
> I have one question related to the Mex problem as follows:
> -------------------------------------------------------------------------------------------
> double **candidates; 
> candidates = new double*[num_candidates];
> for(int i=0; i<num_candidates; i++)	
> 			candidates[i] = new double[dim];
> -------------------------------------------------------------------------------------------
> Then after some operation in C code. 
> 
> I would like to output candidates with double pointer. how to do it? 
> 
> My code is :
> -------------------------------------------------------------------------------------------
> plhs[0] = mxCreateDoubleMatrix(num_candidates, dim, mxREAL);
> double *candi = new double[num_candidates*dim];
> 	for(int i=0; i<num_candidates; i++)
> 	{
> 		memcpy(&candi[dim*i], candidates[i], sizeof(double)*dim);
> 	}
> 
> 	mwSize dims_candidates[2];
> 	dims_candidates[0] = num_candidates;
> 	dims_candidates[1] = dim; 
> 	mxSetPr	        (plhs[0], candi);
> 	mxSetDimensions (plhs[0], dims_candidates, 2);
> -------------------------------------------------------------------------------------------
> But it seems doesn't work.  Please help me. 

You have two major problems. 

1) You cannot mix mxArray memory with C/C++ native memory. By that I mean that you cannot use local variable memory or memory allocated with new, malloc, calloc, etc in an mxArray. That will mess up the MATLAB memory manager and likely lead to a program bomb. So you cannot do this:

    mxSetPr(plhs[0], candi);

because candi is pointing to native C++ memory allocated with the new operator:

    double *candi = new double[num_candidates*dim];

To do this kind of thing you would need to allocate candi with mxMalloc or mxCalloc.

2) MATLAB stores 2D matrices in column order, whereas in your C++ setup the data is stored in rows. If you are copying from a 2D C++ variable into a MATLAB 2D variable you will need to create the MATLAB variable as the transpose of the C++ variable, then copy the data over, then transpose the result on the MATLAB side. Either that, or write special copying code that does the transpose as part of the copy. e.g., you would need to change this creation:

    plhs[0] = mxCreateDoubleMatrix(num_candidates, dim, mxREAL);

to this:

    plhs[0] = mxCreateDoubleMatrix(dim, num_candidates, mxREAL);

and then transpose the result once it got back to MATLAB.

A minor problem:

3) You are leaking memory with this statement:

    mxSetPr(plhs[0], candi);

The mxSetPr function does *not* free any existing allocated memory before replacing its internal pr pointer with candi. So all that memory you just allocated with the mxCreateDoubleMatrix function call gets leaked. The proper way to do this is as follows:

    mxFree(mxGetPr(plhs[0]));
    mxSetPr(plhs[0], candi);

That way the existing memory is freed before you replace the pointer with your candi pointer.

-- BUT --

Having pointed out your errors, I would hasten to add that you are going about this in the most inefficient way possible. All that C++ memory allocation, then copying, etc, can be avoided if you simply create the MATLAB mxArray *first* and then just point into it to use it. e.g., something like this:

    double **candidates;
    double *candi;
    // Do this first
    plhs[0] = mxCreateDoubleMatrix(dim, num_candidates, mxREAL);
    // Then get pointers to the data area
    candi = mxGetPr(plhs[0]);
    // Then set up candidates if you really want to preserve the 2D indexing
    candidates = mxMalloc(num_candidates*sizeof(*candidates));
    for(int i=0; i<num_candidates; i++)	{
        candidates[i] = candi + i * dim;
    }
    // Use candi and candidates here
    // Then free your temporary memory
    mxFree(candidates);


James Tursa
0
Reply James 1/29/2011 5:04:03 PM

"Jan Simon" wrote in message <ii1fr7$7rv$1@fred.mathworks.com>...
> Dear Alex,
> 
> > plhs[0] = mxCreateDoubleMatrix(num_candidates, dim, mxREAL);
> Now copy the values in the array obtained by mxGetPr(plhs[0]):
> 
> > double *candi = mxGetPr(plhs[0]);
> > 	for(int i=0; i<num_candidates; i++)
> > 	{
> > 		memcpy(&candi[dim*i], candidates[i], sizeof(double)*dim);
> > 	}
> 
> That's it. No further setting of mxsetPr or mxSetN.

Almost. This doesn't account for the transpose row vs column issue since the plhs[0] variable is num_candidates x dim, not dim x num_candidates. See my other post.

James Tursa
0
Reply James 1/29/2011 8:28:03 PM

4 Replies
376 Views

(page loaded in 0.065 seconds)

Similiar Articles:













7/23/2012 10:49:12 AM


Reply: