Coverage Report

Created: 2025-10-14 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/math/solvers1d/newtonsafe.hpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl
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
 <https://www.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 newtonsafe.hpp
21
    \brief Safe (bracketed) Newton 1-D solver
22
*/
23
24
#ifndef quantlib_solver1d_newtonsafe_h
25
#define quantlib_solver1d_newtonsafe_h
26
27
#include <ql/math/solver1d.hpp>
28
29
namespace QuantLib {
30
31
    //! safe %Newton 1-D solver
32
    /*! \note This solver requires that the passed function object
33
              implement a method <tt>Real derivative(Real)</tt>.
34
35
        \test the correctness of the returned values is tested by
36
              checking them against known good results.
37
38
        \ingroup solvers
39
    */
40
    class NewtonSafe : public Solver1D<NewtonSafe> {
41
      public:
42
        template <class F>
43
        Real solveImpl(const F& f,
44
0
                       Real xAccuracy) const {
45
46
            /* The implementation of the algorithm was inspired by
47
               Press, Teukolsky, Vetterling, and Flannery,
48
               "Numerical Recipes in C", 2nd edition,
49
               Cambridge University Press
50
            */
51
52
0
            Real froot, dfroot, dx, dxold;
53
0
            Real xh, xl;
54
55
            // Orient the search so that f(xl) < 0
56
0
            if (fxMin_ < 0.0) {
57
0
                xl = xMin_;
58
0
                xh = xMax_;
59
0
            } else {
60
0
                xh = xMin_;
61
0
                xl = xMax_;
62
0
            }
63
64
            // the "stepsize before last"
65
0
            dxold = xMax_-xMin_;
66
            // it was dxold=std::fabs(xMax_-xMin_); in Numerical Recipes
67
            // here (xMax_-xMin_ > 0) is verified in the constructor
68
69
            // and the last step
70
0
            dx = dxold;
71
72
0
            froot = f(root_);
73
0
            dfroot = f.derivative(root_);
74
0
            QL_REQUIRE(dfroot != Null<Real>(),
75
0
                       "NewtonSafe requires function's derivative");
76
0
            ++evaluationNumber_;
77
78
0
            while (evaluationNumber_<=maxEvaluations_) {
79
                // Bisect if (out of range || not decreasing fast enough)
80
0
                if ((((root_-xh)*dfroot-froot)*
81
0
                     ((root_-xl)*dfroot-froot) > 0.0)
82
0
                    || (std::fabs(2.0*froot) > std::fabs(dxold*dfroot))) {
83
84
0
                    dxold = dx;
85
0
                    dx = (xh-xl)/2.0;
86
0
                    root_=xl+dx;
87
0
                } else {
88
0
                    dxold = dx;
89
0
                    dx = froot/dfroot;
90
0
                    root_ -= dx;
91
0
                }
92
                // Convergence criterion
93
0
                if (std::fabs(dx) < xAccuracy) {
94
0
                    f(root_);
95
0
                    ++evaluationNumber_;
96
0
                    return root_;
97
0
                }
98
0
                froot = f(root_);
99
0
                dfroot = f.derivative(root_);
100
0
                ++evaluationNumber_;
101
0
                if (froot < 0.0)
102
0
                    xl=root_;
103
0
                else
104
0
                    xh=root_;
105
0
            }
106
107
0
            QL_FAIL("maximum number of function evaluations ("
108
0
                    << maxEvaluations_ << ") exceeded");
109
0
        }
Unexecuted instantiation: double QuantLib::NewtonSafe::solveImpl<QuantLib::CashFlows::IrrFinder>(QuantLib::CashFlows::IrrFinder const&, double) const
Unexecuted instantiation: double QuantLib::NewtonSafe::solveImpl<QuantLib::GFunctionFactory::GFunctionWithShifts::ObjectiveFunction>(QuantLib::GFunctionFactory::GFunctionWithShifts::ObjectiveFunction const&, double) const
Unexecuted instantiation: irregularswaption.cpp:double QuantLib::NewtonSafe::solveImpl<QuantLib::(anonymous namespace)::IrregularImpliedVolHelper>(QuantLib::(anonymous namespace)::IrregularImpliedVolHelper const&, double) const
Unexecuted instantiation: capfloor.cpp:double QuantLib::NewtonSafe::solveImpl<QuantLib::(anonymous namespace)::ImpliedCapVolHelper>(QuantLib::(anonymous namespace)::ImpliedCapVolHelper const&, double) const
Unexecuted instantiation: swaption.cpp:double QuantLib::NewtonSafe::solveImpl<QuantLib::(anonymous namespace)::ImpliedSwaptionVolHelper>(QuantLib::(anonymous namespace)::ImpliedSwaptionVolHelper const&, double) const
Unexecuted instantiation: double QuantLib::NewtonSafe::solveImpl<QuantLib::detail::SumExponentialsRootSolver>(QuantLib::detail::SumExponentialsRootSolver const&, double) const
Unexecuted instantiation: double QuantLib::NewtonSafe::solveImpl<QuantLib::BlackImpliedStdDevHelper>(QuantLib::BlackImpliedStdDevHelper const&, double) const
Unexecuted instantiation: double QuantLib::NewtonSafe::solveImpl<QuantLib::QdPlusBoundaryEvaluator>(QuantLib::QdPlusBoundaryEvaluator const&, double) const
Unexecuted instantiation: double QuantLib::NewtonSafe::solveImpl<QuantLib::Gaussian1dSwaptionVolatility::DateHelper>(QuantLib::Gaussian1dSwaptionVolatility::DateHelper const&, double) const
110
    };
111
112
}
113
114
#endif