Coverage Report

Created: 2026-06-23 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/methods/montecarlo/lsmbasissystem.cpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2006 Klaus Spanderen
5
 Copyright (C) 2010 Kakhkhor Abdijalilov
6
 
7
 This file is part of QuantLib, a free-software/open-source library
8
 for financial quantitative analysts and developers - http://quantlib.org/
9
10
 QuantLib is free software: you can redistribute it and/or modify it
11
 under the terms of the QuantLib license.  You should have received a
12
 copy of the license along with this program; if not, please email
13
 <quantlib-dev@lists.sf.net>. The license is also available online at
14
 <https://www.quantlib.org/license.shtml>.
15
16
 This program is distributed in the hope that it will be useful, but WITHOUT
17
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
 FOR A PARTICULAR PURPOSE.  See the license for more details.
19
*/
20
21
/*! \file lsmbasissystem.cpp
22
    \brief utility classes for longstaff schwartz early exercise Monte Carlo
23
*/
24
25
#include <ql/math/integrals/gaussianquadratures.hpp>
26
#include <ql/methods/montecarlo/lsmbasissystem.hpp>
27
#include <numeric>
28
#include <set>
29
#include <utility>
30
31
namespace QuantLib {
32
33
    namespace {
34
35
        // makes typing a little easier
36
        typedef std::vector<std::function<Real(Real)> > VF_R;
37
        typedef std::vector<std::function<Real(Array)> > VF_A;
38
        typedef std::vector<std::vector<Size> > VV;
39
40
        // pow(x, order)
41
        class MonomialFct {
42
          public:
43
0
            explicit MonomialFct(Size order): order_(order) {}
44
0
            Real operator()(const Real x) const {
45
0
                Real ret = 1.0;
46
0
                for(Size i=0; i<order_; ++i)
47
0
                    ret *= x;
48
0
                return ret;
49
0
            }
50
          private:
51
            const Size order_;
52
        };
53
54
        /* multiplies [Real -> Real] functors
55
           to create [Array -> Real] functor */
56
        class MultiDimFct {
57
          public:
58
0
            explicit MultiDimFct(VF_R b) : b_(std::move(b)) {
59
0
                QL_REQUIRE(!b_.empty(), "zero size basis");
60
0
            }
61
0
            Real operator()(const Array& a) const {
62
                #if defined(QL_EXTRA_SAFETY_CHECKS)
63
                QL_REQUIRE(b_.size()==a.size(), "wrong argument size");
64
                #endif
65
0
                Real ret = b_[0](a[0]);
66
0
                for(Size i=1; i<b_.size(); ++i)
67
0
                    ret *= b_[i](a[i]);
68
0
                return ret;
69
0
            }
70
          private:
71
            const VF_R b_;
72
        };
73
74
        // check size and order of tuples
75
0
        void check_tuples(const VV& v, Size dim, Size order) {
76
0
            for (const auto& i : v) {
77
0
                QL_REQUIRE(dim == i.size(), "wrong tuple size");
78
0
                QL_REQUIRE(order == std::accumulate(i.begin(), i.end(), 0UL), "wrong tuple order");
79
0
            }
80
0
        }
81
82
        // build order N+1 tuples from order N tuples
83
0
        VV next_order_tuples(const VV& v) {
84
0
            const Size order = std::accumulate(v[0].begin(), v[0].end(), 0UL);
85
0
            const Size dim = v[0].size();
86
87
0
            check_tuples(v, dim, order);
88
89
            // the set of unique tuples
90
0
            std::set<std::vector<Size> > tuples;
91
0
            std::vector<Size> x;
92
0
            for(Size i=0; i<dim; ++i) {
93
                // increase i-th value in every tuple by 1
94
0
                for (const auto& j : v) {
95
0
                    x = j;
96
0
                    x[i] += 1;
97
0
                    tuples.insert(x);
98
0
                }
99
0
            }
100
101
0
            VV ret(tuples.begin(), tuples.end());
102
0
            return ret;
103
0
        }
104
105
    } 
106
107
    // LsmBasisSystem static methods
108
109
0
    VF_R LsmBasisSystem::pathBasisSystem(Size order, PolynomialType type) {
110
0
        VF_R ret(order+1);
111
0
        for (Size i=0; i<=order; ++i) {
112
0
            switch (type) {
113
0
              case Monomial:
114
0
                ret[i] = MonomialFct(i);
115
0
                break;
116
0
              case Laguerre:
117
0
                {
118
0
                  GaussLaguerrePolynomial p;
119
0
                  ret[i] = [=](Real x){ return p.weightedValue(i, x); };
120
0
                }
121
0
                break;
122
0
              case Hermite:
123
0
                {
124
0
                  GaussHermitePolynomial p;
125
0
                  ret[i] = [=](Real x){ return p.weightedValue(i, x); };
126
0
                }
127
0
                break;
128
0
              case Hyperbolic:
129
0
                {
130
0
                  GaussHyperbolicPolynomial p;
131
0
                  ret[i] = [=](Real x){ return p.weightedValue(i, x); };
132
0
                }
133
0
                break;
134
0
              case Legendre:
135
0
                {
136
0
                  GaussLegendrePolynomial p;
137
0
                  ret[i] = [=](Real x){ return p.weightedValue(i, x); };
138
0
                }
139
0
                break;
140
0
              case Chebyshev:
141
0
                {
142
0
                  GaussChebyshevPolynomial p;
143
0
                  ret[i] = [=](Real x){ return p.weightedValue(i, x); };
144
0
                }
145
0
                break;
146
0
              case Chebyshev2nd:
147
0
                {
148
0
                  GaussChebyshev2ndPolynomial p;
149
0
                  ret[i] = [=](Real x){ return p.weightedValue(i, x); };
150
0
                }
151
0
                break;
152
0
              default:
153
0
                QL_FAIL("unknown regression type");
154
0
            }
155
0
        }
156
0
        return ret;
157
0
    }
158
159
    VF_A LsmBasisSystem::multiPathBasisSystem(Size dim, Size order,
160
0
                                              PolynomialType type) {
161
0
        QL_REQUIRE(dim>0, "zero dimension");
162
        // get single factor basis
163
0
        VF_R pathBasis = pathBasisSystem(order, type);
164
0
        VF_A ret;
165
        // 0-th order term
166
0
        VF_R term(dim, pathBasis[0]);
167
0
        ret.emplace_back(MultiDimFct(term));
168
        // start with all 0 tuple
169
0
        VV tuples(1, std::vector<Size>(dim));
170
        // add multi-factor terms
171
0
        for(Size i=1; i<=order; ++i) {
172
0
            tuples = next_order_tuples(tuples);
173
            // now we have all tuples of order i
174
            // for each tuple add the corresponding term
175
0
            for (auto& tuple : tuples) {
176
0
                for(Size k=0; k<dim; ++k)
177
0
                    term[k] = pathBasis[tuple[k]];
178
0
                ret.emplace_back(MultiDimFct(term));
179
0
            }
180
0
        }
181
0
        return ret;
182
0
    }
183
184
}