用于设置向量/矩阵的C ++ Eigen库中的未知错误

时间:2017-01-26 17:51:44

标签: c++ algorithm matlab eigen

我正在尝试实施Longstaff和Scwartz算法,这种算法本质上是一种最小二乘法,可以为美国期权定价。我使用Matlab代码作为参考,用C ++编程。

到目前为止,我所做的是首先设置名为

的时间步变量

dt = T/N其中T是到期时间,N是时间步数。

然后是时间向量(在Matlab中表示为t = 0:dt:T)。我在C ++中为此创建了一个函数,该函数发布在下面:

    VectorXd range(double min, double max, int N){
    VectorXd m(N + 1);
     double delta = (max-min)/N;
     for(int i = 0; i <= N; i++){
             m(i) = min + i*delta;
     }
    return m;
}

然后我必须生成一个生成一组正态分布随机数的向量。在Matlab中,该函数称为z = randn(M/2,1),其中M是路径数。在C ++中,我为此创建了一个函数,如下所示:

MatrixXd generateGaussianNoise(int n, int m){
    MatrixXd M(n,m);
    VectorXd V(n);
    normal_distribution<double> nd(0.0, 1.0);
    random_device rd;
    mt19937 gen(rd());
    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++){
            M(i,j) = nd(gen);
        }
    }
    return M;
}

现在我们必须创建另一个名为w = (r-sigma^2/2)*T + sigma*sqrt(T)*[z;z]的向量。在此之前,我必须创建另一个C ++函数来处理Matlab语法[z;z],如下所示:

MatrixXd generateMatrix(MatrixXd z){
    MatrixXd Dm(2*z.rows(),z.cols());
        Dm << z, -z;
        return Dm;
}

然后我可以用我在下面创建的另一个C ++函数创建w变量:

MatrixXd generateWMatrix(double r, double sigma, double T, MatrixXd Dm){
    MatrixXd w(Dm.rows(),Dm.cols());
    for(int i = 0; i < Dm.rows(); i++){
        for(int j = 0; j < Dm.cols(); j++){
            w(i,j) = (r - pow(sigma,2)/2)*T + sigma*sqrt(T)*Dm(i,j);
        }
    }
        return w;
}

现在我们必须创建一个新变量S = S0*exp(w),其中S0是初始资产价格。我们可以在下面列出的for循环中执行此操作:

MatrixXd S(w.rows(),w.cols());
        for(int i = 0; i < w.rows(); i++){
            for(int j = 0; j < w.cols(); j++){
                S(i,j) = exp(w(i,j));
            }
        }

现在,这件事对我来说有点难看,这篇文章的要点。我们必须为实际算法执行后向for循环。我将提供Matlab代码的开头部分以供参考,这是我在C ++中出错的地方:

for i = N:-1:2

    z = randn(M/2,1);
    w = t(i)*w/(t(i+1)) + sigma*sqrt(dt*t(i)/(t(i+1)))*[z;z];

现在在C ++中,我尝试做的是:

for(int i = N; i >= 2; i--){
      z(i) = generateGaussianNoise(M/2, 1);
      zz(i) = generateMatrix(z);
      w(i) = t(i)*w(i)/(t(i+1)) + sigma*sqrt(dt*t(i)/(t(i+1)))*zz(i);
}

虽然z(i)出现以下错误:

cannot convert 'Eigen::MatrixXd {aka Eigen::Matrix<double, -1, -1>}' to 

'Eigen::DenseCoeffsBase<Eigen::Matrix<double, -1, -1>, 1>::Scalar {aka 
double}' in assignment

zz(i)我收到以下错误:

cannot convert 'Eigen::MatrixXd {aka Eigen::Matrix<double, -1, -1>}' to 

'Eigen::DenseCoeffsBase<Eigen::Matrix<double, -1, -1>, 1>::Scalar {aka double}' in assignment

w(i)我收到以下错误:

invalid arguments '
Candidates are:
double sqrt(double)
float sqrt(float)
long double sqrt(long double)
__gnu_cxx::__enable_if<74 0 __value 14 std::__is_integer 1 #074 0 __value 14 std::__is_integer 1 #0,double>::__type sqrt(#0)
const Eigen::CwiseUnaryOp<Eigen::internal::scalar_sqrt_op<#0::Scalar>,const #0> sqrt(const Eigen::ArrayBase<#0> &)
float sqrt(float)
long double sqrt(long double)
std::complex<#0> sqrt(const std::complex<#0> &)
__gnu_cxx::__enable_if<74 0 __value 14 std::__is_integer 1 #074 0 __value 14 std::__is_integer 1 #0,double>::__type 

