MATLAB Answers

Mex C++ unable to realize simple arithmetic operations with TypedArray std::complex<double>

31 views (last 30 days)
Matthieu Dupre
Matthieu Dupre on 1 Feb 2021
I am trying to mex a C++ function to compute some elements in a matrix with complex value. I have no issue when I use double instead of std::complex<double>.
The complex version is the following:
#include "mex.hpp"
#include "mexAdapter.hpp"
#include <complex>
using namespace matlab::data;
using matlab::mex::ArgumentList;
class MexFunction : public matlab::mex::Function {
ArrayFactory factory;
public:
void operator()(ArgumentList outputs, ArgumentList inputs) {
const std::complex<double> I(0.0, 1.0); //define imaginary constant
const TypedArray<double> R = std::move(inputs[0]); // move inputs (1xN) into a TypedArray
TypedArray<std::complex<double>> U=factory.createArray<std::complex<double>>({1,R.getDimensions()[1]}); // create a complex array same size as R
for(size_t uind=0; uind<U.getDimensions()[1];uind++){U[0][uind] =I+U[0][uind];} // does not work
//for(size_t uind=0; uind<U.getDimensions()[1];uind++){U[0][uind] = I+I;} // Works
outputs[0] = std::move(U);
}
};
Compilation fails, the error message is much longer, I only paste here the beginnign for visibility:
mex test_complex.cpp
Building with 'MinGW64 Compiler (C++)'.
Error using mex
C:\Data\mex\test_complex.cpp: In member function 'virtual void MexFunction::operator()(matlab::mex::ArgumentList, matlab::mex::ArgumentList)':
C:\Data\mex\test_complex.cpp:17:75: error: no match for 'operator+' (operand types are 'const std::complex<double>' and
'matlab::data::ArrayElementTypedRef<std::complex<double>, false>')
for(size_t uind=0; uind<U.getDimensions()[1];uind++){U[0][uind] =I+U[0][uind];} // does not work
In file included from C:\Program Files\MATLAB\R2020b/extern/include/MatlabDataArray/matlab_data_array_defs.hpp:6:0,
from C:\Program Files\MATLAB\R2020b/extern/include/MatlabDataArray.hpp:7,
from C:\Program Files\MATLAB\R2020b/extern/include/mexAdapter.hpp:10,
from C:\Data\mex\test_complex.cpp:3:
C:/ProgramData/MATLAB/SupportPackages/R2020b/3P.instrset/mingw_w64.instrset/lib/gcc/x86_64-w64-mingw32/6.3.0/include/c++/complex:445:5: note: candidate: template<class _Tp>
std::complex<_Tp> std::operator+(const std::complex<_Tp>&)
operator+(const complex<_Tp>& __x)
^~~~~~~~
C:/ProgramData/MATLAB/SupportPackages/R2020b/3P.instrset/mingw_w64.instrset/lib/gcc/x86_64-w64-mingw32/6.3.0/include/c++/complex:445:5: note: template argument deduction/substitution
failed:
C:\Data\mex\test_complex.cpp:17:85: note: candidate expects 1 argument, 2 provided
for(size_t uind=0; uind<U.getDimensions()[1];uind++){U[0][uind] =I+U[0][uind];} // does not work
Using += , * , *= operators return similar errors.
What is strange is the the same function with double values does nto return any issue and works fine:
#include "mex.hpp"
#include "mexAdapter.hpp"
using namespace matlab::data;
using matlab::mex::ArgumentList;
class MexFunction : public matlab::mex::Function {
ArrayFactory factory;
public:
void operator()(ArgumentList outputs, ArgumentList inputs) {
const TypedArray<double> R = std::move(inputs[0]);
TypedArray<double> U=factory.createArray<double>({1,R.getDimensions()[1]});
for(size_t uind=0; uind<U.getDimensions()[1];uind++){U[0][uind] = U[0][uind]+1;}
outputs[0] = std::move(U);
}
};
>> mex test_real.cpp
Building with 'MinGW64 Compiler (C++)'.
MEX completed successfully.
>> test_real(1:10)
ans =
1 1 1 1 1 1 1 1 1 1
  1 Comment
