mxMakeArrayComplex() what's for?

Now (since 2018b) that MATLAB introduces complex-interleaved storage, the C-API has two new functions
mxMakeArrayComplex(A); // or mxMakeArrayReal(A)
That two functions will take the mxArray* A and if it's not Complex/Real then it will convert to the requested type (by adding imag=0 or ignoring imaginary respectively).
Now these functions require the input to be unshared, otherwise it returns the error. One cannot apply this function on any PRHS[.] of the MEX, but one must call
TEMP = mxDuplicateArray(A);
mxMakeArrayComplex(TEMP); // or mxMakeArrayReal(TEMP)
This results two successive memory copies : one deep copy (as it-is) followed by one expansion/truncating copy.
If the inputs is from local create mxArray* user might directly create the type he/she wants and not need to call those functions at all.
From these observations, my question is: what those functions are intended for? It looks like they are just badly designed.
Enclose is a mexfile for those who want to investigate to start with:
#include "mex.h"
#include "matrix.h"
/*
* foo.c test condition to call C-API mxMakeArrayComplex()
* inspired from : https://fr.mathworks.com/help/matlab/apiref/mxmakearraycomplex.html
*
* >> mex -O -R2018a foo.c
*
* >> foo([2 3])
* RETURNS
* 2.0000 + 0.0000i 3.0000 + 0.0000i
*/
extern mxArray *mxCreateSharedDataCopy(const mxArray *pr);
#define A_IN prhs[0]
#define AC_OUT plhs[0]
// Main function ===============================================================
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
int status;
mxArray *temp;
if (nlhs >= 1) AC_OUT = mxCreateDoubleMatrix(0,0,mxREAL);
else AC_OUT = NULL;
if (nrhs >= 1)
{
#if MX_HAS_INTERLEAVED_COMPLEX
// if the next statement is replaced by (temp = A_IN), mxMakeArrayComplex(temp) will fail
temp = mxDuplicateArray(A_IN);
status = mxMakeArrayComplex(temp);
if (status == 0) mexPrintf("cannot make array complex\n");
else
{
if (AC_OUT) mxDestroyArray(AC_OUT);
AC_OUT = temp;
}
#endif
}
}

7 Comments

James Tursa
James Tursa on 17 Sep 2018
Edited: James Tursa on 17 Sep 2018
"... One cannot apply this function on any PRHS[.] of the MEX ..."
The mxMakeArrayComplex( ) and mxMakeArrayReal( ) functions operate on an mxArray inplace by design, so one should not expect them to be able to operate on the prhs[ ] variables. Also note that as of R2015b, all input variables are passed into the mex routine as shared data copies. So the prhs[ ] variables will always be shared with something in R2015b and later.
Bruno Luong
Bruno Luong on 17 Sep 2018
Edited: Bruno Luong on 17 Sep 2018
That's what I understood, but then I still can't see how they can be used.
If they intend to be apply on local non-shared variable, thanks I (as the programmer) will set whatever type I aim for during the creation.
Secondary, TMW can certainly design differently to avoid 2 memory copying if one want to apply on the RHS.
I think those two functions will fall into my ignore list no sooner than we finish discussing and no better argument to defend them would be found.
"... TMW can certainly design differently to avoid 2 memory copying if one want to apply on the RHS ..."
Yes. I would never want to accept that behavior as a programmer and would end up writing my own functions to avoid that extra copy.
James Tursa
James Tursa on 17 Sep 2018
Edited: James Tursa on 17 Sep 2018
One part of the doc I find interesting is this:
"Returns 0 if unsuccessful. The function is unsuccessful if pa is NULL, nonnumeric, or read-only."
How does these functions know if the argument is read-only? And what does this really mean? My guess is they compare the address against some internal list (maybe the caller's workspace), and/or they check for variable sharing, but this is just a guess.
When I test my prhs[0] is not NULL and numerical, so it must be read-only (not by rule but by some mysterious hidden mechanism/attribute) if we assume the doc is accurate.
James Tursa
James Tursa on 17 Sep 2018
Edited: James Tursa on 17 Sep 2018
Side Note: Turning a variable from real to complex used to be very easy ... all you needed to do was attach memory behind the pi pointer which could be accomplished with the standard API function mxSetPi( ) or mxSetData( ).
Now it is tricky to do manually since you would have to hack into the mxArray header to set one of the flags bits. So one is forced outside of the official API in order to avoid that extra data copy.
Similar comments for converting from complex to real.
Bruno Luong
Bruno Luong on 18 Sep 2018
Edited: Bruno Luong on 18 Sep 2018
James, calling mxSetPi will result a compilation error in R2018b.

Sign in to comment.

Answers (1)

James Tursa
James Tursa on 17 Sep 2018
Edited: James Tursa on 17 Sep 2018
If it is your own low level code creating and manipulating the mxArray variables, then I agree with you that this function probably isn't needed since the complexity can be managed directly by you the programmer. But the example in the doc uses a mexCallMATLAB call, so it appears that is the intended purpose. E.g. you are calling a function that maybe you didn't write and want to make sure before going downstream in your code that the mxArray in question has the complexity you want. Although the doc doesn't explicitly state so, I would have to assume when changing complexity that you get a temporary bump in memory usage during the process and then the old memory block gets free'd automatically.

2 Comments

Another related question. Do you know the need for
plhs[0] = mxDuplicateArray(lhs[0]);
in the example of doc file. In my case I do the equivalent of
plhs[0] = lhs[0];
and it seems work just fine.
The example in the doc does not appear to be written very well. IMO neither of the mxDuplicateArray( ) calls are needed, and this should work just fine:
mexCallMATLAB(1, plhs, 1, prhs, "sqrt");
if(!mxIsComplex(plhs[0])) {
/* preserve complexity of data */
mxMakeArrayComplex(plhs[0]);
}
Or, to avoid a compiler warning
mexCallMATLAB(1, plhs, 1, (mxArray **)prhs, "sqrt");
I am not sure why that 4th input argument to mexCallMATLAB doesn't have a const in the signature definition, since I wouldn't expect the call to ever modify that argument.

Sign in to comment.

Categories

Asked:

on 17 Sep 2018

Edited:

on 18 Sep 2018

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!