/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 | | } |