我不确定在上面的后者我做错了什么或这些错误意味着什么。当然我试过谷歌搜索他们看看问题是什么,但我没有得到任何有用的信息。为了完整起见,我将在下面发布我的全部代码:

#include <iostream>
#include <cmath>
#include <math.h>
#include <limits>
#include <algorithm>
#include <Eigen/Dense>
#include <Eigen/Geometry>
#include <random>

using namespace Eigen;
using namespace std;


double LaguerreExplicit(int R, double x); // Generates the (weighted) laguerre value
double payoff_Call(double S, double K); // Pay off of a call option
MatrixXd generateGaussianNoise(int n, int m); // Generates Normally distributed random numbers
double LSM(double T, double r, double sigma, double K, double S0, int N, int M, int R);
// T        Expiration time
// r        Riskless interest rate
// sigma    Volatility
// K        Strike price
// S0       Initial asset price
// N        Number of time steps
// M        Number of paths
// R        Number of basis functions

VectorXd range(double min, double max, int N);
MatrixXd generateMatrix(MatrixXd z);
MatrixXd generateWMatrix(double r, double sigma, double T, MatrixXd z);

int main(){
double r = 0.06;
double sigma = 0.25;
int T = 1.0;
int N = 2;
double dt = T/N;
    VectorXd t = range(0.0, T, N);

    MatrixXd result1 = generateGaussianNoise(2,1);


    MatrixXd result2 = generateMatrix(result1);

    MatrixXd w = generateWMatrix(r,sigma,T, result2);







}


double payoff_Call(double S, double K){
    double payoff;
    if((S - K) > 0)
    {
        payoff = S - K;
    }else
    {
        payoff = 0.0;
    }
    return payoff;
}

double LaguerreExplicit(int R, double x){
    double value;
    if(R==0)
    {
        value = 1;
    }
    else if(R==1)
    {
        value = 0.5*(pow(x,2) - 4.0*x + 2);
    }
    else if(R==3)
    {
        value = (1.0/6.0)*(-1*pow(x,3) + 9*pow(x,2) - 18*x + 6);
    }
    else if(R==4)
    {
        value = (1.0/24.0)*(pow(x,4) - 16*pow(x,3) + 72*pow(x,2) - 96*x + 24);
    }
    else if(R==5)
    {
        value = (1.0/120.0)*(-1*pow(x,5) + 25*pow(x,4) - 200*pow(x,3) + 600*pow(x,2) - 600*x + 120);
    }
    else if (R==6)
    {
        value = (1.0/720.0)*(pow(x,6) - 36*pow(x,5) + 450*pow(x,4) - 2400*pow(x,3) + 5400*pow(x,2) - 4320*x + 720);
    }
    else{
        cout << "Error!, R is out of range" << endl;
        value  = 0;
    }
    value = exp(-0.5*x)*value; // Weighted used in Longstaff-Scwartz
    return value;
}

MatrixXd generateGaussianNoise(int n, int m){
    MatrixXd M(n,m);
    normal_distribution<double> nd(0.0, 1.0);
    random_device rd;
    mt19937 gen(rd());
    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++){
            M(i,j) = nd(gen);
        }
    }
    return M;
}

VectorXd range(double min, double max, int N){
    VectorXd m(N + 1);
     double delta = (max-min)/N;
     for(int i = 0; i <= N; i++){
             m(i) = min + i*delta;
     }
    return m;
}

MatrixXd generateMatrix(MatrixXd z){
    MatrixXd Dm(2*z.rows(),z.cols());
        Dm << z, -z;
        return Dm;
}


MatrixXd generateWMatrix(double r, double sigma, double T, MatrixXd Dm){
    MatrixXd w(Dm.rows(),Dm.cols());
    for(int i = 0; i < Dm.rows(); i++){
        for(int j = 0; j < Dm.cols(); j++){
            w(i,j) = (r - pow(sigma,2)/2)*T + sigma*sqrt(T)*Dm(i,j);
        }
    }
        return w;
}



