error: no matching constructor for initialization of ... and mexFunction

18 views (last 30 days)
I am trying to wrap a C++ code in matlab using mex interface. However, when following the existing examples about how to construct the mexFunction, I encountred some issues. One of them when I want to call the second constructor of my class (no default one) then I got the following error when I compile
C___class_interface/RBergomiST.cpp:300:30: error: no
matching constructor for initialization of 'RBergomiST'
RBergomiST_instance=RBergomiST(x, HIn, e, r,t, k, NIn, MIn);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The code I am using is the following. Any help please?
#include "class_handle.hpp"
#include "RBergomiST.h"
#include "mex.h"
RBergomiST::RBergomiST() {
N = 0;
M = 0;
nDFT = 0;
par = ParamTot();
xC = new fftw_complex[0];
xHat = new fftw_complex[0];
yC = new fftw_complex[0];
yHat = new fftw_complex[0];
zC = new fftw_complex[0];
zHat = new fftw_complex[0];
}
// seed is optional
RBergomiST::RBergomiST(double x, Vector HIn, Vector e, Vector r, Vector t,
Vector k, int NIn, long MIn){
//std::vector<uint64_t> seed = std::vector<uint64_t>(0)) {
// Some safety tests/asserts?
N = NIn;
nDFT = 2 * N - 1;
M = MIn;
//numThreads = numThreadsIn;
par = ParamTot(HIn, e, r, t, k, x);
xC = new fftw_complex[nDFT];
xHat = new fftw_complex[nDFT];
yC = new fftw_complex[nDFT];
yHat = new fftw_complex[nDFT];
zC = new fftw_complex[nDFT];
zHat = new fftw_complex[nDFT];
fPlanX = fftw_plan_dft_1d(nDFT, xC, xHat, FFTW_FORWARD,
FFTW_ESTIMATE);
fPlanY = fftw_plan_dft_1d(nDFT, yC, yHat, FFTW_FORWARD,
FFTW_ESTIMATE);
fPlanZ = fftw_plan_dft_1d(nDFT, zHat, zC, FFTW_BACKWARD,
FFTW_ESTIMATE);
}
// delete allocated arrays
RBergomiST::~RBergomiST() {
delete[] xC;
delete[] xHat;
delete[] yC;
delete[] yHat;
delete[] zC;
delete[] zHat;
}
// Note that Wtilde[0] = 0!
void RBergomiST::updateWtilde(Vector& Wtilde, const Vector& W1, const Vector& W1perp, double H) {
Vector Gamma(N);
getGamma(Gamma, H);
double s2H = sqrt(2.0 * H);
double rhoH = s2H / (H + 0.5);
Vector W1hat = linearComb(rhoH / s2H, W1, sqrt(1.0 - rhoH * rhoH) / s2H,
W1perp);
Vector Y2(N); // see R code
// Convolve W1 and Gamma
// Copy W1 and Gamma to complex arrays
copyToComplex(W1, xC);
copyToComplex(Gamma, yC);
// DFT both
fftw_execute(fPlanX); // DFT saved in xHat[0]
fftw_execute(fPlanY); // DFT saved in yHat[0]
// multiply xHat and yHat and save in zHat
complexMult(xHat, yHat, zHat);
// inverse DFT zHat
fftw_execute(fPlanZ);
// read out the real part, re-scale by 1/nDFT
copyToReal(Y2, zC);
scaleVector(Y2, 1.0 / nDFT);
// Wtilde = (Y2 + W1hat) * sqrt(2*H) * dt^H ??
Wtilde = linearComb(sqrt(2.0 * H) * pow(1.0 / N, H), Y2,
sqrt(2.0 * H) * pow(1.0 / N, H), W1hat);
}
void RBergomiST::scaleWtilde(Vector& WtildeScaled, const Vector& Wtilde,
double T, double H) const {
for (int i = 0; i < N; ++i)
WtildeScaled[i] = pow(T, H) * Wtilde[i];
}
void RBergomiST::scaleZ(Vector& ZScaled, const Vector& Z, double sdt) const {
for (int i = 0; i < N; ++i)
ZScaled[i] = sdt * Z[i];
}
void RBergomiST::updateV(Vector& v, const Vector& WtildeScaled, double h,
double e, double dt) const {
v[0] = par.xi();
for (int i = 1; i < N; ++i)
v[i] = par.xi() * exp(
e * WtildeScaled[i - 1] - 0.5 * e * e
* pow((i - 1) * dt, 2 * h));
}
void RBergomiST::getGamma(Vector& Gamma, double H) const {
double alpha = H - 0.5;
Gamma[0] = 0.0;
for (int i = 1; i < N; ++i)
Gamma[i] = (pow(i + 1.0, alpha + 1.0) - pow(i, alpha + 1.0)) / (alpha
+ 1.0);
}
void RBergomiST::copyToComplex(const Vector& x, fftw_complex* xc) {
for (size_t i = 0; i < x.size(); ++i) {
xc[i][0] = x[i]; // real part
xc[i][1] = 0.0; // imaginary part
}
// fill up with 0es
for (size_t i = x.size(); i < nDFT; ++i) {
xc[i][0] = 0.0; // real part
xc[i][1] = 0.0; // imaginary part
}
}
void RBergomiST::copyToReal(Vector& x, const fftw_complex* xc) const {
for (size_t i = 0; i < x.size(); ++i)
x[i] = xc[i][0]; // real part
}
void RBergomiST::complexMult(const fftw_complex* x, const fftw_complex* y,
fftw_complex* z) {
for (size_t i = 0; i < nDFT; ++i)
fftw_c_mult(x[i], y[i], z[i]);
}
void RBergomiST::fftw_c_mult(const fftw_complex a, const fftw_complex b,
fftw_complex c) {
c[0] = a[0] * b[0] - a[1] * b[1];
c[1] = a[0] * b[1] + a[1] * b[0];
}
long RBergomiST::getM() const {
return M;
}
void RBergomiST::setM(long m) {
M = m;
}
int RBergomiST::getN() const {
return N;
}
void RBergomiST::setN(int n) {
N = n;
}
double RBergomiST::getXi() const {
return par.xi();
}
double RBergomiST::intVdt(const Vector & v, double dt) const
{
return dt * std::accumulate(v.begin(), v.end(), 0.0);
}
double RBergomiST::intRootVdW(const Vector & v, const Vector & W1, double sdt) const
{
double IsvdW = 0.0;
for(size_t i=0; i<v.size(); ++i)
IsvdW += sqrt(v[i]) * sdt * W1[i];
return IsvdW;
}
double RBergomiST::updatePayoff(long i, Vector& Wtilde,
Vector& WtildeScaled, const Vector& W1, const Vector& W1perp, Vector& v){
double dt = par.T(i) / N;
double sdt = sqrt(dt);
bool update = par.HTrigger(i);
if (update)
updateWtilde(Wtilde, W1, W1perp, par.H(i));
// check if T has changed. If so, Wtilde and the time increment need re-scaling
update = update || par.TTrigger(i);
if (update) {
scaleWtilde(WtildeScaled, Wtilde, par.T(i), par.H(i));
}
// check if eta has changed. If so, v needs to be updated
update = update || par.etaTrigger(i);
if (update)
updateV(v, WtildeScaled, par.H(i), par.eta(i), dt);
// now compute \int v_s ds, \int \sqrt{v_s} dW_s with W = W1
double Ivdt = intVdt(v, dt);
double IsvdW = intRootVdW(v, W1, sdt);
// now compute the payoff by inserting properly into the BS formula
double BS_vol = sqrt((1.0 - par.rho(i)*par.rho(i)) * Ivdt);
//double BS_vol = sqrt((1.0 - par.rho(i)*par.rho(i)) * Ivdt*0.5); //I think there is a factor of sqrt(0.5) missing, need to check this
double BS_spot = exp( - 0.5 * par.rho(i)*par.rho(i) * Ivdt + par.rho(i) * IsvdW );
return BS_call_price(BS_spot, par.K(i), 1.0, BS_vol);
}
double RBergomiST::ComputePayoffRT_single(const Vector & W1, const Vector & W1perp){
Vector Wtilde(N);
Vector WtildeScaled(N); // Wtilde scaled according to time
Vector v(N);
double payoff = updatePayoff(0, Wtilde, WtildeScaled, W1, W1perp, v);
return payoff;
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){
// Get the command string
//Declare variables for the input arguments.
double x;
x= mxGetScalar(prhs[0]);
double *HIn;
HIn= mxGetPr(prhs[1]);
double *e;
e= mxGetPr(prhs[2]);
double *r;
r= mxGetPr(prhs[3]);
double *t;
t= mxGetPr(prhs[4]);
double *k;
k= mxGetPr(prhs[5]);
int NIn;
NIn= mxGetN(prhs[6]);
long MIn;
MIn= mxGetN(prhs[7]);
//
// if (nrhs==0){
// plhs[0]= convertPtr2Mat<RBergomiST>(new RBergomiST);
// return;
// }
// Get the command string
char cmd[64];
if (nrhs < 1 || mxGetString(prhs[0], cmd, sizeof(cmd)))
mexErrMsgTxt("First input should be a command string less than 64 characters long.");
// New
if (!strcmp("new", cmd)) {
// Check parameters
if (nlhs != 1)
mexErrMsgTxt("New: One output expected.");
// Return a handle to a new C++ instance
plhs[0] = convertPtr2Mat<RBergomiST>(new RBergomiST);
return;
}
// Check there is a second input, which should be the class instance handle
if (nrhs < 2)
mexErrMsgTxt("Second input should be a class instance handle.");
// Delete
if (!strcmp("delete", cmd)) {
// Destroy the C++ object
destroyObject<RBergomiST>(prhs[1]);
// Warn if other commands were ignored
if (nlhs != 0 || nrhs != 2)
mexWarnMsgTxt("Delete: Unexpected arguments ignored.");
return;
}
// Get the class instance pointer from the second input
RBergomiST* RBergomiST_instance = convertMat2Ptr<RBergomiST>(prhs[1]);
if(nrhs==8) {
RBergomiST_instance=convertMat2Ptr<RBergomiST>(RBergomiST(x, HIn, e, r,t, k, NIn, MIn));
return;
}
}
  2 Comments
