Logo
Fully annotated reference manual - version 1.8.12
Loading...
Searching...
No Matches
randomvariablelsmbasissystem.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2019 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/integrals/gaussianquadratures.hpp>
22
23#include <boost/math/special_functions/binomial.hpp>
24
25#include <numeric>
26#include <set>
27
28namespace QuantExt {
29
30namespace {
31
32// makes typing a little easier
33typedef std::vector<std::function<RandomVariable(const RandomVariable&)>> VF_R;
34typedef std::vector<std::function<RandomVariable(const std::vector<const RandomVariable*>&)>> VF_A;
35typedef std::vector<std::vector<Size>> VV;
36
37// pow(x, order)
38class MonomialFct {
39public:
40 explicit MonomialFct(Size order) : order_(order) {}
41 inline RandomVariable operator()(const RandomVariable& x) const { return compute(x, order_); }
42
43private:
44 inline RandomVariable compute(const RandomVariable& x, Size order) const {
45 switch (order) {
46 case 0:
47 return RandomVariable(x.size(), 1.0);
48 case 1:
49 return x;
50 case 2:
51 return x * x;
52 case 3:
53 return x * x * x;
54 case 4: {
55 auto y = x * x;
56 return y * y;
57 }
58 case 5: {
59 auto y = x * x;
60 return y * y * x;
61 }
62 case 6: {
63 auto y = x * x;
64 return y * y * y;
65 }
66 case 7: {
67 auto y = x * x;
68 return y * y * y * x;
69 }
70 case 8: {
71 auto y = x * x;
72 y *= y;
73 return y * y;
74 }
75 default: {
76 Size m = order / 2, r = order % 2;
77 auto y = compute(x, m);
78 if (r > 0)
79 return y * y * x;
80 else
81 return y * y;
82 }
83 }
84 }
85 const Size order_;
86};
87
88/* multiplies [RV -> RV] functors
89 to create [Vec<RV> -> RV] functor */
90class MultiDimFct {
91public:
92 explicit MultiDimFct(const VF_R& b) : b_(b) { QL_REQUIRE(b_.size() > 0, "zero size basis"); }
93 inline RandomVariable operator()(const std::vector<const RandomVariable*>& a) const {
94#if defined(QL_EXTRA_SAFETY_CHECKS)
95 QL_REQUIRE(b_.size() == a.size(), "wrong argument size");
96#endif
97 RandomVariable ret = b_[0](*a[0]);
98 for (Size i = 1; i < b_.size(); ++i)
99 ret *= b_[i](*a[i]);
100 return ret;
101 }
102
103private:
104 const VF_R b_;
105};
106
107// check size and order of tuples
108void check_tuples(const VV& v, Size dim, Size order) {
109 for (Size i = 0; i < v.size(); ++i) {
110 QL_REQUIRE(dim == v[i].size(), "wrong tuple size");
111 QL_REQUIRE(order == std::accumulate(v[i].begin(), v[i].end(), 0u), "wrong tuple order");
112 }
113}
114
115// build order N+1 tuples from order N tuples
116VV next_order_tuples(const VV& v) {
117 const Size order = std::accumulate(v[0].begin(), v[0].end(), 0u);
118 const Size dim = v[0].size();
119
120 check_tuples(v, dim, order);
121
122 // the set of unique tuples
123 std::set<std::vector<Size>> tuples;
124 std::vector<Size> x;
125 for (Size i = 0; i < dim; ++i) {
126 // increase i-th value in every tuple by 1
127 for (Size j = 0; j < v.size(); ++j) {
128 x = v[j];
129 x[i] += 1;
130 tuples.insert(x);
131 }
132 }
133
134 VV ret(tuples.begin(), tuples.end());
135 return ret;
136}
137} // namespace
138
139// LsmBasisSystem static methods
140
141VF_R RandomVariableLsmBasisSystem::pathBasisSystem(Size order, QuantLib::LsmBasisSystem::PolynomialType type) {
142 VF_R ret(order + 1);
143 for (Size i = 0; i <= order; ++i) {
144 switch (type) {
145 case QuantLib::LsmBasisSystem::Monomial:
146 ret[i] = MonomialFct(i);
147 break;
148 case QuantLib::LsmBasisSystem::Laguerre: {
149 GaussLaguerrePolynomial p;
150 ret[i] = [=](RandomVariable x) {
151 for (std::size_t i = 0; i < x.size(); ++i) {
152 x.set(i, p.weightedValue(i, x[i]));
153 }
154 return x;
155 };
156 } break;
157 case QuantLib::LsmBasisSystem::Hermite: {
158 GaussHermitePolynomial p;
159 ret[i] = [=](RandomVariable x) {
160 for (std::size_t i = 0; i < x.size(); ++i) {
161 x.set(i, p.weightedValue(i, x[i]));
162 }
163 return x;
164 };
165 } break;
166 case QuantLib::LsmBasisSystem::Hyperbolic: {
167 GaussHyperbolicPolynomial p;
168 ret[i] = [=](RandomVariable x) {
169 for (std::size_t i = 0; i < x.size(); ++i) {
170 x.set(i, p.weightedValue(i, x[i]));
171 }
172 return x;
173 };
174 } break;
175 case QuantLib::LsmBasisSystem::Legendre: {
176 GaussLegendrePolynomial p;
177 ret[i] = [=](RandomVariable x) {
178 for (std::size_t i = 0; i < x.size(); ++i) {
179 x.set(i, p.weightedValue(i, x[i]));
180 }
181 return x;
182 };
183 } break;
184 case QuantLib::LsmBasisSystem::Chebyshev: {
185 GaussChebyshevPolynomial p;
186 ret[i] = [=](RandomVariable x) {
187 for (std::size_t i = 0; i < x.size(); ++i) {
188 x.set(i, p.weightedValue(i, x[i]));
189 }
190 return x;
191 };
192 } break;
193 case QuantLib::LsmBasisSystem::Chebyshev2nd: {
194 GaussChebyshev2ndPolynomial p;
195 ret[i] = [=](RandomVariable x) {
196 for (std::size_t i = 0; i < x.size(); ++i) {
197 x.set(i, p.weightedValue(i, x[i]));
198 }
199 return x;
200 };
201 } break;
202 default:
203 QL_FAIL("unknown regression type");
204 }
205 }
206 return ret;
207}
208
210 QuantLib::LsmBasisSystem::PolynomialType type) {
211 QL_REQUIRE(dim > 0, "zero dimension");
212 // get single factor basis
213 VF_R pathBasis = pathBasisSystem(order, type);
214 VF_A ret;
215 // 0-th order term
216 VF_R term(dim, pathBasis[0]);
217 ret.push_back(MultiDimFct(term));
218 // start with all 0 tuple
219 VV tuples(1, std::vector<Size>(dim));
220 // add multi-factor terms
221 for (Size i = 1; i <= order; ++i) {
222 tuples = next_order_tuples(tuples);
223 // now we have all tuples of order i
224 // for each tuple add the corresponding term
225 for (Size j = 0; j < tuples.size(); ++j) {
226 for (Size k = 0; k < dim; ++k)
227 term[k] = pathBasis[tuples[j][k]];
228 ret.push_back(MultiDimFct(term));
229 }
230 }
231 return ret;
232}
233
234Real RandomVariableLsmBasisSystem::size(Size dim, Size order) {
235 // see e.g. proposition 3 in https://murphmath.wordpress.com/2012/08/22/counting-monomials/
236 return boost::math::binomial_coefficient<Real>(
237 dim + order, order,
238 boost::math::policies::make_policy(
239 boost::math::policies::overflow_error<boost::math::policies::ignore_error>()));
240}
241
242} // namespace QuantExt
static std::vector< std::function< RandomVariable(const RandomVariable &)> > pathBasisSystem(Size order, QuantLib::LsmBasisSystem::PolynomialType type)
static std::vector< std::function< RandomVariable(const std::vector< const RandomVariable * > &)> > multiPathBasisSystem(Size dim, Size order, QuantLib::LsmBasisSystem::PolynomialType type)
const Size order_
ql utility class for random variables