double LSM(double T, double r, double sigma, double K, double S0, int N, int M, int R){
    double dt = T/N;
    VectorXd t = range(0,T,N);
    MatrixXd z = generateGaussianNoise(M/2, 1);
    MatrixXd zz = generateMatrix(z); // Need to do this for the [z;-z]
    MatrixXd w = generateWMatrix(r, sigma, T, zz);
    MatrixXd S(w.rows(),w.cols());
        for(int i = 0; i < w.rows(); i++){
            for(int j = 0; j < w.cols(); j++){
                S(i,j) = exp(w(i,j));
            }
        }
    MatrixXd P(S.rows(), S.cols());

    MatrixXd z_new(M,1);
    for(int i = N; i >= 2; i--){
        z_new.topRows(M/2) = generateGaussianNoise(M/2,1);
        z_new.bottomRows(M/2) = -z_new.topRows(M/2);
        w = t(i-1)*w/t(i) + sigma*sqrt((dt*t(i-1)/t(i)))*z_new;
    }







    return 0;

}

更新 我添加了新的完整代码,但我仍然在名为exp()的函数中的sqrt()double LSM(double T, double r, double sigma, double K, double S0, int N, int M, int R)中出现了一些错误我试图谷歌我能做什么,但我没有想法如何修复以下错误消息:

exp()我收到此消息:

Invalid arguments '
Candidates are:
double exp(double)
float exp(float)
long double exp(long double)
__gnu_cxx::__enable_if<74 0 __value 14 std::__is_integer 1 #074 0 __value 14 std::__is_integer 1 #0,double>::__type exp(#0)
const Eigen::CwiseUnaryOp<Eigen::internal::scalar_exp_op<#0::Scalar>,const #0> exp(const Eigen::ArrayBase<#0> &)
float exp(float)
long double exp(long double)
std::complex<#0> exp(const std::complex<#0> &)
__gnu_cxx::__enable_if<74 0 __value 14 std::__is_integer 1 #074 0 __value 14 std::__is_integer 1 #0,double>::__type 

对于sqrt()我收到此消息:

Invalid arguments '
Candidates are:
double sqrt(double)
float sqrt(float)
long double sqrt(long double)
__gnu_cxx::__enable_if<74 0 __value 14 std::__is_integer 1 #074 0 __value 14 std::__is_integer 1 #0,double>::__type sqrt(#0)
const Eigen::CwiseUnaryOp<Eigen::internal::scalar_sqrt_op<#0::Scalar>,const #0> sqrt(const Eigen::ArrayBase<#0> &)
float sqrt(float)
long double sqrt(long double)
std::complex<#0> sqrt(const std::complex<#0> &)
__gnu_cxx::__enable_if<74 0 __value 14 std::__is_integer 1 #074 0 __value 14 std::__is_integer 1 #0,double>::__type

这是我试图在Eigen中实现的Matlab代码。我将在Matlab代码中发布我已经成功完成的部分以及我很难实现的部分:

function u = LSM(T,r,sigma,K,S0,N,M,k)
% T Expiration time
% r Riskless interest rate
% sigma Volatility
% K Strike price
% S0 Initial asset price
% N Number of time steps
% M Number of paths
% k Number of basis functions
dt = T/N; % Time steps
t = 0:dt:T; % Time vector
z = randn(M/2,1);
w = (r-sigmaˆ2/2)*T + sigma*sqrt(T)*[z;-z];
S = S0*exp(w);
P = max(K-S,0); % Payoff at time T
for i = N:-1:2
z = randn(M/2,1);
w = t(i)*w/t(i+1) + sigma*sqrt(dt*t(i)/t(i+1))*[z;-z];

for循环之后的所有东西都是我在努力的地方......

2 个答案:

答案 0 :(得分:2)

以下行没有意义:

zz(i) = generateMatrix(z);

zz(i)double&,而generateMatrix则返回MatrixXd。与w(i)相同。

答案 1 :(得分:1)

你几乎可以逐字翻译这个Matlab代码

for i = N:-1:2
    z = randn(M/2,1);
    w = t(i)*w/t(i+1) + sigma*sqrt(dt*t(i)/t(i+1))*[z;-z];
end

到Eigen(假设循环外的所有东西都有效):

MatrixXd zz(M,1); // allocate space for [z; -z] only once
for(int i=N; i>=2; --i){
    zz.topRows(M/2) = generateGaussianNoise(M/2,1);
    zz.bottomRows(M/2) = -zz.topRows(M/2);

    w = t(i-1)*w/t(i) + sigma*std::sqrt(dt*t(i-1)/t(i))*zz;
}

基本上,唯一的区别是Matlab开始索引为1而Eigen从0开始。

在Eigen中连接[z;-z]也不可能“内联”,但我想知道为什么你为z-z做同样的计算......