Coverage Report

Created: 2026-03-11 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/math/interpolation.hpp
Line
Count
Source
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2002, 2003 Ferdinando Ametrano
5
 Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl
6
 Copyright (C) 2003, 2004, 2005, 2006 StatPro Italia srl
7
8
 This file is part of QuantLib, a free-software/open-source library
9
 for financial quantitative analysts and developers - http://quantlib.org/
10
11
 QuantLib is free software: you can redistribute it and/or modify it
12
 under the terms of the QuantLib license.  You should have received a
13
 copy of the license along with this program; if not, please email
14
 <quantlib-dev@lists.sf.net>. The license is also available online at
15
 <https://www.quantlib.org/license.shtml>.
16
17
 This program is distributed in the hope that it will be useful, but WITHOUT
18
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19
 FOR A PARTICULAR PURPOSE.  See the license for more details.
20
*/
21
22
/*! \file interpolation.hpp
23
    \brief base class for 1-D interpolations
24
*/
25
26
#ifndef quantlib_interpolation_hpp
27
#define quantlib_interpolation_hpp
28
29
#include <ql/math/interpolations/extrapolation.hpp>
30
#include <ql/math/comparison.hpp>
31
#include <ql/errors.hpp>
32
#include <vector>
33
#include <algorithm>
34
35
namespace QuantLib {
36
37
    //! base class for 1-D interpolations.
38
    /*! Classes derived from this class will provide interpolated
39
        values from two sequences of equal length, representing
40
        discretized values of a variable and a function of the former,
41
        respectively.
42
43
        \warning Interpolations don't copy their underlying data;
44
                 instead, they store iterators through which they
45
                 access them.  This allow them to see changes in the
46
                 underlying data without having to propagate them
47
                 manually, but adds the requirement that the lifetime
48
                 of the underlying data exceeds or equals the lifetime
49
                 of the interpolation. It is up to the user to ensure
50
                 this: usually, a class will store as data members
51
                 both the data and the interpolation (see, e.g., the
52
                 InterpolatedCurve class) and call the update() method
53
                 on the latter when the data change.
54
    */
55
    class Interpolation : public Extrapolator {
56
      protected:
57
        //! abstract base class for interpolation implementations
58
        class Impl {
59
          public:
60
0
            virtual ~Impl() = default;
61
            virtual void update() = 0;
62
            virtual Real xMin() const = 0;
63
            virtual Real xMax() const = 0;
64
            virtual std::vector<Real> xValues() const = 0;
65
            virtual std::vector<Real> yValues() const = 0;
66
            virtual bool isInRange(Real) const = 0;
67
            virtual Real value(Real) const = 0;
68
            virtual Real primitive(Real) const = 0;
69
            virtual Real derivative(Real) const = 0;
70
            virtual Real secondDerivative(Real) const = 0;
71
        };
72
        ext::shared_ptr<Impl> impl_;
73
      public:
74
        //! basic template implementation
75
        template <class I1, class I2>
76
        class templateImpl : public Impl {
77
          public:
78
            templateImpl(const I1& xBegin, const I1& xEnd, const I2& yBegin,
79
                         const int requiredPoints = 2)
80
0
            : xBegin_(xBegin), xEnd_(xEnd), yBegin_(yBegin) {
81
0
                QL_REQUIRE(static_cast<std::ptrdiff_t>(xEnd_-xBegin_) >= requiredPoints,
82
0
                           "not enough points to interpolate: at least " <<
83
0
                           requiredPoints <<
84
0
                           " required, " << static_cast<std::ptrdiff_t>(xEnd_-xBegin_)<< " provided");
85
0
            }
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*> >::templateImpl(std::__1::__wrap_iter<double*> const&, std::__1::__wrap_iter<double*> const&, std::__1::__wrap_iter<double*> const&, int)
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, double const*>::templateImpl(std::__1::__wrap_iter<double*> const&, std::__1::__wrap_iter<double*> const&, double const* const&, int)
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, double*>::templateImpl(std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double const*> const&, double* const&, int)
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double const*> >::templateImpl(std::__1::__wrap_iter<double*> const&, std::__1::__wrap_iter<double*> const&, std::__1::__wrap_iter<double const*> const&, int)
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double*> >::templateImpl(std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double*> const&, int)
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*> >::templateImpl(std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double const*> const&, int)
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, double const*>::templateImpl(std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double const*> const&, double const* const&, int)
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, QuantLib::step_iterator<double*> >::templateImpl(std::__1::__wrap_iter<double*> const&, std::__1::__wrap_iter<double*> const&, QuantLib::step_iterator<double*> const&, int)
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double const*, double const*>::templateImpl(double const* const&, double const* const&, double const* const&, int)
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double*, double*>::templateImpl(double* const&, double* const&, double* const&, int)
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double const*, double*>::templateImpl(double const* const&, double const* const&, double* const&, int)
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double*, double const*>::templateImpl(double* const&, double* const&, double const* const&, int)
86
0
            Real xMin() const override { return *xBegin_; }
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*> >::xMin() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, double const*>::xMin() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, double*>::xMin() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double const*, double const*>::xMin() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double*, double*>::xMin() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double const*> >::xMin() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double*> >::xMin() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*> >::xMin() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, double const*>::xMin() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double const*, double*>::xMin() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, QuantLib::step_iterator<double*> >::xMin() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double*, double const*>::xMin() const
87
0
            Real xMax() const override { return *(xEnd_ - 1); }
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*> >::xMax() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, double const*>::xMax() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, double*>::xMax() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double const*, double const*>::xMax() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double*, double*>::xMax() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double const*> >::xMax() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double*> >::xMax() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*> >::xMax() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, double const*>::xMax() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double const*, double*>::xMax() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, QuantLib::step_iterator<double*> >::xMax() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double*, double const*>::xMax() const
88
0
            std::vector<Real> xValues() const override { return std::vector<Real>(xBegin_, xEnd_); }
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*> >::xValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, double const*>::xValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, double*>::xValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double const*, double const*>::xValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double*, double*>::xValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double const*> >::xValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double*> >::xValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*> >::xValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, double const*>::xValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double const*, double*>::xValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, QuantLib::step_iterator<double*> >::xValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double*, double const*>::xValues() const
89
0
            std::vector<Real> yValues() const override {
90
0
                return std::vector<Real>(yBegin_,yBegin_+(xEnd_-xBegin_));
91
0
            }
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*> >::yValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, double const*>::yValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, double*>::yValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double const*, double const*>::yValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double*, double*>::yValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double const*> >::yValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double*> >::yValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*> >::yValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, double const*>::yValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double const*, double*>::yValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, QuantLib::step_iterator<double*> >::yValues() const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double*, double const*>::yValues() const
92
0
            bool isInRange(Real x) const override {
93
#if defined(QL_EXTRA_SAFETY_CHECKS)
94
                for (I1 i=xBegin_, j=xBegin_+1; j!=xEnd_; ++i, ++j)
95
                    QL_REQUIRE(*j > *i, "unsorted x values");
96
                #endif
97
0
                Real x1 = xMin(), x2 = xMax();
98
0
                return (x >= x1 && x <= x2) || close(x,x1) || close(x,x2);
99
0
            }
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*> >::isInRange(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, double const*>::isInRange(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, double*>::isInRange(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double const*, double const*>::isInRange(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double*, double*>::isInRange(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double const*> >::isInRange(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double*> >::isInRange(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*> >::isInRange(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, double const*>::isInRange(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double const*, double*>::isInRange(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, QuantLib::step_iterator<double*> >::isInRange(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double*, double const*>::isInRange(double) const
100
101
          protected:
102
0
            Size locate(Real x) const {
103
                #if defined(QL_EXTRA_SAFETY_CHECKS)
104
                for (I1 i=xBegin_, j=xBegin_+1; j!=xEnd_; ++i, ++j)
105
                    QL_REQUIRE(*j > *i, "unsorted x values");
106
                #endif
107
0
                if (x < *xBegin_)
108
0
                    return 0;
109
0
                else if (x > *(xEnd_-1))
110
0
                    return xEnd_-xBegin_-2;
111
0
                else
112
0
                    return std::upper_bound(xBegin_,xEnd_-1,x)-xBegin_-1;
113
0
            }
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*> >::locate(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, double const*>::locate(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, double*>::locate(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double const*> >::locate(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double*> >::locate(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double*, double*>::locate(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*> >::locate(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double const*>, double const*>::locate(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double const*, double*>::locate(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<std::__1::__wrap_iter<double*>, QuantLib::step_iterator<double*> >::locate(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double const*, double const*>::locate(double) const
Unexecuted instantiation: QuantLib::Interpolation::templateImpl<double*, double const*>::locate(double) const
114
            I1 xBegin_, xEnd_;
115
            I2 yBegin_;
116
        };
117
118
0
        Interpolation() = default;
119
0
        bool empty() const { return !impl_; }
120
0
        Real operator()(Real x, bool allowExtrapolation = false) const {
121
0
            checkRange(x,allowExtrapolation);
122
0
            return impl_->value(x);
123
0
        }
124
0
        Real primitive(Real x, bool allowExtrapolation = false) const {
125
0
            checkRange(x,allowExtrapolation);
126
0
            return impl_->primitive(x);
127
0
        }
128
0
        Real derivative(Real x, bool allowExtrapolation = false) const {
129
0
            checkRange(x,allowExtrapolation);
130
0
            return impl_->derivative(x);
131
0
        }
132
0
        Real secondDerivative(Real x, bool allowExtrapolation = false) const {
133
0
            checkRange(x,allowExtrapolation);
134
0
            return impl_->secondDerivative(x);
135
0
        }
136
0
        Real xMin() const {
137
0
            return impl_->xMin();
138
0
        }
139
0
        Real xMax() const {
140
0
            return impl_->xMax();
141
0
        }
142
0
        bool isInRange(Real x) const {
143
0
            return impl_->isInRange(x);
144
0
        }
145
0
        void update() {
146
0
            impl_->update();
147
0
        }
148
      protected:
149
0
        void checkRange(Real x, bool extrapolate) const {
150
            QL_REQUIRE(extrapolate || allowsExtrapolation() ||
151
0
                       impl_->isInRange(x),
152
0
                       "interpolation range is ["
153
0
                       << impl_->xMin() << ", " << impl_->xMax()
154
0
                       << "]: extrapolation at " << x << " not allowed");
155
0
        }
156
        friend class MixedLinearCubicInterpolation;
157
    };
158
159
}
160
161
#endif