I am a graduate student at Florida State University studying financial mathematics. I am still a bit of a novice with C++ but I am trying to implement the Longstaff-Schwartz method for pricing of American options. Although, the algorithm in the journal is a bit daunting thus I am trying to convert the code that was written in Matlab and change it into C++. Essentially I am using the Matlab code as a guide.
I was referred by some stackexchange users to use the Eigen library which contains a good matrix class. Unfortunately the website here does not show me how to make my own function from the class. What I am stuck on is making a C++ function for the function in Matlab that does this:
Say t = 0:1/2:1 then in Matlab the output will be t = 0 0.500 1
So using the Eigen class I created a function called range to achieve the latter above. The function looks like this:
MatrixXd range(double min, double max, double N){
MatrixXd m(N,1);
double delta = (max-min)/N;
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++){
m(i,j) = min + i*delta;
}
}
return m;
}
I do not have any errors on my IDE (Ecclipse) but when I run my code and test this function I get this error message:
c:\mingw\include\c++\6.2.0\eigen\src/Core/PlainObjectBase.h:736:7:
error: static assertion failed:
FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED
I am not sure what is wrong. Any suggestions on achieving what I am trying to do or any suggestions at all are greatly appreciated.
Taking the suggestion by Martijn Courteaux, I changed $N$ into an int now but I now receive a new error that I do not understand:
c:\mingw\include\c++\6.2.0\eigen\src/Core/Matrix.h:350:7: error: static
assertion failed: THIS_METHOD_IS_ONLY_FOR_VECTORS_OF_A_SPECIFIC_SIZE
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(Matrix, 3)
For sake of completeness I will post my whole code below:
#include <iostream>
#include <cmath>
#include <limits>
#include <algorithm>
#include <Eigen/Dense>
#include <Eigen/Geometry>
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
double generateGaussianNoise(double mu, double sigma); // Generates Normally distributed random numbers
double LSM(int 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
MatrixXd range(double min, double max, int N);
int main(){
MatrixXd range(0, 1, 2);
}
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;
}
double generateGaussianNoise(double mu, double sigma)
{
const double epsilon = std::numeric_limits<double>::min();
const double two_pi = 2.0*M_PI;
static double z0, z1;
static bool generate;
generate = !generate;
if (!generate)
return z1 * sigma + mu;
double u1, u2;
do
{
u1 = rand() * (1.0 / RAND_MAX);
u2 = rand() * (1.0 / RAND_MAX);
}
while ( u1 <= epsilon );
z0 = sqrt(-2.0 * log(u1)) * cos(two_pi * u2);
z1 = sqrt(-2.0 * log(u1)) * sin(two_pi * u2);
return z0 * sigma + mu;
}
MatrixXd range(double min, double max, int N){
MatrixXd m(N,1);
double delta = (max-min)/N;
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++){
m(i,j) = min + i*delta;
}
}
return m;
}
double LSM(int T, double r, double sigma, double K, double S0, int N, int M, int R){
double dt = T/N;
MatrixXd m(T,1);
return 0;
}
Here is the corrected function code that I fixed:
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;
}
Mistake is here:
MatrixXd range(double min, double max, double N){
MatrixXd m(N,1);
N is a double. The arguments of MatrixXd::MatrixXd(int, int) are int.
You presumably want to make N an int.
In regard to your edit:
Second mistake is here:
MatrixXd range(0, 1, 2);
in the main() function. Not sure what you are trying to do here, but that constructor is not valid. EDIT: Ah I believe I have an idea. You are trying to call your function named range. Do this like this:
MatrixXd result = range(0.0, 1.0, 2);
Related
Hi guys i created a c program to confront taylor taylor series of cosine and interpolation but i have a problem . The problem is about the function cosine (calculated by using taylor method) because the programme always gives me a degree of 3 , or 1 . My teacher said that i should use this arrest criteria
x^(2k)/(2k!)<t where t is tau in my code , the tolerance. Really thanks to anyone who can help me!
#include<stdio.h>
#include<math.h>
double read_tolerance();
double put_x();
void cosine(double,double,int &,double,double);
double Li(int,int,double[],double);
double Pn(int,double[],double[],double);
void interpo_Lagrange(int);
int main()
{
int k=1;
double cos_initial=1,a=1;
double tau=read_tolerance();
double x=put_x();
cosine (cos_initial,a,k,x,tau);
interpo_Lagrange(k+1);
return 0;
}
double read_tolerance()
{
double t;
printf("\n choose the value of tolerance: ");
scanf("%lf", &t);
return t;
}
double put_x()
{
double x;
printf("\nput value of x: ");
scanf("%lf",&x);
return x;
}
void cosine(double coseno,double a,int &k,double x,double tau)
{
do {
a *= pow(-1,k)*((x*x) / (2*k));
coseno += a;
k=k+2;
}while (a> tau);
printf("value of cosine of %lf is %lf\n",x,coseno);
printf("degree with taylor is ' %d\n",k);
return ;
}
double Li(int i, int n, double x[], double X){
int j;
double prod=1;
for(j=0;j<=n;j++){
if(j!=i)
prod=prod*(X-x[j])/(x[i]-x[j]);
}
return prod;
}
double Pn(int n, double x[], double y[], double X){
double sum=0;
int i;
for(i=0;i<=n;i++){
sum=sum+Li(i,n,x,X)*y[i];
}
return sum;
}
void interpo_Lagrange(int n)
{
int i;
printf("the number of data-points are %d:\n",n);
double x[n];
double y[n];
printf("Enter the x data-points:\n");
for(i=1;i<=n;i++){
x[i]=Pi*i/(8);
printf("%lf\n",x[i]);
}
printf("Enter the y data-points:\n");
for(i=1;i<=n;i++){
y[i]=cos(Pi*i/(8));
printf("%lf\n",y[i]);
}
double X;
printf("Enter the value of x for which you want the interpolated value of y(x):\n");
scanf("%lf",&X);
printf("The interpolated value is %lf",Pn(n,x,y,X));
}
The implementation of tayllor series is incorrect and here is the right one
do {
a *= -((x * x) / ((2 * k - 1) * (2 * k)));
coseno += a;
k = k + 1;
} while (fabs(a) > tau);
i hope this fixes your problem
The first issue is that the term can be negative. So the stopping criteria
must used the absolute value of it.
Another issue is that the used formula is not correct. The calculation of the denominator (fatorial) was not correct.
A last issue is that is is better a little bit that the function return the calculated value: more clear.
Output:
cos calculated = 0.707107
Error = -1.14623e-010
#include <iostream>
#include <cmath>
double cosine (double x, double tolerance) {
double x2 = x*x;
double term = 1;
double y = 1;
int sign = -1;
int k = 2;
do {
term *= x2/(k*(k-1));
y += sign * term;
k += 2;
sign = -sign;
} while (term > tolerance);
return y;
}
int main() {
double tolerance = 1.0e-6;
double angle = 3.141592/4;
double calculated = cosine (angle, tolerance);
double exact = cos(angle);
double err = calculated - exact;
std::cout << "cos calculated = " << calculated << std::endl;
std::cout << "Error = " << err << std::endl;
return 0;
}
I have issues with memory leaks on a C++ function that I have sourced into R through Rcpp. This result in a sudden abortion of my R session, without returning any specific error message.
What is weird to me is that if in function_test I move double lower =1; and double upper = value2; inside the for loop and edited them by also adding 'i': double lower =1 + i; and double upper = value2 + i; the function works without aborting my R session.
The code below is sourced in R using the function sourceCpp from Rcpp R package. I run the function with the following values:
R function:
function_test(value1=4000, value2=4000, alpha = 5e-04)
C++ code sourced in R:
// [[Rcpp::depends(RcppEigen)]]
// [[Rcpp::depends(RcppNumerical)]]
#define EIGEN_PERMANENTLY_DISABLE_STUPID_WARNINGS
#include <Eigen/Eigen>
#include <RcppNumerical.h>
#include <Rcpp.h>
using namespace Rcpp;
using namespace Numer;
// [[Rcpp::export]]
double func1(double t, double alpha, double beta){
double term1 = (( 2.0 * log(t - 0.5)) + 1) / 25.0;
int N;
if (t == 1 || t == 2) {
N = 2;
}else{
if (t <= 44) {
N = t;
}else{
N = 44;
}
}
NumericVector term_up(N);
term_up[0] = 0;
term_up[1] = term1;
double res = std::accumulate(term_up.begin(), term_up.end(), 0.0);
double int_final = (1/(25.0*t)) * (1 - (0.96)*res);
return int_final;
}
class Func1PDF: public Func
{
private:
double alpha;
double beta;
public:
Func1PDF(double alpha_, double beta_) : alpha(alpha_), beta(beta_) {}
double operator()(const double& t) const{
return func1(t, alpha, beta);
}
};
// [[Rcpp::export]]
double integrate_func(double lower, double upper, double alpha, double beta)
{
Func1PDF f(alpha, beta);
double err_est;
int err_code;
const double res = integrate(f, lower, upper, err_est, err_code);
return res;
}
// [[Rcpp::export]]
NumericVector function_test(double value1, double value2, double alpha) {
NumericVector res(value1);
double lower = 1;
double upper = value2;
for(int i=1;i<=value1;i++){
double beta = i;
res[i-1] = integrate_func(lower, upper, alpha, beta);
}
return res;
}
I learnt that we use
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
std::default_random_engine generator (seed);
std::normal_distribution<double> distribution (mean_value,variance_value);
to generate real numbers. But I don't know how to give a range (min and max) to this generation and how to generate only integers in this scenario. In case of uniform_distribution, it is straight forward. Can anyone help please? Thanks!
Well, you could compute probabilities from normal distribution at given points, and use them for discrete sampling.
Along the lines
#include <cmath>
#include <random>
#include <iostream>
constexpr double PI = 3.14159265359;
static inline double squared(const double x) {
return x * x;
}
double GaussPDF(const double x,
const double mu,
const double sigma) {
return exp(-0.5 * squared((x - mu) / sigma)) / (sqrt(2.0 * PI) * sigma);
}
int SampleTruncIntGauss(const int xmin, const int xmax, const double mu, const double sigma, std::mt19937_64& rng) {
int n = xmax - xmin + 1;
std::vector<double> p(n);
for (int k = 0; k != n; ++k)
p[k] = GaussPDF(static_cast<double>(xmin) + k, mu, sigma);
std::discrete_distribution<int> igauss{ p.begin(), p.end() };
return xmin + igauss(rng);
}
int main() {
int xmin = -3;
int xmax = 5;
int n = xmax - xmin + 1;
double mu = 1.2;
double sigma = 2.3;
std::mt19937_64 rng{ 98761728941ULL };
std::vector<int> h(n, 0);
for (int k = 0; k != 10000; ++k) {
int v = SampleTruncIntGauss(xmin, xmax, mu, sigma, rng);
h[v - xmin] += 1;
}
int i = xmin;
for (auto k : h) {
std::cout << i << " " << k << '\n';
++i;
}
return 0;
}
You could make code more optimal, I reinitialize probabilities array each time we sample, but it demonstrates the gist of the idea.
UPDATE
You could also use non-point probabilities for sampling, basically assuming that probability at integer point x means probability to have value in the range [x-0.5...x+0.5]. This could be easily expressed via Gaussian CDF.
constexpr double INV_SQRT2 = 0.70710678118;
double GaussCDF(const double x,
const double mu,
const double sigma) {
double v = INV_SQRT2 * (x - mu) / sigma;
return 0.5 * (1.0 + erf(v));
}
double ProbCDF(const int x,
const double mu,
const double sigma) {
return GaussCDF(static_cast<double>(x) + 0.5, mu, sigma) - GaussCDF(static_cast<double>(x) - 0.5, mu, sigma);
}
and code for probabilities would be
for (int k = 0; k != n; ++k) {
p[k] = ProbCDF(xmin + k, mu, sigma);
Result is slightly different, but still resembles Gaussian
I am new to C++ and I am using the Eigen library. I was wondering if there was a way to sum certain elements in a vector. For example, say I have a vector that is a 100 by 1 and I just want to sum the first 10 elements. Is there a way of doing that using the Eigen library?
What I am trying to do is this: say I have a vector that is 1000 by 1 and I want to take the mean of the first 10 elements, then the next 10 elements, and so on and store that in some vector. Hence I will have a vector of size 100 of the averages. Any thoughts or suggestions are greatly appreciated.
Here is the beginning steps I have in my code. I have a S_temp4vector that is 1000 by 1. Now I intialize a new vector S_A that I want to have as the vector of the means. Here is my messy sloppy code so far: (Note that my question resides in the crudeMonteCarlo function)
#include <iostream>
#include <cmath>
#include <math.h>
#include <Eigen/Dense>
#include <Eigen/Geometry>
#include <random>
#include <time.h>
using namespace Eigen;
using namespace std;
void crudeMonteCarlo(int N,double K, double r, double S0, double sigma, double T, int n);
VectorXd time_vector(double min, double max, int n);
VectorXd call_payoff(VectorXd S, double K);
int main(){
int N = 100;
double K = 100;
double r = 0.2;
double S0 = 100;
double sigma = 0.4;
double T = 0.1;
int n = 10;
crudeMonteCarlo(N,K,r,S0,sigma,T,n);
return 0;
}
VectorXd time_vector(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 generateGaussianNoise(int M, int N){
MatrixXd Z(M,N);
static random_device rd;
static mt19937 e2(time(0));
normal_distribution<double> dist(0.0, 1.0);
for(int i = 0; i < M; i++){
for(int j = 0; j < N; j++){
Z(i,j) = dist(e2);
}
}
return Z;
}
VectorXd call_payoff(VectorXd S, double K){
VectorXd C(S.size());
for(int i = 0; i < S.size(); i++){
if(S(i) - K > 0){
C(i) = S(i) - K;
}else{
C(i) = 0.0;
}
}
return C;
}
void crudeMonteCarlo(int N,double K, double r, double S0, double sigma, double T, int n){
// Create time vector
VectorXd tt = time_vector(0.0,T,n);
VectorXd t(n);
double dt = T/n;
for(int i = 0; i < n; i++){
t(i) = tt(i+1);
}
// Generate standard normal Z matrix
//MatrixXd Z = generateGaussianNoise(N,n);
// Generate the log normal stock process N times to get S_A for crude Monte Carlo
MatrixXd SS(N,n+1);
MatrixXd Z = generateGaussianNoise(N,n);
for(int i = 0; i < N; i++){
SS(i,0) = S0;
for(int j = 1; j <= n; j++){
SS(i,j) = SS(i,j-1)*exp((double) (r - pow(sigma,2.0))*dt + sigma*sqrt(dt)*(double)Z(i,j-1));
}
}
// This long bit of code gives me my S_A.....
Map<RowVectorXd> S_temp1(SS.data(), SS.size());
VectorXd S_temp2(S_temp1.size());
for(int i = 0; i < S_temp2.size(); i++){
S_temp2(i) = S_temp1(i);
}
VectorXd S_temp3(S_temp2.size() - N);
int count = 0;
for(int i = N; i < S_temp2.size(); i++){
S_temp3(count) = S_temp2(i);
count++;
}
VectorXd S_temp4(S_temp3.size());
for(int i = 0; i < S_temp4.size(); i++){
S_temp4(i) = S_temp3(i);
}
VectorXd S_A(N);
S_A(0) = (S_temp4(0) + S_temp4(1) + S_temp4(2) + S_temp4(3) + S_temp4(4) + S_temp4(5) + S_temp4(6) + S_temp4(7) + S_temp4(8) + S_temp4(9))/(n);
S_A(1) = (S_temp4(10) + S_temp4(11) + S_temp4(12) + S_temp4(13) + S_temp4(14) + S_temp4(15) + S_temp4(16) + S_temp4(17) + S_temp4(18) + S_temp4(19))/(n);
int count1 = 0;
for(int i = 0; i < S_temp4.size(); i++){
S_A(count1) =
}
// Calculate payoff of Asian option
//VectorXd call_fun = call_payoff(S_A,K);
}
This question includes a lot of code, which makes it hard to understand the question you're trying to ask. Consider including only the code specific to your question.
In any case, you can use Eigen directly to do all of these things quite simply. In Eigen, Vectors are just matrices with 1 column, so all of the reasoning here is directly applicable to what you've written.
const Eigen::Matrix<double, 100, 1> v = Eigen::Matrix<double, 100, 1>::Random();
const int num_rows = 10;
const int num_cols = 1;
const int starting_row = 0;
const int starting_col = 0;
const double sum_of_first_ten = v.block(starting_row, starting_col, num_rows, num_cols).sum();
const double mean_of_first_ten = sum_of_first_ten / num_rows;
In summary: You can use .block to get a block object, .sum() to sum that block, and then conventional division to get the mean.
You can reshape the input using Map and then do all sub-summations at once without any loop:
VectorXd A(1000); // input
Map<MatrixXd> B(A.data(), 10, A.size()/10); // reshaped version, no copy
VectorXd res = B.colwise().mean(); // partial reduction, you can also use .sum(), .minCoeff(), etc.
The Eigen documentation at https://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html says an Eigen block is a rectangular part of a matrix or array accessed by matrix.block(i,j,p,q) where i and j are the starting values (eg 0 and 0) and p and q are the block size (eg 10 and 1). Presumably you would then iterate i in steps of 10, and use std::accumulate or perhaps an explicit summation to find the mean of matrix.block(i,0,10,1).
I've tried to implement Newton's method for polynomials. Like:
double xn=x0;
double gxn=g(w, n, xn);
int i=0;
while(abs(gxn)>e && i<100){
xn=xn-(gxn/dg(w, n, xn));
gxn=g(w, n, xn);
i++;
}
where g(w, n, xn) computes the value of the function and dg(w, n, xn) computes the derivative.
As x0 I use starting point M which I found using Sturm's theorem.
My problem is that this method is divergent for some polynomials like x^4+2x^3+2x^2+2x+1. Maybe it's not regular, but I noticed that it happens when the solution of the equation is a negative number. Where can I look for an explanation?
Edit:
dg
double result=0;
for(int i=0; i<n+1; i++)
result+=w[i]*(n-i)*pow(x, n-i-1);
where n is the degree of polynomial
I'm not sure why would you say it's divergent.
I implemented Newton's method similarly to yours:
double g(int w[], int n, double x) {
double result = 0;
for (int i = 0; i < n + 1; i++)
result += w[i] * pow(x, n - i);
return result;
}
double dg_dx(int w[], int n, double x) {
double result = 0;
for (int i = 0; i < n ; i++)
result += w[i] * (n - i) * pow(x, n - i - 1);
return result;
}
int main() {
double xn = 0; // Choose initial value. I chose 0.
double gx;
double dg_dx_x;
int w[] = { 1, 2, 2, 2, 1 };
int i = 0;
int n = 4;
do {
gx = g(w, n, xn);
dg_dx_x = dg_dx(w, n, xn);
xn = xn - (gx / dg_dx_x);
i++;
} while (abs(gx) > 10e-5 && i < 100);
std::cout << xn << '\n';
}
And it yields -0.997576, which is close to the solution -1.