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
prandpipointers, the pointers returned by themxGetPr/mxGetPiandmxGetData/mxGetImagDatafunctions. In the interleaved complex API, there is one pointer,pa, the value returned bymxGetDoublesand the other typed data functions. It is important to check an input array for complexity before attempting to read the data. Calls tomxGetPrandmxGetDataon 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
-R2017bAPI. 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.
mxGetPimxSetPimxGetImagDatamxSetImagData
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.
mxGetPrmxSetPrmxGetData (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 displayTypesafeNumericdisplayTypesafeNumeric.m Help file for displayTypesafeNumeric C MEX function Use the following command to build this MEX file: mex -R2018a displayTypesafeNumeric.c