Upgrade MEX Files to Use Interleaved Complex API
This topic describes how to upgrade your MEX files to use the interleaved complex API.
You can continue to use the separate complex API by calling the mex
command with the -R2017b
option. However, for more information about
using this option, see Do I Need to Upgrade My MEX Files to Use Interleaved Complex API?
Note
If you build your MEX files using the mex
command with the
-compatibleArrayDims
option, then you first must update the
source code to use the 64-bit API. For information, see Upgrade MEX Files to Use 64-Bit API.
To update your MEX source code, use the following checklist.
Review your code for usage of
pr
andpi
pointers, the pointers returned by themxGetPr
/mxGetPi
andmxGetData
/mxGetImagData
functions. In the interleaved complex API, there is one pointer,pa
, the value returned bymxGetDoubles
and the other typed data functions. It is important to check an input array for complexity before attempting to read the data. Calls tomxGetPr
andmxGetData
on complex arrays return different results in the interleaved complex API than in the separate complex API.Prepare your code before editing.
Before modifying your code, verify that the MEX function works with the
-R2017b
API. At a minimum, build a list of expected inputs and outputs, or create a full test suite. Use these tests to compare the results with the updated source code. The results should be identical.Back up all source, binary, and test files.
Iteratively refactor your existing code by checking for the following conditions.
After each change, compile using the interleaved complex API. To build
myMexFile.c
, type:To buildmex -R2018a myMexFile.c
myMexFile.F
, type:mex -R2018a myMexFile.F
Resolve failures and warnings.
Test after each refactoring.
Compare the results of running your MEX function compiled with the interleaved complex API with the results from your original binary. If there are any differences or failures, use a debugger to investigate the cause. For information on the capabilities of your debugger, refer to your compiler documentation.
Check Array Complexity Using mxIsComplex
If your code calls the mxGetPi
function to determine if an
array has complex elements, use the mxIsComplex
function instead.
This function builds with both the -R2017b
and
-R2018a
APIs. Search your code for the following
patterns.
Replace C Source Code: | With: |
---|---|
mxArray *pa; ... if (mxGetPi(pa)) { /* process complex array */ } |
mxArray *pa; ... if (mxIsComplex(pa)) { /* process complex array */ } |
double *ptr; ptr = mxGetPi(pa); if (ptr != NULL) { /* process complex array */ } |
Add MX_HAS_INTERLEAVED_COMPLEX
to Support Both Complex Number Representations
To write code that builds with both the -R2017b
and
-R2018a
APIs, add the
MX_HAS_INTERLEAVED_COMPLEX
macro. This macro returns
true
if you build the MEX file with the
-R2018a
option.
Wrapping the following code in an #if
MX_HAS_INTERLEAVED_COMPLEX
statement ensures that this code will build
with either the -R2017b
or -R2018a
mex
option. However, in this example, there is no code to
execute when built with -R2018a
.
Replace C Source Code: | With: |
---|---|
static void analyze_double(const mxArray *array_ptr) { mwSize total_num_of_elements, index; double *pr, *pi; total_num_of_elements = mxGetNumberOfElements(array_ptr); pr = mxGetPr(array_ptr); pi = mxGetPi(array_ptr); for (index=0; index<total_num_of_elements; index++) { if (mxIsComplex(array_ptr)) { mexPrintf("%g + %gi\n", *pr++, *pi++); } else { mexPrintf("%g\n", *pr++); } } } |
static void analyze_double(const mxArray *array_ptr) { mwSize total_num_of_elements, index; total_num_of_elements = mxGetNumberOfElements(array_ptr); #if MX_HAS_INTERLEAVED_COMPLEX /* interleaved complex API processing */ mxComplexDouble *pc; mxDouble *p; if (mxIsComplex(array_ptr)) { pc = mxGetComplexDoubles(array_ptr); for (index=0; index<total_num_of_elements; index++) { mexPrintf(" = %g + %gi\n",(*pc).real,(*pc).imag); pc++; } } else { p = mxGetDoubles(array_ptr); for (index=0; index<total_num_of_elements; index++) { mexPrintf(" = %g\n", *p++); } } #else /* separate complex API processing */ double *pr, *pi; pr = mxGetPr(array_ptr); pi = mxGetPi(array_ptr); for (index=0; index<total_num_of_elements; index++) { if (mxIsComplex(array_ptr)) { mexPrintf("%g + %gi\n", *pr++, *pi++); } else { mexPrintf("%g\n", *pr++); } } #endif } |
Replace Fortran Source Code: | With: |
---|---|
mwPointer prhs(*), pr pr = mxGetPr(prhs(1)) |
mwPointer prhs(*), pr #if MX_HAS_INTERLEAVED_COMPLEX pr = mxGetDoubles(prhs(1)) #else pr = mxGetPr(prhs(1)) #endif |
Use Typed Data Access Functions
To use the mxGetData
and mxGetImagData
functions, you must verify the type of the input mxArray
and
manually cast the pointer output to the correct type. The typed data access
functions verify the type of the array and return the correct pointer type. When you
use the mxGetInt16s
and mxGetComplexInt16s
functions in the following code to process an int16
array, you do
not need to remember the corresponding C type, short int
.
Replace C Source Code: | With: |
---|---|
static void analyze_int16(const mxArray *array_ptr) { short int *pr, *pi; pr = (short int *)mxGetData(array_ptr); pi = (short int *)mxGetImagData(array_ptr); if (mxIsComplex(array_ptr)) { /* process complex data *pr,*pi */ } else { /* process real data *pr */ } } |
static void analyze_int16(const mxArray *array_ptr) { mxComplexInt16 *pc; mxInt16 *p; if(mxIsComplex(array_ptr)) { pc = mxGetComplexInt16s(array_ptr); /* process complex data (*pc).real,(*pc).imag */ } } else { p = mxGetInt16s(array_ptr); /* process real data *p */ } } } |
Handle Complex mxArrays
The following examples show how MATLAB® uses one array variable to represent a complex array.
Complex C mxArrays
Suppose that you have the following complex mxArray
variables and want to add the real numbers and the imaginary numbers of
x
and y
to create array
z
. Arrays x
and y
are the same size.
mxArray * x, y, z;
Instead of creating two pointers xr
and
xi
for array x
, create one pointer
xc
of type mxComplexDouble
. To access
the real and imaginary parts of element xc[i]
, use
xc[i].real
and xc[i].imag
.
Replace C Source Code: | With: |
---|---|
double *xr, *xi, *yr, *yi, *zr, *zi; /* get pointers to the real and imaginary parts of the arrays */ xr = mxGetPr(x); xi = mxGetPi(x); yr = mxGetPr(y); yi = mxGetPi(y); zr = mxGetPr(z); zi = mxGetPi(z); ... /* perform addition on element i */ zr[i] = xr[i] + yr[i]; zi[i] = xi[i] + yi[i]; |
/* get pointers to the complex arrays */ mxComplexDouble * xc = mxGetComplexDoubles(x); mxComplexDouble * yc = mxGetComplexDoubles(y); mxComplexDouble * zc = mxGetComplexDoubles(z); ... /* perform addition on element i */ zc[i].real = xc[i].real + yc[i].real; zc[i].imag = xc[i].imag + yc[i].imag; |
The following code copies an mxArray
into an output
argument. The code shows how to test for and copy complex arrays.
Replace C Source Code: | With: |
---|---|
mxGetPr(plhs[0])[0] = mxGetPr(prhs[0])[index]; if (mxIsComplex(prhs[0])) { mxGetPi(plhs[0])[0] = mxGetPi(prhs[0])[index]; } |
if (mxIsComplex(prhs[0])) { mxGetComplexDoubles(plhs[0])[0] = mxGetComplexDoubles(prhs[0])[index]; } else { mxGetDoubles(plhs[0])[0] = mxGetDoubles(prhs[0])[index]; } |
Complex Fortran mxArrays
Suppose that you have two complex double mxArrays
and want
to pass them to a Fortran function with input arguments x
and
y
defined as follows.
complex*16 x(*), y(*)
Instead of separately converting the real and imaginary parts of each
mxArray
, use the mxGetComplexDoubles
function.
Replace Fortran Source Code: | With: |
---|---|
mwPointer mxGetPr, mxGetPi C Copy the data into native COMPLEX Fortran arrays. call mxCopyPtrToComplex16( + mxGetPr(prhs(1)), + mxGetPi(prhs(1)),x,nx) call mxCopyPtrToComplex16( + mxGetPr(prhs(2)), + mxGetPi(prhs(2)),y,ny) |
mwPointer mxGetComplexDoubles integer*4 status integer*4 mxCopyPtrToComplex16, mxCopyComplex16ToPtr C Copy the data into native COMPLEX Fortran arrays. status = + mxCopyPtrToComplex16(mxGetComplexDoubles(prhs(1)),x,nx) C Test status for error conditions status = + mxCopyPtrToComplex16(mxGetComplexDoubles(prhs(2)),y,ny) C Test status for error conditions |
Maintain Complexity of mxArray
This C code snippet shows how to convert a real, double, input array
prhs[0]
into a complex array. The following code sets up the
variables used to fill the complex part of the array with consecutive
numbers.
// code to check number of arguments and expected types mwSize rows = mxGetM(prhs[0]); mwSize cols = mxGetN(prhs[0]); mwSize sz = mxGetElementSize(prhs[0]);
The following code shows how to use mxMakeArrayComplex
to
convert a real, double, input array to an interleaved complex
mxArray
. For more examples, see mxMakeArrayComplex (C)
.
Replace C Source Code: | With: |
---|---|
plhs[0] = mxDuplicateArray(prhs[0]); mxDouble *dc = (mxDouble*)mxMalloc(rows*cols*sz); mxSetImagData(plhs[0], dc); for (int i = 0 ; i < rows*cols ; i++) { dc[i] = i+1; } |
plhs[0] = mxDuplicateArray(prhs[0]); if (mxMakeArrayComplex(plhs[0])) { mxComplexDouble *dt = mxGetComplexDoubles(plhs[0]); for (int i = 0 ; i < rows*cols ; i++) { dt[i].imag = i+1; } } |
Replace Separate Complex Functions
The following functions are not in the interleaved complex API. You must replace them with interleaved complex functions when handling complex data.
mxGetPi
mxSetPi
mxGetImagData
mxSetImagData
You can replace calls to mxGetPr
and
mxGetPi
with a call to
mxGetComplexDoubles
. This function verifies that your array
contains elements of type mxComplexDouble
. Likewise,
mxSetComplexDoubles
replaces mxSetPr
and mxSetPi
.
The mxGetData
and mxGetImagData
functions do not check the type of the array. Instead, you must cast the return
value to the pointer type that matches the type specified by the input. Replace
calls to mxGetData
and mxGetImagData
with
the single, appropriate, typed data access function, for example,
mxGetComplexInt64s
.
Replace C Source Code: | With: |
---|---|
mxArray *pa; mwSize numElements; int64_T *pr, *pi; pr = (int64_T *)mxGetData(pa); pi = (int64_T *)mxGetImagData(pa); numElements = mxGetNumberOfElements(pa); |
mxArray *pa; mwSize numElements; mxComplexInt64 *pc; pc = mxGetComplexInt64s(pa); numElements = mxGetNumberOfElements(pa); |
Calculate Array Data Size with mxGetElementSize
In the -R2018a
API, the mxGetElementSize (C)
function
returns sizeof(std::complex<T>)
for a complex
mxArray
with data type T
. This value is
twice the value returned by the function in the -R2017b
API.
Similarly, mxGetElementSize (Fortran)
in the -R2018a
API
returns twice the value as the function in the -R2017b
API.
Consider Replacing To-Be-Phased-Out Functions
The following functions are in both the -R2017b
and the
-R2018a
APIs. While you do not need replace them with typed
data access functions, the typed data functions provide type checking. Also, if you
use mxGetPr
, you might choose mxGetPi
for
any complex array processing. This code pattern causes errors when writing
-R2018a
MEX functions.
mxGetPr
mxSetPr
mxGetData (C)
andmxGetData (Fortran)
- for numeric arraysmxSetData (C)
andmxSetData (Fortran)
- for numeric arrays
You can replace calls to mxGetPr
with a call to
mxGetDoubles
. This function verifies that your array
contains elements of type mxDouble
. Likewise,
mxSetDoubles
replaces mxSetPr
. To
replace calls to mxGetData
and mxSetData
functions, choose the appropriate typed data access function, for example,
mxGetInt64s
and mxSetInt64s
.
Replace C Source Code: | With: |
---|---|
double *y; /* create a pointer y to input matrix */ y = mxGetPr(prhs[1]); |
mxDouble *p; p = mxGetDoubles(prhs[1]); |
Replace Fortran Source Code: | With: |
---|---|
mwPointer pr mwPointer mxGetPr C Create a pointer to input matrix pr = mxGetPr(prhs(1)) |
mwPointer pr mwPointer mxGetDoubles pr = mxGetDoubles(prhs(1)) |
Add Build Information to MEX Help File
Consider creating a help file, described in Use Help Files with MEX Functions, that contains build information. For
example, create a file displayTypesafeNumeric.m
containing the
following text.
% displayTypesafeNumeric.m Help file for displayTypesafeNumeric C MEX function % % Use the following command to build this MEX file: % mex -R2018a displayTypesafeNumeric.c
At the MATLAB command prompt, type:
help displayTypesafeNumeric
displayTypesafeNumeric.m Help file for displayTypesafeNumeric C MEX function Use the following command to build this MEX file: mex -R2018a displayTypesafeNumeric.c