Coverage Report

Created: 2025-08-11 06:28

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