Coverage Report

Created: 2025-09-04 07:11

/src/quantlib/ql/math/interpolations/mixedinterpolation.hpp
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) 2010 Ferdinando Ametrano
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 mixedinterpolation.hpp
21
    \brief mixed interpolation between discrete points
22
*/
23
24
#ifndef quantlib_mixed_interpolation_hpp
25
#define quantlib_mixed_interpolation_hpp
26
27
#include <ql/math/interpolations/linearinterpolation.hpp>
28
#include <ql/math/interpolations/cubicinterpolation.hpp>
29
#include <ql/utilities/dataformatters.hpp>
30
31
namespace QuantLib {
32
33
    namespace detail {
34
35
        template<class I1, class I2, class Ia, class Ib>
36
        class MixedInterpolationImpl;
37
38
    }
39
40
41
    struct MixedInterpolation {
42
        enum Behavior {
43
            ShareRanges,  /*!< Define both interpolations over the
44
                               whole range defined by the passed
45
                               iterators. This is the default
46
                               behavior. */
47
            SplitRanges   /*!< Define the first interpolation over the
48
                               first part of the range, and the second
49
                               interpolation over the second part. */
50
        };
51
    };
52
53
    //! mixed linear/cubic interpolation between discrete points
54
    /*! \ingroup interpolations
55
        \warning See the Interpolation class for information about the
56
                 required lifetime of the underlying data.
57
    */
58
    class MixedLinearCubicInterpolation : public Interpolation {
59
      public:
60
        /*! \pre the \f$ x \f$ values must be sorted. */
61
        template <class I1, class I2>
62
        MixedLinearCubicInterpolation(const I1& xBegin, const I1& xEnd,
63
                                      const I2& yBegin, Size n,
64
                                      MixedInterpolation::Behavior behavior,
65
                                      CubicInterpolation::DerivativeApprox da,
66
                                      bool monotonic,
67
                                      CubicInterpolation::BoundaryCondition leftC,
68
                                      Real leftConditionValue,
69
                                      CubicInterpolation::BoundaryCondition rightC,
70
                                      Real rightConditionValue) {
71
            impl_ = ext::shared_ptr<Interpolation::Impl>(new
72
                detail::MixedInterpolationImpl<I1, I2, Linear, Cubic>(
73
                    xBegin, xEnd, yBegin, n, behavior,
74
                    Linear(),
75
                    Cubic(da, monotonic,
76
                          leftC, leftConditionValue,
77
                          rightC, rightConditionValue)));
78
            impl_->update();
79
        }
80
    };
81
82
    //! mixed linear/cubic interpolation factory and traits
83
    /*! \ingroup interpolations */
84
    class MixedLinearCubic {
85
      public:
86
        MixedLinearCubic(Size n,
87
                         MixedInterpolation::Behavior behavior,
88
                         CubicInterpolation::DerivativeApprox da,
89
                         bool monotonic = true,
90
                         CubicInterpolation::BoundaryCondition leftCondition
91
                             = CubicInterpolation::SecondDerivative,
92
                         Real leftConditionValue = 0.0,
93
                         CubicInterpolation::BoundaryCondition rightCondition
94
                             = CubicInterpolation::SecondDerivative,
95
                         Real rightConditionValue = 0.0)
96
        : n_(n), behavior_(behavior), da_(da), monotonic_(monotonic),
97
          leftType_(leftCondition), rightType_(rightCondition),
98
0
          leftValue_(leftConditionValue), rightValue_(rightConditionValue) {}
99
        template <class I1, class I2>
100
        Interpolation interpolate(const I1& xBegin, const I1& xEnd,
101
                                  const I2& yBegin) const {
102
            return MixedLinearCubicInterpolation(xBegin, xEnd,
103
                                                 yBegin, n_, behavior_,
104
                                                 da_, monotonic_,
105
                                                 leftType_, leftValue_,
106
                                                 rightType_, rightValue_);
107
        }
108
        // fix below
109
        static const bool global = true;
110
        static const Size requiredPoints = 3;
111
      private:
112
        Size n_;
113
        MixedInterpolation::Behavior behavior_;
114
        CubicInterpolation::DerivativeApprox da_;
115
        bool monotonic_;
116
        CubicInterpolation::BoundaryCondition leftType_, rightType_;
117
        Real leftValue_, rightValue_;
118
    };
119
120
    // convenience classes
121
122
    class MixedLinearCubicNaturalSpline : public MixedLinearCubicInterpolation {
123
      public:
124
        /*! \pre the \f$ x \f$ values must be sorted. */
125
        template <class I1, class I2>
126
        MixedLinearCubicNaturalSpline(const I1& xBegin, const I1& xEnd,
127
                                      const I2& yBegin, Size n,
128
                                      MixedInterpolation::Behavior behavior
129
                                            = MixedInterpolation::ShareRanges)
130
        : MixedLinearCubicInterpolation(xBegin, xEnd, yBegin, n, behavior,
131
                                        CubicInterpolation::Spline, false,
132
                                        CubicInterpolation::SecondDerivative, 0.0,
133
                                        CubicInterpolation::SecondDerivative, 0.0) {}
134
    };
135
136
    class MixedLinearMonotonicCubicNaturalSpline : public MixedLinearCubicInterpolation {
137
      public:
138
        /*! \pre the \f$ x \f$ values must be sorted. */
139
        template <class I1, class I2>
140
        MixedLinearMonotonicCubicNaturalSpline(const I1& xBegin, const I1& xEnd,
141
                                               const I2& yBegin, Size n,
142
                                               MixedInterpolation::Behavior behavior
143
                                                   = MixedInterpolation::ShareRanges)
144
        : MixedLinearCubicInterpolation(xBegin, xEnd, yBegin, n, behavior,
145
                                        CubicInterpolation::Spline, true,
146
                                        CubicInterpolation::SecondDerivative, 0.0,
147
                                        CubicInterpolation::SecondDerivative, 0.0) {}
148
    };
149
150
    class MixedLinearKrugerCubic : public MixedLinearCubicInterpolation {
151
      public:
152
        /*! \pre the \f$ x \f$ values must be sorted. */
153
        template <class I1, class I2>
154
        MixedLinearKrugerCubic(const I1& xBegin, const I1& xEnd,
155
                               const I2& yBegin, Size n,
156
                               MixedInterpolation::Behavior behavior
157
                                            = MixedInterpolation::ShareRanges)
158
        : MixedLinearCubicInterpolation(xBegin, xEnd, yBegin, n, behavior,
159
                                        CubicInterpolation::Kruger, false,
160
                                        CubicInterpolation::SecondDerivative, 0.0,
161
                                        CubicInterpolation::SecondDerivative, 0.0) {}
162
    };
163
164
    class MixedLinearFritschButlandCubic : public MixedLinearCubicInterpolation {
165
      public:
166
        /*! \pre the \f$ x \f$ values must be sorted. */
167
        template <class I1, class I2>
168
        MixedLinearFritschButlandCubic(const I1& xBegin, const I1& xEnd,
169
                                       const I2& yBegin, Size n,
170
                                       MixedInterpolation::Behavior behavior
171
                                            = MixedInterpolation::ShareRanges)
172
        : MixedLinearCubicInterpolation(xBegin, xEnd, yBegin, n, behavior,
173
                                        CubicInterpolation::FritschButland, false,
174
                                        CubicInterpolation::SecondDerivative, 0.0,
175
                                        CubicInterpolation::SecondDerivative, 0.0) {}
176
    };
177
178
    class MixedLinearParabolic : public MixedLinearCubicInterpolation {
179
      public:
180
        /*! \pre the \f$ x \f$ values must be sorted. */
181
        template <class I1, class I2>
182
        MixedLinearParabolic(const I1& xBegin, const I1& xEnd,
183
                             const I2& yBegin, Size n,
184
                             MixedInterpolation::Behavior behavior
185
                                            = MixedInterpolation::ShareRanges)
186
        : MixedLinearCubicInterpolation(xBegin, xEnd, yBegin, n, behavior,
187
                                        CubicInterpolation::Parabolic, false,
188
                                        CubicInterpolation::SecondDerivative, 0.0,
189
                                        CubicInterpolation::SecondDerivative, 0.0) {}
190
    };
191
192
    class MixedLinearMonotonicParabolic : public MixedLinearCubicInterpolation {
193
      public:
194
        /*! \pre the \f$ x \f$ values must be sorted. */
195
        template <class I1, class I2>
196
        MixedLinearMonotonicParabolic(const I1& xBegin, const I1& xEnd,
197
                                      const I2& yBegin, Size n,
198
                                      MixedInterpolation::Behavior behavior
199
                                            = MixedInterpolation::ShareRanges)
200
        : MixedLinearCubicInterpolation(xBegin, xEnd, yBegin, n, behavior,
201
                                        CubicInterpolation::Parabolic, true,
202
                                        CubicInterpolation::SecondDerivative, 0.0,
203
                                        CubicInterpolation::SecondDerivative, 0.0) {}
204
    };
205
206
    namespace detail {
207
208
        template <class I1, class I2, class Interpolator1, class Interpolator2>
209
        class MixedInterpolationImpl
210
            : public Interpolation::templateImpl<I1,I2> {
211
          public:
212
            MixedInterpolationImpl(const I1& xBegin, const I1& xEnd,
213
                                   const I2& yBegin, Size n,
214
                                   MixedInterpolation::Behavior behavior
215
                                            = MixedInterpolation::ShareRanges,
216
                                   const Interpolator1& factory1 = Interpolator1(),
217
                                   const Interpolator2& factory2 = Interpolator2())
218
            : Interpolation::templateImpl<I1,I2>(
219
                               xBegin, xEnd, yBegin,
220
                               std::max(Size(Interpolator1::requiredPoints),
221
                                        Size(Interpolator2::requiredPoints))),
222
              n_(n) {
223
224
                xBegin2_ = this->xBegin_ + n_;
225
                yBegin2_ = this->yBegin_ + n_;
226
227
                QL_REQUIRE(xBegin2_<this->xEnd_,
228
                           "too large n (" << n << ") for " <<
229
                           this->xEnd_-this->xBegin_ << "-element x sequence");
230
231
                switch (behavior) {
232
                  case MixedInterpolation::ShareRanges:
233
                    interpolation1_ = factory1.interpolate(this->xBegin_,
234
                                                           this->xEnd_,
235
                                                           this->yBegin_);
236
                    interpolation2_ = factory2.interpolate(this->xBegin_,
237
                                                           this->xEnd_,
238
                                                           this->yBegin_);
239
                    break;
240
                  case MixedInterpolation::SplitRanges:
241
                    interpolation1_ = factory1.interpolate(this->xBegin_,
242
                                                           this->xBegin2_+1,
243
                                                           this->yBegin_);
244
                    interpolation2_ = factory2.interpolate(this->xBegin2_,
245
                                                           this->xEnd_,
246
                                                           this->yBegin2_);
247
                    break;
248
                  default:
249
                    QL_FAIL("unknown mixed-interpolation behavior: " << behavior);
250
                }
251
            }
252
253
            void update() {
254
                interpolation1_.update();
255
                interpolation2_.update();
256
            }
257
            Real value(Real x) const {
258
                if (x<*(this->xBegin2_))
259
                    return interpolation1_(x, true);
260
                return interpolation2_(x, true);
261
            }
262
            Real primitive(Real x) const {
263
                if (x<*(this->xBegin2_))
264
                    return interpolation1_.primitive(x, true);
265
                return interpolation2_.primitive(x, true) -
266
                    interpolation2_.primitive(*xBegin2_, true) +
267
                    interpolation1_.primitive(*xBegin2_, true);
268
            }
269
            Real derivative(Real x) const {
270
                if (x<*(this->xBegin2_))
271
                    return interpolation1_.derivative(x, true);
272
                return interpolation2_.derivative(x, true);
273
            }
274
            Real secondDerivative(Real x) const {
275
                if (x<*(this->xBegin2_))
276
                    return interpolation1_.secondDerivative(x, true);
277
                return interpolation2_.secondDerivative(x, true);
278
            }
279
            Size switchIndex() { return n_; }
280
          private:
281
            I1 xBegin2_;
282
            I2 yBegin2_;
283
            Size n_;
284
            Interpolation interpolation1_, interpolation2_;
285
        };
286
287
    }
288
289
}
290
291
#endif