/src/quantlib/ql/math/integrals/gausslobattointegral.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) 2008 Klaus Spanderen |
5 | | |
6 | | This file is part of QuantLib, a free-software/open-source library |
7 | | for financial quantitative analysts and developers - http://quantlib.org/ |
8 | | |
9 | | QuantLib is free software: you can redistribute it and/or modify it |
10 | | under the terms of the QuantLib license. You should have received a |
11 | | copy of the license along with this program; if not, please email |
12 | | <quantlib-dev@lists.sf.net>. The license is also available online at |
13 | | <http://quantlib.org/license.shtml>. |
14 | | |
15 | | This program is distributed in the hope that it will be useful, but WITHOUT |
16 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
17 | | FOR A PARTICULAR PURPOSE. See the license for more details. |
18 | | */ |
19 | | |
20 | | /*! \file gausslabottointegral.cpp |
21 | | \brief integral of a one-dimensional function using the adaptive |
22 | | Gauss-Lobatto integral |
23 | | */ |
24 | | |
25 | | #include <ql/math/integrals/gausslobattointegral.hpp> |
26 | | #include <algorithm> |
27 | | |
28 | | namespace QuantLib { |
29 | | |
30 | | const Real GaussLobattoIntegral::alpha_ = std::sqrt(2.0/3.0); |
31 | | const Real GaussLobattoIntegral::beta_ = 1.0/std::sqrt(5.0); |
32 | | const Real GaussLobattoIntegral::x1_ = 0.94288241569547971906; |
33 | | const Real GaussLobattoIntegral::x2_ = 0.64185334234578130578; |
34 | | const Real GaussLobattoIntegral::x3_ = 0.23638319966214988028; |
35 | | |
36 | | GaussLobattoIntegral::GaussLobattoIntegral(Size maxIterations, |
37 | | Real absAccuracy, |
38 | | Real relAccuracy, |
39 | | bool useConvergenceEstimate) |
40 | 0 | : Integrator(absAccuracy, maxIterations), |
41 | 0 | relAccuracy_(relAccuracy), |
42 | 0 | useConvergenceEstimate_(useConvergenceEstimate) { |
43 | 0 | } |
44 | | |
45 | | Real GaussLobattoIntegral::integrate( |
46 | | const std::function<Real (Real)>& f, |
47 | 0 | Real a, Real b) const { |
48 | |
|
49 | 0 | setNumberOfEvaluations(0); |
50 | 0 | const Real calcAbsTolerance = calculateAbsTolerance(f, a, b); |
51 | |
|
52 | 0 | increaseNumberOfEvaluations(2); |
53 | 0 | return adaptivGaussLobattoStep(f, a, b, f(a), f(b), calcAbsTolerance); |
54 | 0 | } |
55 | | |
56 | | Real GaussLobattoIntegral::calculateAbsTolerance( |
57 | | const std::function<Real (Real)>& f, |
58 | 0 | Real a, Real b) const { |
59 | | |
60 | |
|
61 | 0 | Real relTol = std::max(relAccuracy_, QL_EPSILON); |
62 | | |
63 | 0 | const Real m = (a+b)/2; |
64 | 0 | const Real h = (b-a)/2; |
65 | 0 | const Real y1 = f(a); |
66 | 0 | const Real y3 = f(m-alpha_*h); |
67 | 0 | const Real y5 = f(m-beta_*h); |
68 | 0 | const Real y7 = f(m); |
69 | 0 | const Real y9 = f(m+beta_*h); |
70 | 0 | const Real y11= f(m+alpha_*h); |
71 | 0 | const Real y13= f(b); |
72 | |
|
73 | 0 | const Real f1 = f(m-x1_*h); |
74 | 0 | const Real f2 = f(m+x1_*h); |
75 | 0 | const Real f3 = f(m-x2_*h); |
76 | 0 | const Real f4 = f(m+x2_*h); |
77 | 0 | const Real f5 = f(m-x3_*h); |
78 | 0 | const Real f6 = f(m+x3_*h); |
79 | |
|
80 | 0 | Real acc=h*(0.0158271919734801831*(y1+y13) |
81 | 0 | +0.0942738402188500455*(f1+f2) |
82 | 0 | +0.1550719873365853963*(y3+y11) |
83 | 0 | +0.1888215739601824544*(f3+f4) |
84 | 0 | +0.1997734052268585268*(y5+y9) |
85 | 0 | +0.2249264653333395270*(f5+f6) |
86 | 0 | +0.2426110719014077338*y7); |
87 | | |
88 | 0 | increaseNumberOfEvaluations(13); |
89 | 0 | if (acc == 0.0 && ( f1 != 0.0 || f2 != 0.0 || f3 != 0.0 |
90 | 0 | || f4 != 0.0 || f5 != 0.0 || f6 != 0.0)) { |
91 | 0 | QL_FAIL("can not calculate absolute accuracy " |
92 | 0 | "from relative accuracy"); |
93 | 0 | } |
94 | | |
95 | 0 | Real r = 1.0; |
96 | 0 | if (useConvergenceEstimate_) { |
97 | 0 | const Real integral2 = (h/6)*(y1+y13+5*(y5+y9)); |
98 | 0 | const Real integral1 = (h/1470)*(77*(y1+y13)+432*(y3+y11)+ |
99 | 0 | 625*(y5+y9)+672*y7); |
100 | | |
101 | 0 | if (std::fabs(integral2-acc) != 0.0) |
102 | 0 | r = std::fabs(integral1-acc)/std::fabs(integral2-acc); |
103 | 0 | if (r == 0.0 || r > 1.0) |
104 | 0 | r = 1.0; |
105 | 0 | } |
106 | |
|
107 | 0 | if (relAccuracy_ != Null<Real>()) |
108 | 0 | return std::min(absoluteAccuracy(), acc*relTol)/(r*QL_EPSILON); |
109 | 0 | else { |
110 | 0 | return absoluteAccuracy()/(r*QL_EPSILON); |
111 | 0 | } |
112 | 0 | } |
113 | | |
114 | | Real GaussLobattoIntegral::adaptivGaussLobattoStep( |
115 | | const std::function<Real (Real)>& f, |
116 | | Real a, Real b, Real fa, Real fb, |
117 | 0 | Real acc) const { |
118 | 0 | QL_REQUIRE(numberOfEvaluations() < maxEvaluations(), |
119 | 0 | "max number of iterations reached"); |
120 | | |
121 | 0 | const Real h=(b-a)/2; |
122 | 0 | const Real m=(a+b)/2; |
123 | | |
124 | 0 | const Real mll=m-alpha_*h; |
125 | 0 | const Real ml =m-beta_*h; |
126 | 0 | const Real mr =m+beta_*h; |
127 | 0 | const Real mrr=m+alpha_*h; |
128 | | |
129 | 0 | const Real fmll= f(mll); |
130 | 0 | const Real fml = f(ml); |
131 | 0 | const Real fm = f(m); |
132 | 0 | const Real fmr = f(mr); |
133 | 0 | const Real fmrr= f(mrr); |
134 | 0 | increaseNumberOfEvaluations(5); |
135 | | |
136 | 0 | const Real integral2=(h/6)*(fa+fb+5*(fml+fmr)); |
137 | 0 | const Real integral1=(h/1470)*(77*(fa+fb) |
138 | 0 | +432*(fmll+fmrr)+625*(fml+fmr)+672*fm); |
139 | | |
140 | | // avoid 80 bit logic on x86 cpu |
141 | 0 | const Real dist = acc + (integral1-integral2); |
142 | 0 | if(dist==acc || mll<=a || b<=mrr) { |
143 | 0 | QL_REQUIRE(m>a && b>m,"Interval contains no more machine number"); |
144 | 0 | return integral1; |
145 | 0 | } |
146 | 0 | else { |
147 | 0 | return adaptivGaussLobattoStep(f,a,mll,fa,fmll,acc) |
148 | 0 | + adaptivGaussLobattoStep(f,mll,ml,fmll,fml,acc) |
149 | 0 | + adaptivGaussLobattoStep(f,ml,m,fml,fm,acc) |
150 | 0 | + adaptivGaussLobattoStep(f,m,mr,fm,fmr,acc) |
151 | 0 | + adaptivGaussLobattoStep(f,mr,mrr,fmr,fmrr,acc) |
152 | 0 | + adaptivGaussLobattoStep(f,mrr,b,fmrr,fb,acc); |
153 | 0 | } |
154 | 0 | } |
155 | | } |