Riccardo Scorretti
Riccardo Scorretti on 4 May 2021
Thank you very much. In fact I have a similar problem, which I don't manage to fix by using casting. I'm trying to adapt the example arrayProduct.cpp so that it can works with complex values.
I tried the modification hereafter, but I got the following error message at run-time (the program compiles with no warning):
Error using arrayProductComplex
Can't convert the Array to this TypedArray
I guess it is a similar issue. Any hint to fix it? Thank you in advance
//
// arrayProduct.cpp - example in MATLAB External Interfaces
//
// (includes, comments, etc.)
class MexFunction : public matlab::mex::Function {
public:
void operator()(matlab::mex::ArgumentList outputs, matlab::mex::ArgumentList inputs) {
checkArguments(outputs, inputs);
std::complex<double> multiplier = inputs[0][0]; // So far, so good
// Here I get a run-time error
matlab::data::TypedArray<std::complex<double>> in = std::move(inputs[1]);
arrayProduct(in, multiplier);
outputs[0] = std::move(in);
}
void arrayProduct(matlab::data::TypedArray<std::complex<double>>& inMatrix, std::complex<double> multiplier) {
for (auto& elem : inMatrix) {
elem *= multiplier;
}
}
// Here is the (modifid) method checkArguments
};

Sign in to comment.

Answers (1)

Aghamarsh Varanasi
Aghamarsh Varanasi on 21 Apr 2021
Edited: Aghamarsh Varanasi on 21 Apr 2021
Hi Matthieu Dupre,
The binary operator '+' in 'std::complex<T>' is only defined for adding types std::complex<T>' or 'scalar'. While using the 'operator[ ]' for 'matlab::data::TypedArray<T>', the return type is a 'ArrayElementTypedRef'. As the binary '+' operator is not defined for 'ArrayElementTypedRef' in 'std::complex<T>' you are recieving this error.
To overcome this issue,
  1. You can initialize the value of 'U[0][uind]' to a variable of type 'std::complex<double>'. Hence, your code would be,
#include "mex.hpp"
#include "mexAdapter.hpp"
#include <complex>
using namespace matlab::data;
using matlab::mex::ArgumentList;
class MexFunction : public matlab::mex::Function {
ArrayFactory factory;
public:
void operator()(ArgumentList outputs, ArgumentList inputs) {
const std::complex<double> I(0.0, 1.0); //define imaginary constant
const TypedArray<double> R = std::move(inputs[0]); // move inputs (1xN) into a TypedArray
TypedArray<std::complex<double>> U=factory.createArray<std::complex<double>>({1,R.getDimensions()[1]}); // create a complex array same size as R
// creating a temporary variable
std::complex<double> tmp;
for(size_t uind=0; uind<U.getDimensions()[1];uind++){
// initializing U[0][uind] to tmp
tmp = U[0][uind];
U[0][uind] = I + tmp;} // this does work !!
//for(size_t uind=0; uind<U.getDimensions()[1];uind++){U[0][uind] = I+I;} // Works
outputs[0] = std::move(U);
}
2. Or, you could type cast 'U[0][uind]' to 'std::complex<double'>. For Example,
#include "mex.hpp"
#include "mexAdapter.hpp"
#include <complex>
using namespace matlab::data;
using matlab::mex::ArgumentList;
class MexFunction : public matlab::mex::Function {
ArrayFactory factory;
public:
void operator()(ArgumentList outputs, ArgumentList inputs) {
const std::complex<double> I(0.0, 1.0); //define imaginary constant
const TypedArray<double> R = std::move(inputs[0]); // move inputs (1xN) into a TypedArray
TypedArray<std::complex<double>> U=factory.createArray<std::complex<double>>({1,R.getDimensions()[1]}); // create a complex array same size as R
for(size_t uind=0; uind<U.getDimensions()[1];uind++){
U[0][uind] = I + (std::complex<double>) U[0][uind];} // this does work !!
//for(size_t uind=0; uind<U.getDimensions()[1];uind++){U[0][uind] = I+I;} // Works
outputs[0] = std::move(U);
}
Hope this helps

Community Treasure Hunt

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

Start Hunting!