Guillaume
Guillaume on 14 May 2019
Edited: Guillaume on 14 May 2019
I would suspect that Vector is not typedef'd to double* so the type of Hin, e, etc. don't match that of your constructor. You haven't shown what Vector is defined as.
Note that since R2018a, matlab has a direct interface to C++ which would be better than using the C mex interface.
edit: fixed link
Chiheb Ben Hammouda
Chiheb Ben Hammouda on 14 May 2019
Regarding Vector I do know how to convert it in this context and it is defined as such
typedef std::vector<double> Vector;
How can I do it directly without mex? I think the link that you put is wrong!

Sign in to comment.

Answers (1)

Guillaume
Guillaume on 14 May 2019
I've fixed the link in comment. Note that you would still use mex, but the C++ mex interface instead of the C interface.
Regardless of the interface, you cannot pass a pointer to a matlab array (whose memory is controlled by matlab) to a function that expects a std::vector (whose memory is controlled by the vector allocator).
You could change the signature of your constructor so it accepts double pointers (and size), or better the mxArray if using C mex. If using the C++ mex interface, you'd change the signature to accept a matlab::data::TypedArray<T> which is closer to a std::vector but let matlab manage the memory. Either way, you'll have to change the signature of all the functions that need these as inputs.
The other option is to construct the vectors form your mxArray / matlab::data::TypedArray<T>. The disadvantage of this option is that you'd be copying all the arrays (maybe not a bad thing)
So something like, (warning: my C++ is very rusty!)
Using C mex:
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){
//You're missing any kind of input validation. Your code will crash matlab if it receives incorrect inputs
//Add input validation!
double x = mxGetScalar(prhs[0]);
mxArray HinArr = prhs[1];
std::vector<double> Hin = std::vector<double>(mxGetDoubles(HinArr), mxGetDoubles(HinArr) + mxGetNumberOfElements(HinArr));
//etc.
Using C++ mex:
class MexFunction : public matlab::mex::Function {
public:
void operator()(matlab::mex::ArgumentList outputs, matlab::mex::ArgumentList inputs) {
//add input validation
//fetch x
matlab::data::TypedArray<double> HinArr = std::move(inputs[1]);
std::vector<double> Hin = std::vector<double>(HinArr.begin, HinArr.end);
//ec.
  1 Comment
Chiheb Ben Hammouda
Chiheb Ben Hammouda on 25 May 2019
I tried this using mex and I got an error indicating
error: variable has incomplete type 'mxArray' (aka 'mxArray_tag')
mxArray HinArr = prhs[1];

Sign in to comment.

Categories

Find more on Write C Functions Callable from MATLAB (MEX Files) in Help Center and File Exchange

Community Treasure Hunt

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

Start Hunting!