Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
lgmconvolutionsolver2.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2020 Quaternion Risk Management Ltd
3 All rights reserved.
4
5 This file is part of ORE, a free-software/open-source library
6 for transparent pricing and risk analysis - http://opensourcerisk.org
7
8 ORE is free software: you can redistribute it and/or modify it
9 under the terms of the Modified BSD License. You should have received a
10 copy of the license along with this program.
11 The license is also available online at <http://opensourcerisk.org>
12
13 This program is distributed on the basis that it will form a useful
14 contribution to risk analytics and model standardisation, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
17*/
18
20
21#include <ql/math/distributions/normaldistribution.hpp>
22
23namespace QuantExt {
24
25LgmConvolutionSolver2::LgmConvolutionSolver2(const QuantLib::ext::shared_ptr<LinearGaussMarkovModel>& model, const Real sy,
26 const Size ny, const Real sx, const Size nx)
27 : model_(model), nx_(static_cast<int>(nx)) {
28
29 // precompute weights
30
31 // number of x, y grid points > 0
32 mx_ = static_cast<int>(floor(sx * static_cast<Real>(nx)) + 0.5);
33 my_ = static_cast<int>(floor(sy * static_cast<Real>(ny)) + 0.5);
34
35 // y-grid spacing
36 h_ = 1.0 / static_cast<Real>(ny);
37
38 // weights for convolution in the rollback step
39 CumulativeNormalDistribution N;
40 NormalDistribution G;
41
42 y_.resize(2 * my_ + 1); // x-coordinate / standard deviation of x
43 w_.resize(2 * my_ + 1); // probability weight around y-grid point i
44 for (int i = 0; i <= 2 * my_; i++) {
45 y_[i] = h_ * (i - my_);
46 if (i == 0 || i == 2 * my_)
47 w_[i] = (1. + y_[0] / h_) * N(y_[0] + h_) - y_[0] / h_ * N(y_[0]) + (G(y_[0] + h_) - G(y_[0])) / h_;
48 else
49 w_[i] = (1. + y_[i] / h_) * N(y_[i] + h_) - 2. * y_[i] / h_ * N(y_[i]) -
50 (1. - y_[i] / h_) * N(y_[i] - h_) // opposite sign in the paper
51 + (G(y_[i] + h_) - 2. * G(y_[i]) + G(y_[i] - h_)) / h_;
52 // w_[i] might be negative due to numerical errors
53 if (w_[i] < 0.0) {
54 QL_REQUIRE(w_[i] > -1.0E-10, "LgmConvolutionSolver: negative w (" << w_[i] << ") at i=" << i);
55 w_[i] = 0.0;
56 }
57 }
58}
59
61 if (QuantLib::close_enough(t, 0.0))
62 return RandomVariable(2 * mx_ + 1, 0.0);
63 RandomVariable x(2 * mx_ + 1);
64 Real dx = std::sqrt(model_->parametrization()->zeta(t)) / static_cast<Real>(nx_);
65 for (int k = 0; k <= 2 * mx_; ++k) {
66 x.set(k, dx * (k - mx_));
67 }
68 return x;
69}
70
71RandomVariable LgmConvolutionSolver2::rollback(const RandomVariable& v, const Real t1, const Real t0, Size) const {
72 if (QuantLib::close_enough(t0, t1) || v.deterministic())
73 return v;
74 QL_REQUIRE(t0 < t1, "LgmConvolutionSolver2::rollback(): t0 (" << t0 << ") < t1 (" << t1 << ") required.");
75 Real sigma = std::sqrt(model_->parametrization()->zeta(t1));
76 Real dx = sigma / static_cast<Real>(nx_);
77 if (QuantLib::close_enough(t0, 0.0)) {
78 // rollback from t1 to t0 = 0
79 Real value = 0.0;
80 for (int i = 0; i <= 2 * my_; i++) {
81 // Map y index to x index, not integer in general
82 Real kp = y_[i] * sigma / dx + mx_;
83 // Adjacent integer x index <= k
84 int kk = int(floor(kp));
85 // Get value at kp by linear interpolation on
86 // kk <= kp <= kk + 1 with flat extrapolation
87 value +=
88 w_[i] *
89 (kk < 0 ? v[0] : (kk + 1 > 2 * mx_ ? v[2 * mx_] : (kp - kk) * v[kk + 1] + (1.0 + kk - kp) * v[kk]));
90 }
91 return RandomVariable(2 * mx_ + 1, value);
92 } else {
93 RandomVariable value(2 * mx_ + 1, 0.0);
94 value.expand();
95 // rollback from t1 to t0 > 0
96 Real std = std::sqrt(model_->parametrization()->zeta(t1) - model_->parametrization()->zeta(t0));
97 Real dx2 = std::sqrt(model_->parametrization()->zeta(t0)) / static_cast<Real>(nx_);
98 for (int k = 0; k <= 2 * mx_; k++) {
99 for (int i = 0; i <= 2 * my_; i++) {
100 // Map y index to x index, not integer in generalTo
101 Real kp = (dx2 * (k - mx_) + y_[i] * std) / dx + mx_;
102 // Adjacent integer x index <= k
103 int kk = int(floor(kp));
104 // Get value at kp by linear interpolation on
105 // kk <= kp <= kk + 1 with flat extrapolation
106 value.set(k, value[k] + w_[i] * (kk < 0 ? v[0]
107 : (kk + 1 > 2 * mx_
108 ? v[2 * mx_]
109 : (kp - kk) * v[kk + 1] + (1.0 + kk - kp) * v[kk])));
110 }
111 }
112 return value;
113 }
114}
115
116} // namespace QuantExt
RandomVariable rollback(const RandomVariable &v, const Real t1, const Real t0, Size steps=Null< Size >()) const override
RandomVariable stateGrid(const Real t) const override
QuantLib::ext::shared_ptr< LinearGaussMarkovModel > model_
LgmConvolutionSolver2(const QuantLib::ext::shared_ptr< LinearGaussMarkovModel > &model, const Real sy, const Size ny, const Real sx, const Size nx)
numeric convolution solver for the LGM model using RandoMVariable
JY INF index sigma component.
void set(const Size i, const Real v)