Coverage Report

Created: 2026-08-14 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/math/interpolations/loginterpolation.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, 2008, 2009 Ferdinando Ametrano
5
 Copyright (C) 2004, 2007, 2008 StatPro Italia srl
6
7
 This file is part of QuantLib, a free-software/open-source library
8
 for financial quantitative analysts and developers - http://quantlib.org/
9
10
 QuantLib is free software: you can redistribute it and/or modify it
11
 under the terms of the QuantLib license.  You should have received a
12
 copy of the license along with this program; if not, please email
13
 <quantlib-dev@lists.sf.net>. The license is also available online at
14
 <https://www.quantlib.org/license.shtml>.
15
16
 This program is distributed in the hope that it will be useful, but WITHOUT
17
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18
 FOR A PARTICULAR PURPOSE.  See the license for more details.
19
*/
20
21
/*! \file loginterpolation.hpp
22
    \brief log-linear and log-cubic interpolation between discrete points
23
*/
24
25
#ifndef quantlib_log_interpolation_hpp
26
#define quantlib_log_interpolation_hpp
27
28
#include <ql/math/interpolations/linearinterpolation.hpp>
29
#include <ql/math/interpolations/cubicinterpolation.hpp>
30
#include <ql/math/interpolations/mixedinterpolation.hpp>
31
#include <ql/utilities/dataformatters.hpp>
32
33
namespace QuantLib {
34
35
    namespace detail {
36
        template <class I1, class I2> class LogInterpolationImpl;
37
    }
38
39
    //! %log-linear interpolation between discrete points
40
    /*! \ingroup interpolations
41
        \warning See the Interpolation class for information about the
42
                 required lifetime of the underlying data.
43
    */
44
    class LogLinearInterpolation : public Interpolation {
45
      public:
46
        /*! \pre the \f$ x \f$ values must be sorted. */
47
        template <class I1, class I2>
48
        LogLinearInterpolation(const I1& xBegin, const I1& xEnd,
49
52
                               const I2& yBegin, bool update = true) {
50
52
            impl_ = ext::make_shared<detail::LogInterpolationImpl<I1, I2>>(
51
52
                xBegin, xEnd, yBegin, Linear());
52
52
            if (update)
53
52
                impl_->update();
54
52
        }
55
    };
56
57
    //! log-linear interpolation factory and traits
58
    /*! \ingroup interpolations */
59
    class LogLinear {
60
      public:
61
        template <class I1, class I2>
62
        Interpolation interpolate(const I1& xBegin, const I1& xEnd,
63
                                  const I2& yBegin, bool update = true) const {
64
            return LogLinearInterpolation(xBegin, xEnd, yBegin, update);
65
        }
66
        static const bool global = false;
67
        static const Size requiredPoints = 2;
68
    };
69
70
    //! %log-cubic interpolation between discrete points
71
    /*! \ingroup interpolations */
72
    class LogCubicInterpolation : public Interpolation {
73
      public:
74
        /*! \pre the \f$ x \f$ values must be sorted. */
75
        template <class I1, class I2>
76
        LogCubicInterpolation(const I1& xBegin, const I1& xEnd,
77
                              const I2& yBegin,
78
                              CubicInterpolation::DerivativeApprox da,
79
                              bool monotonic,
80
                              CubicInterpolation::BoundaryCondition leftC,
81
                              Real leftConditionValue,
82
                              CubicInterpolation::BoundaryCondition rightC,
83
                              Real rightConditionValue,
84
                              bool update = true) {
85
            impl_ = ext::make_shared<detail::LogInterpolationImpl<I1, I2>>(
86
                xBegin, xEnd, yBegin,
87
                Cubic(da, monotonic,
88
                      leftC, leftConditionValue,
89
                      rightC, rightConditionValue));
90
            if (update)
91
                impl_->update();
92
        }
93
    };
94
95
    //! log-cubic interpolation factory and traits
96
    /*! \ingroup interpolations */
97
    class LogCubic {
98
      public:
99
        LogCubic(CubicInterpolation::DerivativeApprox da,
100
                  bool monotonic = true,
101
                  CubicInterpolation::BoundaryCondition leftCondition
102
                      = CubicInterpolation::SecondDerivative,
103
                  Real leftConditionValue = 0.0,
104
                  CubicInterpolation::BoundaryCondition rightCondition
105
                      = CubicInterpolation::SecondDerivative,
106
                  Real rightConditionValue = 0.0)
107
        : da_(da), monotonic_(monotonic),
108
          leftType_(leftCondition), rightType_(rightCondition),
109
0
          leftValue_(leftConditionValue), rightValue_(rightConditionValue) {}
110
        template <class I1, class I2>
111
        Interpolation interpolate(const I1& xBegin, const I1& xEnd,
112
                                  const I2& yBegin, bool update = true) const {
113
            return LogCubicInterpolation(xBegin, xEnd, yBegin,
114
                                         da_, monotonic_,
115
                                         leftType_, leftValue_,
116
                                         rightType_, rightValue_, update);
117
        }
118
        static const bool global = true;
119
        static const Size requiredPoints = 2;
120
      private:
121
        CubicInterpolation::DerivativeApprox da_;
122
        bool monotonic_;
123
        CubicInterpolation::BoundaryCondition leftType_, rightType_;
124
        Real leftValue_, rightValue_;
125
    };
126
127
    // convenience classes
128
129
    /*! \deprecated Use KrugerLog instead.
130
                    Deprecated in version 1.42.
131
    */
132
    class [[deprecated("Use KrugerLog instead")]] DefaultLogCubic : public LogCubic {
133
      public:
134
        DefaultLogCubic()
135
0
        : LogCubic(CubicInterpolation::Kruger) {}
136
    };
137
138
    class MonotonicLogCubic : public LogCubic {
139
      public:
140
        MonotonicLogCubic()
141
        : LogCubic(CubicInterpolation::Spline, true,
142
                   CubicInterpolation::SecondDerivative, 0.0,
143
0
                   CubicInterpolation::SecondDerivative, 0.0) {}
144
    };
145
146
    class KrugerLog : public LogCubic {
147
      public:
148
        KrugerLog()
149
        : LogCubic(CubicInterpolation::Kruger, false,
150
                   CubicInterpolation::SecondDerivative, 0.0,
151
0
                   CubicInterpolation::SecondDerivative, 0.0) {}
152
    };
153
154
155
    class LogCubicNaturalSpline : public LogCubicInterpolation {
156
      public:
157
        /*! \pre the \f$ x \f$ values must be sorted. */
158
        template <class I1, class I2>
159
        LogCubicNaturalSpline(const I1& xBegin,
160
                              const I1& xEnd,
161
                              const I2& yBegin)
162
        : LogCubicInterpolation(xBegin, xEnd, yBegin,
163
                                CubicInterpolation::Spline, false,
164
                                CubicInterpolation::SecondDerivative, 0.0,
165
                                CubicInterpolation::SecondDerivative, 0.0) {}
166
    };
167
168
    class MonotonicLogCubicNaturalSpline : public LogCubicInterpolation {
169
      public:
170
        /*! \pre the \f$ x \f$ values must be sorted. */
171
        template <class I1, class I2>
172
        MonotonicLogCubicNaturalSpline(const I1& xBegin,
173
                                       const I1& xEnd,
174
                                       const I2& yBegin)
175
        : LogCubicInterpolation(xBegin, xEnd, yBegin,
176
                                CubicInterpolation::Spline, true,
177
                                CubicInterpolation::SecondDerivative, 0.0,
178
                                CubicInterpolation::SecondDerivative, 0.0) {}
179
    };
180
181
    class KrugerLogCubic : public LogCubicInterpolation {
182
      public:
183
        /*! \pre the \f$ x \f$ values must be sorted. */
184
        template <class I1, class I2>
185
        KrugerLogCubic(const I1& xBegin,
186
                       const I1& xEnd,
187
                       const I2& yBegin)
188
        : LogCubicInterpolation(xBegin, xEnd, yBegin,
189
                                CubicInterpolation::Kruger, false,
190
                                CubicInterpolation::SecondDerivative, 0.0,
191
                                CubicInterpolation::SecondDerivative, 0.0) {}
192
    };
193
194
    class HarmonicLogCubic : public LogCubicInterpolation {
195
      public:
196
        /*! \pre the \f$ x \f$ values must be sorted. */
197
        template <class I1, class I2>
198
        HarmonicLogCubic(const I1& xBegin,
199
                         const I1& xEnd,
200
                         const I2& yBegin)
201
        : LogCubicInterpolation(xBegin, xEnd, yBegin,
202
                                CubicInterpolation::Harmonic, false,
203
                                CubicInterpolation::SecondDerivative, 0.0,
204
                                CubicInterpolation::SecondDerivative, 0.0) {}
205
    };
206
207
    class FritschButlandLogCubic : public LogCubicInterpolation {
208
      public:
209
        /*! \pre the \f$ x \f$ values must be sorted. */
210
        template <class I1, class I2>
211
        FritschButlandLogCubic(const I1& xBegin,
212
                               const I1& xEnd,
213
                               const I2& yBegin)
214
        : LogCubicInterpolation(xBegin, xEnd, yBegin,
215
                                CubicInterpolation::FritschButland, false,
216
                                CubicInterpolation::SecondDerivative, 0.0,
217
                                CubicInterpolation::SecondDerivative, 0.0) {}
218
    };
219
220
    class LogParabolic : public LogCubicInterpolation {
221
      public:
222
        /*! \pre the \f$ x \f$ values must be sorted. */
223
        template <class I1, class I2>
224
        LogParabolic(const I1& xBegin,
225
                     const I1& xEnd,
226
                     const I2& yBegin)
227
        : LogCubicInterpolation(xBegin, xEnd, yBegin,
228
                                CubicInterpolation::Parabolic, false,
229
                                CubicInterpolation::SecondDerivative, 0.0,
230
                                CubicInterpolation::SecondDerivative, 0.0) {}
231
    };
232
233
    class MonotonicLogParabolic : public LogCubicInterpolation {
234
      public:
235
        /*! \pre the \f$ x \f$ values must be sorted. */
236
        template <class I1, class I2>
237
        MonotonicLogParabolic(const I1& xBegin,
238
                              const I1& xEnd,
239
                              const I2& yBegin)
240
        : LogCubicInterpolation(xBegin, xEnd, yBegin,
241
                                CubicInterpolation::Parabolic, true,
242
                                CubicInterpolation::SecondDerivative, 0.0,
243
                                CubicInterpolation::SecondDerivative, 0.0) {}
244
    };
245
246
    //! %log-mixedlinearcubic interpolation between discrete points
247
    /*! \ingroup interpolations */
248
    class LogMixedLinearCubicInterpolation : public Interpolation {
249
      public:
250
        /*! \pre the \f$ x \f$ values must be sorted. */
251
        template <class I1, class I2>
252
        LogMixedLinearCubicInterpolation(const I1& xBegin, const I1& xEnd,
253
                                         const I2& yBegin, const Size n,
254
                                         MixedInterpolation::Behavior behavior,
255
                                         CubicInterpolation::DerivativeApprox da,
256
                                         bool monotonic,
257
                                         CubicInterpolation::BoundaryCondition leftC,
258
                                         Real leftConditionValue,
259
                                         CubicInterpolation::BoundaryCondition rightC,
260
                                         Real rightConditionValue,
261
                                         bool update = true) {
262
            impl_ = ext::make_shared<detail::LogInterpolationImpl<I1, I2>>(
263
                xBegin, xEnd, yBegin,
264
                MixedLinearCubic(n, behavior, da, monotonic,
265
                                 leftC, leftConditionValue,
266
                                 rightC, rightConditionValue));
267
            if (update)
268
                impl_->update();
269
        }
270
    };
271
272
    //! log-cubic interpolation factory and traits
273
    /*! \ingroup interpolations */
274
    class LogMixedLinearCubic {
275
      public:
276
        LogMixedLinearCubic(const Size n,
277
                            MixedInterpolation::Behavior behavior,
278
                            CubicInterpolation::DerivativeApprox da,
279
                            bool monotonic = true,
280
                            CubicInterpolation::BoundaryCondition leftCondition
281
                                = CubicInterpolation::SecondDerivative,
282
                            Real leftConditionValue = 0.0,
283
                            CubicInterpolation::BoundaryCondition rightCondition
284
                                = CubicInterpolation::SecondDerivative,
285
                            Real rightConditionValue = 0.0)
286
        : n_(n), behavior_(behavior), da_(da), monotonic_(monotonic),
287
          leftType_(leftCondition), rightType_(rightCondition),
288
0
          leftValue_(leftConditionValue), rightValue_(rightConditionValue) {}
289
        template <class I1, class I2>
290
        Interpolation interpolate(const I1& xBegin, const I1& xEnd,
291
                                  const I2& yBegin, bool update = true) const {
292
            return LogMixedLinearCubicInterpolation(xBegin, xEnd, yBegin,
293
                                                    n_, behavior_,
294
                                                    da_, monotonic_,
295
                                                    leftType_, leftValue_,
296
                                                    rightType_, rightValue_,
297
                                                    update);
298
        }
299
        static const bool global = true;
300
        static const Size requiredPoints = 3;
301
    private:
302
        Size n_;
303
        MixedInterpolation::Behavior behavior_;
304
        CubicInterpolation::DerivativeApprox da_;
305
        bool monotonic_;
306
        CubicInterpolation::BoundaryCondition leftType_, rightType_;
307
        Real leftValue_, rightValue_;
308
    };
309
310
    // convenience classes
311
    
312
    /*! \deprecated Use KrugerLogMixedLinearCubic instead.
313
                    Deprecated in version 1.42.
314
    */
315
    class [[deprecated("Use KrugerLogMixedLinearCubic instead")]] DefaultLogMixedLinearCubic
316
        : public LogMixedLinearCubic {
317
      public:
318
        explicit DefaultLogMixedLinearCubic(const Size n,
319
                                            MixedInterpolation::Behavior behavior
320
                                            = MixedInterpolation::ShareRanges)
321
        : LogMixedLinearCubic(n, behavior,
322
0
                              CubicInterpolation::Kruger) {}
323
    };
324
325
    class MonotonicLogMixedLinearCubic : public LogMixedLinearCubic {
326
      public:
327
        explicit MonotonicLogMixedLinearCubic(const Size n,
328
                                              MixedInterpolation::Behavior behavior
329
                                              = MixedInterpolation::ShareRanges)
330
        : LogMixedLinearCubic(n, behavior,
331
                              CubicInterpolation::Spline, true,
332
                              CubicInterpolation::SecondDerivative, 0.0,
333
0
                              CubicInterpolation::SecondDerivative, 0.0) {}
334
    };
335
336
    class KrugerLogMixedLinearCubic: public LogMixedLinearCubic {
337
      public:
338
        explicit KrugerLogMixedLinearCubic(const Size n,
339
                                           MixedInterpolation::Behavior behavior
340
                                           = MixedInterpolation::ShareRanges)
341
        : LogMixedLinearCubic(n, behavior,
342
                              CubicInterpolation::Kruger, false,
343
                              CubicInterpolation::SecondDerivative, 0.0,
344
0
                              CubicInterpolation::SecondDerivative, 0.0) {}
345
    };
346
347
348
    class LogMixedLinearCubicNaturalSpline : public LogMixedLinearCubicInterpolation {
349
      public:
350
        /*! \pre the \f$ x \f$ values must be sorted. */
351
        template <class I1, class I2>
352
        LogMixedLinearCubicNaturalSpline(const I1& xBegin, const I1& xEnd,
353
                                         const I2& yBegin, const Size n,
354
                                         MixedInterpolation::Behavior behavior
355
                                             = MixedInterpolation::ShareRanges)
356
        : LogMixedLinearCubicInterpolation(xBegin, xEnd, yBegin, n, behavior,
357
                                           CubicInterpolation::Spline, false,
358
                                           CubicInterpolation::SecondDerivative, 0.0,
359
                                           CubicInterpolation::SecondDerivative, 0.0) {}
360
    };
361
362
363
    namespace detail {
364
365
        template <class I1, class I2>
366
        class LogInterpolationImpl final
367
            : public Interpolation::templateImpl<I1, I2> {
368
          public:
369
            template <class Interpolator>
370
            LogInterpolationImpl(const I1& xBegin, const I1& xEnd,
371
                                 const I2& yBegin,
372
                                 const Interpolator& factory)
373
52
            : Interpolation::templateImpl<I1, I2>(xBegin, xEnd, yBegin,
374
52
                                                  Interpolator::requiredPoints),
375
52
              logY_(xEnd-xBegin) {
376
52
                interpolation_ = detail::interpolateWithoutUpdate(
377
52
                    factory, this->xBegin_, this->xEnd_, logY_.begin());
378
52
            }
379
52
            void update() override {
380
719
                for (Size i=0; i<logY_.size(); ++i) {
381
667
                    QL_REQUIRE(this->yBegin_[i]>0.0,
382
667
                               "invalid value (" << this->yBegin_[i]
383
667
                               << ") at index " << i);
384
667
                    logY_[i] = std::log(this->yBegin_[i]);
385
667
                }
386
52
                interpolation_.update();
387
52
            }
388
208
            Real value(Real x) const override { return std::exp(interpolation_(x, true)); }
389
52
            Real primitive(Real) const override {
390
52
                QL_FAIL("LogInterpolation primitive not implemented");
391
52
            }
392
104
            Real derivative(Real x) const override {
393
104
                return value(x)*interpolation_.derivative(x, true);
394
104
            }
395
52
            Real secondDerivative(Real x) const override {
396
52
                return derivative(x)*interpolation_.derivative(x, true) +
397
52
                            value(x)*interpolation_.secondDerivative(x, true);
398
52
            }
399
400
          private:
401
            std::vector<Real> logY_;
402
            Interpolation interpolation_;
403
        };
404
405
    }
406
407
}
408
409
#endif