Is it possible to allocate a complex array in a mex file and have the real and imaginary parts be contiguous with each other? I'm working with very large matrices and need to conserve memory and would like to not have to make a copy of the input matrices to get them into FORTRAN format. If the memory were contiguous, I could just rearrange the data into interleaved real and imaginary. I've already been able to pass in a real valued array from matlab and have LAPACK treat it as a complex (it just assumes the real and imaginary are interleaved), but this isn't exactly an elegant solution since I still have to write the data to a file and read it back into complex form. At that point it becomes useless to use MATLAB at all and I might as well just write a standalone program in C or FORTRAN. Any ideas if this can be done or am I out of luck?
MATLAB: Contiguous memory for complex arrays in mex
complexlapackmemorymex
Related Solutions
I am unaware of specific documentation on this, but Part 1 should be sufficient (and safe) as long as you don't care about the wasted memory at the end hanging around (and this is extremely fast of course). I have done this many times myself and have never run into an issue. I have even done this with only one copy of a group of shared data copies (different mxArray variables having different number of elements but pointing to the same data block). I do not believe the MATLAB Memory Manager uses the size information in a mxArray for anything. After all, it is perfectly legal to do this:
mxArray *mx;double *pr;mx = mxCreateDoubleMatrix( 0, 0, mxREAL );pr = mxMalloc( 1000 * sizeof(*pr) );mxSetPr(mx,pr);mxSetM(mx,1);mxSetN(mx,2);// do stuffmxSetN(mx,20);// do more stuff// etc.
So here you also have a mismatch between the allocated memory and the mxArray size information, but everything is OK as long as the memory is large enough to encompass the sizes present.
What I have had issues with in the past is with mxRealloc not always freeing up the memory when going from a large block to a small block. Or, at least the memory didn't always show up as available after the mxRealloc call (maybe the memory manager has it somehow marked internally as available but I didn't have access to the details so I couldn't really tell).
Side Issue:
The following comparison is technically non-conforming:
q != p
If p was free'd by the mxRealloc call, you can't legally use it in downstream code, even for comparison purposes (although you can probably get away with it on the machines we typically run on). So, you could just skip that test entirely and always just do the mxSetPr call regardless if you wanted to be a stickler about conforming code:
mxSetPr(plhs[0], q);
Finally, I don't think q can ever return NULL from a mxRealloc call in a mex routine. I think the doc is to be interpreted as
"... a MAT standalone application or engine standalone application ..."
This change has been incorporated into the documentation in Release 2010a (R2010a). For previous releases, read below for any additional information:
Below is code that shows four valid methods for filling an mxArray with data:
#include"mex.h"#define ONE plhs[0]#define TWO plhs[1]#define THREE plhs[2]#define FOUR plhs[3]void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ){ const double data[]={2.1, 3.4, 2.3, 2.45}; double *dynamicData1, *dynamicData2, *dynamicData4; double nonDynamicData[4]; const int dims[]={0,0}; int i;/********************************************************************************** METHOD 1, mxSetData with dynamic data *********************************************************************************/ dynamicData1 = (double*)mxMalloc(4 * sizeof( double )); // Create the matrix as 0 by 0, since you are about to allocate the memory manually ONE = mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL); for( i = 0; i < 4; i++ ) { // Here, you could be loading data from somewhere. // Instead, just copy from data[i] dynamicData1[i]=data[i]; } // Put the C array into the mxArray. You can do this because // the mxArray is empty (0x0) at this time, so there will be no // memory leak. mxSetData(ONE, dynamicData1); mxSetM( ONE, 2 ); mxSetN( ONE, 2 ); // It is not necessary to call mxFree( dynamicData1 ) because // that memory is pointed to inside the mxArray you are returning./********************************************************************************** METHOD 2, mxSetPr with dynamic data, mxSetPr is only for double data *********************************************************************************/ dynamicData2 = (double*)mxMalloc(4 * sizeof( double )); // Create the matrix as 0 by 0, since you are about to allocate the // memory manually. TWO = mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL); for( i = 0; i < 4; i++ ) { // Here, you could be loading data from somewhere. // Instead, just copy from data[i] dynamicData2[i]=data[i]; } // Put the C array into the mxArray. You can do this because // the mxArray is empty (0x0) at this time so there will be no // memory leak mxSetPr( TWO, dynamicData2 ); mxSetM( TWO, 2 ); mxSetN( TWO, 2 ); // It is not necessary to call mxFree( dynamicData2 ) because // that memory is pointed to inside the mxArray you are returning./********************************************************************************** METHOD 3, mxGetPr with non-dynamic data *********************************************************************************/ // Create the matrix as 2-by-2, since you are just copying existing data into it THREE = mxCreateNumericMatrix(2, 2, mxDOUBLE_CLASS, mxREAL); for( i = 0; i < 4; i++ ) { // Here, you could be loading data from somewhere. // Instead, just copy from data[i] ((double*)mxGetPr(THREE))[i]=data[i]; }/********************************************************************************** METHOD 4, mxGetPr with dynamic data, using a copy of the data *********************************************************************************/ dynamicData4 = (double*)mxMalloc(4 * sizeof( double )); // Create the matrix as 2-by-2, since you are just copying existing data into it FOUR = mxCreateNumericMatrix(2, 2, mxDOUBLE_CLASS, mxREAL); for( i = 0; i < 4; i++ ) { // Here, you could be loading data from somewhere. // Instead, just copy from data[i] dynamicData4[i]=data[i]; } for( i = 0; i < 4; i++ ) { // Copy the data in. ((double*)mxGetPr(FOUR))[i]=dynamicData4[i]; } // You must call mxFree( dynamicData4 ) at this time because // that memory is not pointed to inside the mxArray you are // returning. This is because you copied it into the array with mxGetPr. mxFree( dynamicData4 ); return; }
The above example only uses the double data type, but you can also create mxArrays of other data type. The documentation has an example using unsigned 16-bit integers:
Best Answer