Coverage Report

Created: 2025-08-11 06:28

/src/quantlib/ql/math/integrals/gaussianquadratures.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2005 Klaus Spanderen
5
 Copyright (C) 2005 Gary Kennedy
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
 <http://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 gaussianquadratures.hpp
22
    \brief Integral of a 1-dimensional function using the Gauss quadratures
23
*/
24
25
#include <ql/utilities/null.hpp>
26
#include <ql/math/integrals/gaussianquadratures.hpp>
27
#include <ql/math/matrixutilities/tqreigendecomposition.hpp>
28
#include <ql/math/matrixutilities/symmetricschurdecomposition.hpp>
29
30
#include <map>
31
32
namespace QuantLib {
33
34
    GaussianQuadrature::GaussianQuadrature(
35
                                Size n,
36
                                const GaussianOrthogonalPolynomial& orthPoly)
37
0
    : x_(n), w_(n) {
38
39
        // set-up matrix to compute the roots and the weights
40
0
        Array e(n-1);
41
42
0
        Size i;
43
0
        for (i=1; i < n; ++i) {
44
0
            x_[i] = orthPoly.alpha(i);
45
0
            e[i-1] = std::sqrt(orthPoly.beta(i));
46
0
        }
47
0
        x_[0] = orthPoly.alpha(0);
48
49
0
        TqrEigenDecomposition tqr(
50
0
                               x_, e,
51
0
                               TqrEigenDecomposition::OnlyFirstRowEigenVector,
52
0
                               TqrEigenDecomposition::Overrelaxation);
53
54
0
        x_ = tqr.eigenvalues();
55
0
        const Matrix& ev = tqr.eigenvectors();
56
57
0
        Real mu_0 = orthPoly.mu_0();
58
0
        for (i=0; i<n; ++i) {
59
0
            w_[i] = mu_0*ev[0][i]*ev[0][i] / orthPoly.w(x_[i]);
60
0
        }
61
0
    }
62
63
64
    MultiDimGaussianIntegration::MultiDimGaussianIntegration(
65
        const std::vector<Size>& ns,
66
        const std::function<ext::shared_ptr<GaussianQuadrature>(Size)>& genQuad)
67
0
    : weights_(std::accumulate(ns.begin(), ns.end(), Size(1), std::multiplies<>()), 1.0),
68
0
      x_(weights_.size(), Array(ns.size())) {
69
70
0
        const Size m = ns.size();
71
0
        const Size n = x_.size();
72
73
0
        std::vector<Size> spacing(m);
74
0
        spacing[0] = 1;
75
0
        std::partial_sum(ns.begin(), ns.end()-1, spacing.begin()+1, std::multiplies<>());
76
77
0
        std::map<Size, Array> n2weights, n2x;
78
0
        for (auto order: ns) {
79
0
            if (n2x.find(order) == n2x.end()) {
80
0
                const ext::shared_ptr<GaussianQuadrature> quad = genQuad(order);
81
0
                n2x[order] = quad->x();
82
0
                n2weights[order] = quad->weights();
83
0
            }
84
0
        }
85
86
0
        for (Size i=0; i < n; ++i) {
87
0
            for (Size j=0; j < m; ++j) {
88
0
                const Size order = ns[j];
89
0
                const Size nx = (i / spacing[j]) % ns[j];
90
0
                weights_[i] *= n2weights[order][nx];
91
0
                x_[i][j] = n2x[order][nx];
92
0
            }
93
0
        }
94
0
    }
95
96
    Real MultiDimGaussianIntegration::operator()(
97
0
        const std::function<Real(Array)>& f) const {
98
0
        Real s = 0.0;
99
0
        const Size n = x_.size();
100
0
        for (Size i=0; i < n; ++i)
101
0
            s += weights_[i]*f(x_[i]);
102
103
0
        return s;
104
0
    }
105
106
107
108
    namespace detail {
109
        template <class Integration>
110
        GaussianQuadratureIntegrator<Integration>::GaussianQuadratureIntegrator(
111
            Size n)
112
0
        : Integrator(Null<Real>(), n),
113
0
          integration_(ext::make_shared<Integration>(n))
114
0
         {  }
Unexecuted instantiation: QuantLib::detail::GaussianQuadratureIntegrator<QuantLib::GaussLegendreIntegration>::GaussianQuadratureIntegrator(unsigned long)
Unexecuted instantiation: QuantLib::detail::GaussianQuadratureIntegrator<QuantLib::GaussChebyshevIntegration>::GaussianQuadratureIntegrator(unsigned long)
Unexecuted instantiation: QuantLib::detail::GaussianQuadratureIntegrator<QuantLib::GaussChebyshev2ndIntegration>::GaussianQuadratureIntegrator(unsigned long)
115
116
        template <class Integration>
117
        Real GaussianQuadratureIntegrator<Integration>::integrate(
118
0
            const std::function<Real (Real)>& f, Real a, Real b) const {
119
120
0
            const Real c1 = 0.5*(b-a);
121
0
            const Real c2 = 0.5*(a+b);
122
123
0
            return c1*integration_->operator()(
124
0
                [c1, c2, f](Real x) { return f(c1*x+c2);});
Unexecuted instantiation: QuantLib::detail::GaussianQuadratureIntegrator<QuantLib::GaussLegendreIntegration>::integrate(std::__1::function<double (double)> const&, double, double) const::{lambda(double)#1}::operator()(double) const
Unexecuted instantiation: QuantLib::detail::GaussianQuadratureIntegrator<QuantLib::GaussChebyshevIntegration>::integrate(std::__1::function<double (double)> const&, double, double) const::{lambda(double)#1}::operator()(double) const
Unexecuted instantiation: QuantLib::detail::GaussianQuadratureIntegrator<QuantLib::GaussChebyshev2ndIntegration>::integrate(std::__1::function<double (double)> const&, double, double) const::{lambda(double)#1}::operator()(double) const
125
0
        }
Unexecuted instantiation: QuantLib::detail::GaussianQuadratureIntegrator<QuantLib::GaussLegendreIntegration>::integrate(std::__1::function<double (double)> const&, double, double) const
Unexecuted instantiation: QuantLib::detail::GaussianQuadratureIntegrator<QuantLib::GaussChebyshevIntegration>::integrate(std::__1::function<double (double)> const&, double, double) const
Unexecuted instantiation: QuantLib::detail::GaussianQuadratureIntegrator<QuantLib::GaussChebyshev2ndIntegration>::integrate(std::__1::function<double (double)> const&, double, double) const
126
127
        template class GaussianQuadratureIntegrator<GaussLegendreIntegration>;
128
        template class GaussianQuadratureIntegrator<GaussChebyshevIntegration>;
129
        template class GaussianQuadratureIntegrator<GaussChebyshev2ndIntegration>;
130
    }
131
132
0
    void TabulatedGaussLegendre::order(Size order) {
133
0
        switch(order) {
134
0
          case(6):
135
0
            order_=order; x_=x6; w_=w6; n_=n6;
136
0
            break;
137
0
          case(7):
138
0
            order_=order; x_=x7; w_=w7; n_=n7;
139
0
            break;
140
0
          case(12):
141
0
            order_=order; x_=x12; w_=w12; n_=n12;
142
0
            break;
143
0
          case(20):
144
0
            order_=order; x_=x20; w_=w20; n_=n20;
145
0
            break;
146
0
          default:
147
0
            QL_FAIL("order " << order << " not supported");
148
0
        }
149
0
    }
150
151
152
    // Abscissas and Weights from Abramowitz and Stegun
153
154
    /* order 6 */
155
    const Real TabulatedGaussLegendre::x6[3] = { 0.238619186083197,
156
                                                 0.661209386466265,
157
                                                 0.932469514203152 };
158
159
    const Real TabulatedGaussLegendre::w6[3] = { 0.467913934572691,
160
                                                 0.360761573048139,
161
                                                 0.171324492379170 };
162
163
    const Size TabulatedGaussLegendre::n6 = 3;
164
165
    /* order 7 */
166
    const Real TabulatedGaussLegendre::x7[4] = { 0.000000000000000,
167
                                                 0.405845151377397,
168
                                                 0.741531185599394,
169
                                                 0.949107912342759 };
170
171
    const Real TabulatedGaussLegendre::w7[4] = { 0.417959183673469,
172
                                                 0.381830050505119,
173
                                                 0.279705391489277,
174
                                                 0.129484966168870 };
175
176
    const Size TabulatedGaussLegendre::n7 = 4;
177
178
    /* order 12 */
179
    const Real TabulatedGaussLegendre::x12[6] = { 0.125233408511469,
180
                                                  0.367831498998180,
181
                                                  0.587317954286617,
182
                                                  0.769902674194305,
183
                                                  0.904117256370475,
184
                                                  0.981560634246719 };
185
186
    const Real TabulatedGaussLegendre::w12[6] = { 0.249147045813403,
187
                                                  0.233492536538355,
188
                                                  0.203167426723066,
189
                                                  0.160078328543346,
190
                                                  0.106939325995318,
191
                                                  0.047175336386512 };
192
193
    const Size TabulatedGaussLegendre::n12 = 6;
194
195
    /* order 20 */
196
    const Real TabulatedGaussLegendre::x20[10] = { 0.076526521133497,
197
                                                   0.227785851141645,
198
                                                   0.373706088715420,
199
                                                   0.510867001950827,
200
                                                   0.636053680726515,
201
                                                   0.746331906460151,
202
                                                   0.839116971822219,
203
                                                   0.912234428251326,
204
                                                   0.963971927277914,
205
                                                   0.993128599185095 };
206
207
    const Real TabulatedGaussLegendre::w20[10] = { 0.152753387130726,
208
                                                   0.149172986472604,
209
                                                   0.142096109318382,
210
                                                   0.131688638449177,
211
                                                   0.118194531961518,
212
                                                   0.101930119817240,
213
                                                   0.083276741576704,
214
                                                   0.062672048334109,
215
                                                   0.040601429800387,
216
                                                   0.017614007139152 };
217
218
    const Size TabulatedGaussLegendre::n20 = 10;
219
220
}