Coverage Report

Created: 2026-06-23 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/quantlib/ql/math/interpolations/cubicinterpolation.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
 Copyright (C) 2001, 2002, 2003 Nicolas Di Césaré
6
 Copyright (C) 2004, 2008, 2009, 2011 Ferdinando Ametrano
7
 Copyright (C) 2009 Sylvain Bertrand
8
 Copyright (C) 2013 Peter Caspers
9
 Copyright (C) 2016 Nicholas Bertocchi
10
11
 This file is part of QuantLib, a free-software/open-source library
12
 for financial quantitative analysts and developers - http://quantlib.org/
13
14
 QuantLib is free software: you can redistribute it and/or modify it
15
 under the terms of the QuantLib license.  You should have received a
16
 copy of the license along with this program; if not, please email
17
 <quantlib-dev@lists.sf.net>. The license is also available online at
18
 <https://www.quantlib.org/license.shtml>.
19
20
 This program is distributed in the hope that it will be useful, but WITHOUT
21
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
22
 FOR A PARTICULAR PURPOSE.  See the license for more details.
23
*/
24
25
/*! \file cubicinterpolation.hpp
26
    \brief cubic interpolation between discrete points
27
*/
28
29
#ifndef quantlib_cubic_interpolation_hpp
30
#define quantlib_cubic_interpolation_hpp
31
32
#include <algorithm>
33
#include <ql/math/matrix.hpp>
34
#include <ql/math/interpolation.hpp>
35
#include <ql/methods/finitedifferences/tridiagonaloperator.hpp>
36
#include <vector>
37
38
namespace QuantLib {
39
40
    namespace detail {
41
42
        class CubicInterpolationBaseImpl : public Interpolation::Impl {
43
          public:
44
            CubicInterpolationBaseImpl(Size n,
45
                                       Real leftConditionValue,
46
                                       Real rightConditionValue)
47
6.90k
            : primitiveConst_(n-1), a_(n-1), b_(n-1), c_(n-1),
48
6.90k
              monotonicityAdjustments_(n),
49
6.90k
              leftValue_(leftConditionValue), rightValue_(rightConditionValue) {}
50
51
            // P[i](x) = y[i] +
52
            //           a[i]*(x-x[i]) +
53
            //           b[i]*(x-x[i])^2 +
54
            //           c[i]*(x-x[i])^3
55
            std::vector<Real> primitiveConst_, a_, b_, c_;
56
            std::vector<bool> monotonicityAdjustments_;
57
            Real leftValue_, rightValue_;
58
        };
59
60
        template <class I1, class I2> class CubicInterpolationImpl;
61
62
    }
63
64
    //! %Cubic interpolation between discrete points.
65
    /*! Cubic interpolation is fully defined when the ${f_i}$ function values
66
        at points ${x_i}$ are supplemented with ${f^'_i}$ function derivative
67
        values.
68
69
        Different type of first derivative approximations are implemented,
70
        both local and non-local. Local schemes (Fourth-order, Parabolic,
71
        Modified Parabolic, Fritsch-Butland, Akima, Kruger) use only $f$ values
72
        near $x_i$ to calculate each $f^'_i$. Non-local schemes (Spline with
73
        different boundary conditions) use all ${f_i}$ values and obtain
74
        ${f^'_i}$ by solving a linear system of equations. Local schemes
75
        produce $C^1$ interpolants, while the spline schemes generate $C^2$
76
        interpolants.
77
78
        Hyman's monotonicity constraint filter is also implemented: it can be
79
        applied to all schemes to ensure that in the regions of local
80
        monotoniticity of the input (three successive increasing or decreasing
81
        values) the interpolating cubic remains monotonic. If the interpolating
82
        cubic is already monotonic, the Hyman filter leaves it unchanged
83
        preserving all its original features.
84
85
        In the case of $C^2$ interpolants the Hyman filter ensures local
86
        monotonicity at the expense of the second derivative of the interpolant
87
        which will no longer be continuous in the points where the filter has
88
        been applied.
89
90
        While some non-linear schemes (Modified Parabolic, Fritsch-Butland,
91
        Kruger) are guaranteed to be locally monotonic in their original
92
        approximation, all other schemes must be filtered according to the
93
        Hyman criteria at the expense of their linearity.
94
95
        See R. L. Dougherty, A. Edelman, and J. M. Hyman,
96
        "Nonnegativity-, Monotonicity-, or Convexity-Preserving CubicSpline and
97
        Quintic Hermite Interpolation"
98
        Mathematics Of Computation, v. 52, n. 186, April 1989, pp. 471-494.
99
100
        \todo implement missing schemes (FourthOrder and ModifiedParabolic) and
101
              missing boundary conditions (Periodic and Lagrange).
102
103
        \test to be adapted from old ones.
104
105
        \ingroup interpolations
106
        \warning See the Interpolation class for information about the
107
                 required lifetime of the underlying data.
108
    */
109
    class CubicInterpolation : public Interpolation {
110
      public:
111
        enum DerivativeApprox {
112
            /*! Spline approximation (non-local, non-monotonic, linear[?]).
113
                Different boundary conditions can be used on the left and right
114
                boundaries: see BoundaryCondition.
115
            */
116
            Spline,
117
118
            //! Overshooting minimization 1st derivative
119
            SplineOM1,
120
121
            //! Overshooting minimization 2nd derivative
122
            SplineOM2,
123
124
            //! Fourth-order approximation (local, non-monotonic, linear)
125
            FourthOrder,
126
127
            //! Parabolic approximation (local, non-monotonic, linear)
128
            Parabolic,
129
130
            //! Fritsch-Butland approximation (local, monotonic, non-linear)
131
            FritschButland,
132
133
            //! Akima approximation (local, non-monotonic, non-linear)
134
            Akima,
135
136
            //! Kruger approximation (local, monotonic, non-linear)
137
            Kruger, 
138
139
            //! Weighted harmonic mean approximation (local, monotonic, non-linear)
140
            Harmonic,
141
        };
142
        enum BoundaryCondition {
143
            //! Make second(-last) point an inactive knot
144
            NotAKnot,
145
146
            //! Match value of end-slope
147
            FirstDerivative,
148
149
            //! Match value of second derivative at end
150
            SecondDerivative,
151
152
            //! Match first and second derivative at either end
153
            Periodic,
154
155
            /*! Match end-slope to the slope of the cubic that matches
156
                the first four data at the respective end
157
            */
158
            Lagrange
159
        };
160
        /*! \pre the \f$ x \f$ values must be sorted. */
161
        template <class I1, class I2>
162
        CubicInterpolation(const I1& xBegin,
163
                           const I1& xEnd,
164
                           const I2& yBegin,
165
                           CubicInterpolation::DerivativeApprox da,
166
                           bool monotonic,
167
                           CubicInterpolation::BoundaryCondition leftCond,
168
                           Real leftConditionValue,
169
                           CubicInterpolation::BoundaryCondition rightCond,
170
                           Real rightConditionValue,
171
6.90k
                           bool update = true) {
172
6.90k
            impl_ = ext::shared_ptr<Interpolation::Impl>(new
173
6.90k
                detail::CubicInterpolationImpl<I1,I2>(xBegin, xEnd, yBegin,
174
6.90k
                                                      da,
175
6.90k
                                                      monotonic,
176
6.90k
                                                      leftCond,
177
6.90k
                                                      leftConditionValue,
178
6.90k
                                                      rightCond,
179
6.90k
                                                      rightConditionValue));
180
6.90k
            if (update)
181
6.90k
                impl_->update();
182
6.90k
        }
QuantLib::CubicInterpolation::CubicInterpolation<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*> >(std::__1::__wrap_iter<double*> const&, std::__1::__wrap_iter<double*> const&, std::__1::__wrap_iter<double*> const&, QuantLib::CubicInterpolation::DerivativeApprox, bool, QuantLib::CubicInterpolation::BoundaryCondition, double, QuantLib::CubicInterpolation::BoundaryCondition, double, bool)
Line
Count
Source
171
122
                           bool update = true) {
172
122
            impl_ = ext::shared_ptr<Interpolation::Impl>(new
173
122
                detail::CubicInterpolationImpl<I1,I2>(xBegin, xEnd, yBegin,
174
122
                                                      da,
175
122
                                                      monotonic,
176
122
                                                      leftCond,
177
122
                                                      leftConditionValue,
178
122
                                                      rightCond,
179
122
                                                      rightConditionValue));
180
122
            if (update)
181
122
                impl_->update();
182
122
        }
Unexecuted instantiation: QuantLib::CubicInterpolation::CubicInterpolation<std::__1::__wrap_iter<double*>, double const*>(std::__1::__wrap_iter<double*> const&, std::__1::__wrap_iter<double*> const&, double const* const&, QuantLib::CubicInterpolation::DerivativeApprox, bool, QuantLib::CubicInterpolation::BoundaryCondition, double, QuantLib::CubicInterpolation::BoundaryCondition, double, bool)
QuantLib::CubicInterpolation::CubicInterpolation<std::__1::__wrap_iter<double const*>, double*>(std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double const*> const&, double* const&, QuantLib::CubicInterpolation::DerivativeApprox, bool, QuantLib::CubicInterpolation::BoundaryCondition, double, QuantLib::CubicInterpolation::BoundaryCondition, double, bool)
Line
Count
Source
171
6.78k
                           bool update = true) {
172
6.78k
            impl_ = ext::shared_ptr<Interpolation::Impl>(new
173
6.78k
                detail::CubicInterpolationImpl<I1,I2>(xBegin, xEnd, yBegin,
174
6.78k
                                                      da,
175
6.78k
                                                      monotonic,
176
6.78k
                                                      leftCond,
177
6.78k
                                                      leftConditionValue,
178
6.78k
                                                      rightCond,
179
6.78k
                                                      rightConditionValue));
180
6.78k
            if (update)
181
6.78k
                impl_->update();
182
6.78k
        }
Unexecuted instantiation: QuantLib::CubicInterpolation::CubicInterpolation<std::__1::__wrap_iter<double const*>, double const*>(std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double const*> const&, double const* const&, QuantLib::CubicInterpolation::DerivativeApprox, bool, QuantLib::CubicInterpolation::BoundaryCondition, double, QuantLib::CubicInterpolation::BoundaryCondition, double, bool)
Unexecuted instantiation: QuantLib::CubicInterpolation::CubicInterpolation<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double*> >(std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double*> const&, QuantLib::CubicInterpolation::DerivativeApprox, bool, QuantLib::CubicInterpolation::BoundaryCondition, double, QuantLib::CubicInterpolation::BoundaryCondition, double, bool)
Unexecuted instantiation: QuantLib::CubicInterpolation::CubicInterpolation<double const*, double*>(double const* const&, double const* const&, double* const&, QuantLib::CubicInterpolation::DerivativeApprox, bool, QuantLib::CubicInterpolation::BoundaryCondition, double, QuantLib::CubicInterpolation::BoundaryCondition, double, bool)
Unexecuted instantiation: QuantLib::CubicInterpolation::CubicInterpolation<double*, double*>(double* const&, double* const&, double* const&, QuantLib::CubicInterpolation::DerivativeApprox, bool, QuantLib::CubicInterpolation::BoundaryCondition, double, QuantLib::CubicInterpolation::BoundaryCondition, double, bool)
Unexecuted instantiation: QuantLib::CubicInterpolation::CubicInterpolation<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*> >(std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double const*> const&, QuantLib::CubicInterpolation::DerivativeApprox, bool, QuantLib::CubicInterpolation::BoundaryCondition, double, QuantLib::CubicInterpolation::BoundaryCondition, double, bool)
Unexecuted instantiation: QuantLib::CubicInterpolation::CubicInterpolation<double const*, double const*>(double const* const&, double const* const&, double const* const&, QuantLib::CubicInterpolation::DerivativeApprox, bool, QuantLib::CubicInterpolation::BoundaryCondition, double, QuantLib::CubicInterpolation::BoundaryCondition, double, bool)
183
0
        const std::vector<Real>& primitiveConstants() const {
184
0
            return baseImpl().primitiveConst_;
185
0
        }
186
0
        const std::vector<Real>& aCoefficients() const { return baseImpl().a_; }
187
0
        const std::vector<Real>& bCoefficients() const { return baseImpl().b_; }
188
0
        const std::vector<Real>& cCoefficients() const { return baseImpl().c_; }
189
0
        const std::vector<bool>& monotonicityAdjustments() const {
190
0
            return baseImpl().monotonicityAdjustments_;
191
0
        }
192
0
        void updateLeftConditionValue(Real value) {
193
0
            baseImpl().leftValue_ = value;
194
0
        }
195
0
        void updateRightConditionValue(Real value) {
196
0
            baseImpl().rightValue_ = value;
197
0
        }
198
      private:
199
0
        detail::CubicInterpolationBaseImpl& baseImpl() const {
200
0
            // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast)
201
0
            return *static_cast<detail::CubicInterpolationBaseImpl*>(impl_.get());
202
0
        }
203
    };
204
205
206
    // convenience classes
207
208
    class CubicNaturalSpline : public CubicInterpolation {
209
      public:
210
        /*! \pre the \f$ x \f$ values must be sorted. */
211
        template <class I1, class I2>
212
        CubicNaturalSpline(const I1& xBegin,
213
                           const I1& xEnd,
214
                           const I2& yBegin)
215
122
        : CubicInterpolation(xBegin, xEnd, yBegin,
216
122
                             Spline, false,
217
122
                             SecondDerivative, 0.0,
218
122
                             SecondDerivative, 0.0) {}
QuantLib::CubicNaturalSpline::CubicNaturalSpline<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*> >(std::__1::__wrap_iter<double*> const&, std::__1::__wrap_iter<double*> const&, std::__1::__wrap_iter<double*> const&)
Line
Count
Source
215
122
        : CubicInterpolation(xBegin, xEnd, yBegin,
216
122
                             Spline, false,
217
122
                             SecondDerivative, 0.0,
218
122
                             SecondDerivative, 0.0) {}
Unexecuted instantiation: QuantLib::CubicNaturalSpline::CubicNaturalSpline<double*, double*>(double* const&, double* const&, double* const&)
Unexecuted instantiation: QuantLib::CubicNaturalSpline::CubicNaturalSpline<std::__1::__wrap_iter<double const*>, double*>(std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double const*> const&, double* const&)
Unexecuted instantiation: QuantLib::CubicNaturalSpline::CubicNaturalSpline<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*> >(std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double const*> const&)
Unexecuted instantiation: QuantLib::CubicNaturalSpline::CubicNaturalSpline<double const*, double const*>(double const* const&, double const* const&, double const* const&)
219
    };
220
221
    class MonotonicCubicNaturalSpline : public CubicInterpolation {
222
      public:
223
        /*! \pre the \f$ x \f$ values must be sorted. */
224
        template <class I1, class I2>
225
        MonotonicCubicNaturalSpline(const I1& xBegin,
226
                                    const I1& xEnd,
227
                                    const I2& yBegin)
228
6.78k
        : CubicInterpolation(xBegin, xEnd, yBegin,
229
6.78k
                             Spline, true,
230
6.78k
                             SecondDerivative, 0.0,
231
6.78k
                             SecondDerivative, 0.0) {}
QuantLib::MonotonicCubicNaturalSpline::MonotonicCubicNaturalSpline<std::__1::__wrap_iter<double const*>, double*>(std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double const*> const&, double* const&)
Line
Count
Source
228
6.78k
        : CubicInterpolation(xBegin, xEnd, yBegin,
229
6.78k
                             Spline, true,
230
6.78k
                             SecondDerivative, 0.0,
231
6.78k
                             SecondDerivative, 0.0) {}
Unexecuted instantiation: QuantLib::MonotonicCubicNaturalSpline::MonotonicCubicNaturalSpline<double const*, double*>(double const* const&, double const* const&, double* const&)
Unexecuted instantiation: QuantLib::MonotonicCubicNaturalSpline::MonotonicCubicNaturalSpline<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*> >(std::__1::__wrap_iter<double*> const&, std::__1::__wrap_iter<double*> const&, std::__1::__wrap_iter<double*> const&)
232
    };
233
234
    class CubicSplineOvershootingMinimization1 : public CubicInterpolation {
235
      public:
236
        /*! \pre the \f$ x \f$ values must be sorted. */
237
        template <class I1, class I2>
238
        CubicSplineOvershootingMinimization1 (const I1& xBegin,
239
                                           const I1& xEnd,
240
                                           const I2& yBegin)
241
        : CubicInterpolation(xBegin, xEnd, yBegin,
242
                             SplineOM1, false,
243
                             SecondDerivative, 0.0,
244
                             SecondDerivative, 0.0) {}
245
    };
246
247
    class CubicSplineOvershootingMinimization2 : public CubicInterpolation {
248
      public:
249
        /*! \pre the \f$ x \f$ values must be sorted. */
250
        template <class I1, class I2>
251
        CubicSplineOvershootingMinimization2 (const I1& xBegin,
252
                                           const I1& xEnd,
253
                                           const I2& yBegin)
254
        : CubicInterpolation(xBegin, xEnd, yBegin,
255
                             SplineOM2, false,
256
                             SecondDerivative, 0.0,
257
                             SecondDerivative, 0.0) {}
258
    };
259
260
    class AkimaCubicInterpolation : public CubicInterpolation {
261
      public:
262
        /*! \pre the \f$ x \f$ values must be sorted. */
263
        template <class I1, class I2>
264
        AkimaCubicInterpolation(const I1& xBegin,
265
                                const I1& xEnd,
266
                                const I2& yBegin)
267
        : CubicInterpolation(xBegin, xEnd, yBegin,
268
                             Akima, false,
269
                             SecondDerivative, 0.0,
270
                             SecondDerivative, 0.0) {}
271
    };
272
273
    class KrugerCubic : public CubicInterpolation {
274
      public:
275
        /*! \pre the \f$ x \f$ values must be sorted. */
276
        template <class I1, class I2>
277
        KrugerCubic(const I1& xBegin,
278
                    const I1& xEnd,
279
                    const I2& yBegin)
280
        : CubicInterpolation(xBegin, xEnd, yBegin,
281
                             Kruger, false,
282
                             SecondDerivative, 0.0,
283
                             SecondDerivative, 0.0) {}
284
    };
285
286
    class HarmonicCubic : public CubicInterpolation {
287
      public:
288
        /*! \pre the \f$ x \f$ values must be sorted. */
289
        template <class I1, class I2>
290
        HarmonicCubic(const I1& xBegin,
291
                      const I1& xEnd,
292
                      const I2& yBegin)
293
        : CubicInterpolation(xBegin, xEnd, yBegin,
294
                             Harmonic, false,
295
                             SecondDerivative, 0.0,
296
                             SecondDerivative, 0.0) {}
297
    };
298
299
    class FritschButlandCubic : public CubicInterpolation {
300
      public:
301
        /*! \pre the \f$ x \f$ values must be sorted. */
302
        template <class I1, class I2>
303
        FritschButlandCubic(const I1& xBegin,
304
                            const I1& xEnd,
305
                            const I2& yBegin)
306
        : CubicInterpolation(xBegin, xEnd, yBegin,
307
                             FritschButland, true,
308
                             SecondDerivative, 0.0,
309
                             SecondDerivative, 0.0) {}
310
    };
311
312
    class Parabolic : public CubicInterpolation {
313
      public:
314
        /*! \pre the \f$ x \f$ values must be sorted. */
315
        template <class I1, class I2>
316
        Parabolic(const I1& xBegin,
317
                  const I1& xEnd,
318
                  const I2& yBegin)
319
        : CubicInterpolation(xBegin, xEnd, yBegin,
320
                             CubicInterpolation::Parabolic, false,
321
                             SecondDerivative, 0.0,
322
                             SecondDerivative, 0.0) {}
323
    };
324
325
    class MonotonicParabolic : public CubicInterpolation {
326
      public:
327
        /*! \pre the \f$ x \f$ values must be sorted. */
328
        template <class I1, class I2>
329
        MonotonicParabolic(const I1& xBegin,
330
                           const I1& xEnd,
331
                           const I2& yBegin)
332
        : CubicInterpolation(xBegin, xEnd, yBegin,
333
                             Parabolic, true,
334
                             SecondDerivative, 0.0,
335
                             SecondDerivative, 0.0) {}
336
    };
337
338
    //! %Cubic interpolation factory and traits
339
    /*! \ingroup interpolations */
340
    class Cubic {
341
      public:
342
        Cubic(CubicInterpolation::DerivativeApprox da
343
                  = CubicInterpolation::Kruger,
344
              bool monotonic = false,
345
              CubicInterpolation::BoundaryCondition leftCondition
346
                  = CubicInterpolation::SecondDerivative,
347
              Real leftConditionValue = 0.0,
348
              CubicInterpolation::BoundaryCondition rightCondition
349
                  = CubicInterpolation::SecondDerivative,
350
              Real rightConditionValue = 0.0)
351
        : da_(da), monotonic_(monotonic),
352
          leftType_(leftCondition), rightType_(rightCondition),
353
0
          leftValue_(leftConditionValue), rightValue_(rightConditionValue) {}
354
        template <class I1, class I2>
355
        Interpolation interpolate(const I1& xBegin,
356
                                  const I1& xEnd,
357
                                  const I2& yBegin,
358
0
                                  bool update = true) const {
359
0
            return CubicInterpolation(xBegin, xEnd, yBegin,
360
0
                                      da_, monotonic_,
361
0
                                      leftType_, leftValue_,
362
0
                                      rightType_, rightValue_, update);
363
0
        }
364
        static const bool global = true;
365
        static const Size requiredPoints = 2;
366
      private:
367
        CubicInterpolation::DerivativeApprox da_;
368
        bool monotonic_;
369
        CubicInterpolation::BoundaryCondition leftType_, rightType_;
370
        Real leftValue_, rightValue_;
371
    };
372
373
374
    namespace detail {
375
376
        template <class I1, class I2>
377
        class CubicInterpolationImpl final
378
            : public Interpolation::templateImpl<I1, I2, CubicInterpolationBaseImpl> {
379
          public:
380
            CubicInterpolationImpl(const I1& xBegin,
381
                                   const I1& xEnd,
382
                                   const I2& yBegin,
383
                                   CubicInterpolation::DerivativeApprox da,
384
                                   bool monotonic,
385
                                   CubicInterpolation::BoundaryCondition leftCondition,
386
                                   Real leftConditionValue,
387
                                   CubicInterpolation::BoundaryCondition rightCondition,
388
                                   Real rightConditionValue)
389
6.90k
            : Interpolation::templateImpl<I1, I2, CubicInterpolationBaseImpl>(
390
6.90k
                xBegin, xEnd, yBegin, Cubic::requiredPoints,
391
6.90k
                xEnd-xBegin, leftConditionValue, rightConditionValue),
392
6.90k
              n_(xEnd-xBegin),
393
6.90k
              da_(da),
394
6.90k
              monotonic_(monotonic),
395
6.90k
              leftType_(leftCondition), rightType_(rightCondition),
396
6.90k
              tmp_(n_), dx_(n_-1), S_(n_-1), L_(n_) {
397
6.90k
                if (leftType_ == CubicInterpolation::Lagrange
398
6.90k
                    || rightType_ == CubicInterpolation::Lagrange) {
399
0
                    QL_REQUIRE((xEnd-xBegin) >= 4,
400
0
                               "Lagrange boundary condition requires at least "
401
0
                               "4 points (" << (xEnd-xBegin) << " are given)");
402
0
                }
403
6.90k
                if (da_ == CubicInterpolation::Akima) {
404
0
                    QL_REQUIRE((xEnd-xBegin) >= 4,
405
0
                               "Akima approximation requires at least "
406
0
                               "4 points (" << (xEnd-xBegin) << " are given)");
407
0
                }
408
6.90k
            }
QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*> >::CubicInterpolationImpl(std::__1::__wrap_iter<double*> const&, std::__1::__wrap_iter<double*> const&, std::__1::__wrap_iter<double*> const&, QuantLib::CubicInterpolation::DerivativeApprox, bool, QuantLib::CubicInterpolation::BoundaryCondition, double, QuantLib::CubicInterpolation::BoundaryCondition, double)
Line
Count
Source
389
122
            : Interpolation::templateImpl<I1, I2, CubicInterpolationBaseImpl>(
390
122
                xBegin, xEnd, yBegin, Cubic::requiredPoints,
391
122
                xEnd-xBegin, leftConditionValue, rightConditionValue),
392
122
              n_(xEnd-xBegin),
393
122
              da_(da),
394
122
              monotonic_(monotonic),
395
122
              leftType_(leftCondition), rightType_(rightCondition),
396
122
              tmp_(n_), dx_(n_-1), S_(n_-1), L_(n_) {
397
122
                if (leftType_ == CubicInterpolation::Lagrange
398
122
                    || rightType_ == CubicInterpolation::Lagrange) {
399
0
                    QL_REQUIRE((xEnd-xBegin) >= 4,
400
0
                               "Lagrange boundary condition requires at least "
401
0
                               "4 points (" << (xEnd-xBegin) << " are given)");
402
0
                }
403
122
                if (da_ == CubicInterpolation::Akima) {
404
                    QL_REQUIRE((xEnd-xBegin) >= 4,
405
0
                               "Akima approximation requires at least "
406
0
                               "4 points (" << (xEnd-xBegin) << " are given)");
407
0
                }
408
122
            }
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double*>, double const*>::CubicInterpolationImpl(std::__1::__wrap_iter<double*> const&, std::__1::__wrap_iter<double*> const&, double const* const&, QuantLib::CubicInterpolation::DerivativeApprox, bool, QuantLib::CubicInterpolation::BoundaryCondition, double, QuantLib::CubicInterpolation::BoundaryCondition, double)
QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, double*>::CubicInterpolationImpl(std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double const*> const&, double* const&, QuantLib::CubicInterpolation::DerivativeApprox, bool, QuantLib::CubicInterpolation::BoundaryCondition, double, QuantLib::CubicInterpolation::BoundaryCondition, double)
Line
Count
Source
389
6.78k
            : Interpolation::templateImpl<I1, I2, CubicInterpolationBaseImpl>(
390
6.78k
                xBegin, xEnd, yBegin, Cubic::requiredPoints,
391
6.78k
                xEnd-xBegin, leftConditionValue, rightConditionValue),
392
6.78k
              n_(xEnd-xBegin),
393
6.78k
              da_(da),
394
6.78k
              monotonic_(monotonic),
395
6.78k
              leftType_(leftCondition), rightType_(rightCondition),
396
6.78k
              tmp_(n_), dx_(n_-1), S_(n_-1), L_(n_) {
397
6.78k
                if (leftType_ == CubicInterpolation::Lagrange
398
6.78k
                    || rightType_ == CubicInterpolation::Lagrange) {
399
0
                    QL_REQUIRE((xEnd-xBegin) >= 4,
400
0
                               "Lagrange boundary condition requires at least "
401
0
                               "4 points (" << (xEnd-xBegin) << " are given)");
402
0
                }
403
6.78k
                if (da_ == CubicInterpolation::Akima) {
404
                    QL_REQUIRE((xEnd-xBegin) >= 4,
405
0
                               "Akima approximation requires at least "
406
0
                               "4 points (" << (xEnd-xBegin) << " are given)");
407
0
                }
408
6.78k
            }
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, double const*>::CubicInterpolationImpl(std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double const*> const&, double const* const&, QuantLib::CubicInterpolation::DerivativeApprox, bool, QuantLib::CubicInterpolation::BoundaryCondition, double, QuantLib::CubicInterpolation::BoundaryCondition, double)
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double*> >::CubicInterpolationImpl(std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double*> const&, QuantLib::CubicInterpolation::DerivativeApprox, bool, QuantLib::CubicInterpolation::BoundaryCondition, double, QuantLib::CubicInterpolation::BoundaryCondition, double)
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<double const*, double*>::CubicInterpolationImpl(double const* const&, double const* const&, double* const&, QuantLib::CubicInterpolation::DerivativeApprox, bool, QuantLib::CubicInterpolation::BoundaryCondition, double, QuantLib::CubicInterpolation::BoundaryCondition, double)
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<double*, double*>::CubicInterpolationImpl(double* const&, double* const&, double* const&, QuantLib::CubicInterpolation::DerivativeApprox, bool, QuantLib::CubicInterpolation::BoundaryCondition, double, QuantLib::CubicInterpolation::BoundaryCondition, double)
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*> >::CubicInterpolationImpl(std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double const*> const&, std::__1::__wrap_iter<double const*> const&, QuantLib::CubicInterpolation::DerivativeApprox, bool, QuantLib::CubicInterpolation::BoundaryCondition, double, QuantLib::CubicInterpolation::BoundaryCondition, double)
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<double const*, double const*>::CubicInterpolationImpl(double const* const&, double const* const&, double const* const&, QuantLib::CubicInterpolation::DerivativeApprox, bool, QuantLib::CubicInterpolation::BoundaryCondition, double, QuantLib::CubicInterpolation::BoundaryCondition, double)
409
410
6.90k
            void update() override {
411
412
456k
                for (Size i=0; i<n_-1; ++i) {
413
449k
                    dx_[i] = this->xBegin_[i+1] - this->xBegin_[i];
414
449k
                    S_[i] = (this->yBegin_[i+1] - this->yBegin_[i])/dx_[i];
415
449k
                }
416
417
                // first derivative approximation
418
6.90k
                if (da_==CubicInterpolation::Spline) {
419
449k
                    for (Size i=1; i<n_-1; ++i) {
420
442k
                        L_.setMidRow(i, dx_[i], 2.0*(dx_[i]+dx_[i-1]), dx_[i-1]);
421
442k
                        tmp_[i] = 3.0*(dx_[i]*S_[i-1] + dx_[i-1]*S_[i]);
422
442k
                    }
423
424
                    // left boundary condition
425
6.90k
                    switch (leftType_) {
426
0
                      case CubicInterpolation::NotAKnot:
427
                        // ignoring end condition value
428
0
                        L_.setFirstRow(dx_[1]*(dx_[1]+dx_[0]),
429
0
                                      (dx_[0]+dx_[1])*(dx_[0]+dx_[1]));
430
0
                        tmp_[0] = S_[0]*dx_[1]*(2.0*dx_[1]+3.0*dx_[0]) +
431
0
                                 S_[1]*dx_[0]*dx_[0];
432
0
                        break;
433
0
                      case CubicInterpolation::FirstDerivative:
434
0
                        L_.setFirstRow(1.0, 0.0);
435
0
                        tmp_[0] = this->leftValue_;
436
0
                        break;
437
6.90k
                      case CubicInterpolation::SecondDerivative:
438
6.90k
                        L_.setFirstRow(2.0, 1.0);
439
6.90k
                        tmp_[0] = 3.0*S_[0] - this->leftValue_*dx_[0]/2.0;
440
6.90k
                        break;
441
0
                      case CubicInterpolation::Periodic:
442
0
                        QL_FAIL("this end condition is not implemented yet");
443
0
                      case CubicInterpolation::Lagrange:
444
0
                        L_.setFirstRow(1.0, 0.0);
445
0
                        tmp_[0] = cubicInterpolatingPolynomialDerivative(
446
0
                                            this->xBegin_[0],this->xBegin_[1],
447
0
                                            this->xBegin_[2],this->xBegin_[3],
448
0
                                            this->yBegin_[0],this->yBegin_[1],
449
0
                                            this->yBegin_[2],this->yBegin_[3],
450
0
                                            this->xBegin_[0]);
451
0
                        break;
452
0
                      default:
453
0
                        QL_FAIL("unknown end condition");
454
6.90k
                    }
455
456
                    // right boundary condition
457
6.90k
                    switch (rightType_) {
458
0
                      case CubicInterpolation::NotAKnot:
459
                        // ignoring end condition value
460
0
                        L_.setLastRow(-(dx_[n_-2]+dx_[n_-3])*(dx_[n_-2]+dx_[n_-3]),
461
0
                                     -dx_[n_-3]*(dx_[n_-3]+dx_[n_-2]));
462
0
                        tmp_[n_-1] = -S_[n_-3]*dx_[n_-2]*dx_[n_-2] -
463
0
                                     S_[n_-2]*dx_[n_-3]*(3.0*dx_[n_-2]+2.0*dx_[n_-3]);
464
0
                        break;
465
0
                      case CubicInterpolation::FirstDerivative:
466
0
                        L_.setLastRow(0.0, 1.0);
467
0
                        tmp_[n_-1] = this->rightValue_;
468
0
                        break;
469
6.90k
                      case CubicInterpolation::SecondDerivative:
470
6.90k
                        L_.setLastRow(1.0, 2.0);
471
6.90k
                        tmp_[n_-1] = 3.0*S_[n_-2] + this->rightValue_*dx_[n_-2]/2.0;
472
6.90k
                        break;
473
0
                      case CubicInterpolation::Periodic:
474
0
                        QL_FAIL("this end condition is not implemented yet");
475
0
                      case CubicInterpolation::Lagrange:
476
0
                        L_.setLastRow(0.0,1.0);
477
0
                        tmp_[n_-1] = cubicInterpolatingPolynomialDerivative(
478
0
                                      this->xBegin_[n_-4],this->xBegin_[n_-3],
479
0
                                      this->xBegin_[n_-2],this->xBegin_[n_-1],
480
0
                                      this->yBegin_[n_-4],this->yBegin_[n_-3],
481
0
                                      this->yBegin_[n_-2],this->yBegin_[n_-1],
482
0
                                      this->xBegin_[n_-1]);
483
0
                        break;
484
0
                      default:
485
0
                        QL_FAIL("unknown end condition");
486
6.90k
                    }
487
488
                    // solve the system
489
6.90k
                    L_.solveFor(tmp_, tmp_);
490
6.90k
                } else if (da_==CubicInterpolation::SplineOM1) {
491
0
                    Matrix T_(n_-2, n_, 0.0);
492
0
                    for (Size i=0; i<n_-2; ++i) {
493
0
                        T_[i][i]=dx_[i]/6.0;
494
0
                        T_[i][i+1]=(dx_[i+1]+dx_[i])/3.0;
495
0
                        T_[i][i+2]=dx_[i+1]/6.0;
496
0
                    }
497
0
                    Matrix S_(n_-2, n_, 0.0);
498
0
                    for (Size i=0; i<n_-2; ++i) {
499
0
                        S_[i][i]=1.0/dx_[i];
500
0
                        S_[i][i+1]=-(1.0/dx_[i+1]+1.0/dx_[i]);
501
0
                        S_[i][i+2]=1.0/dx_[i+1];
502
0
                    }
503
0
                    Matrix Up_(n_, 2, 0.0);
504
0
                    Up_[0][0]=1;
505
0
                    Up_[n_-1][1]=1;
506
0
                    Matrix Us_(n_, n_-2, 0.0);
507
0
                    for (Size i=0; i<n_-2; ++i)
508
0
                        Us_[i+1][i]=1;
509
0
                    Matrix Z_ = Us_*inverse(T_*Us_);
510
0
                    Matrix I_(n_, n_, 0.0);
511
0
                    for (Size i=0; i<n_; ++i)
512
0
                        I_[i][i]=1;
513
0
                    Matrix V_ = (I_-Z_*T_)*Up_;
514
0
                    Matrix W_ = Z_*S_;
515
0
                    Matrix Q_(n_, n_, 0.0);
516
0
                    Q_[0][0]=1.0/(n_-1)*dx_[0]*dx_[0]*dx_[0];
517
0
                    Q_[0][1]=7.0/8*1.0/(n_-1)*dx_[0]*dx_[0]*dx_[0];
518
0
                    for (Size i=1; i<n_-1; ++i) {
519
0
                        Q_[i][i-1]=7.0/8*1.0/(n_-1)*dx_[i-1]*dx_[i-1]*dx_[i-1];
520
0
                        Q_[i][i]=1.0/(n_-1)*dx_[i]*dx_[i]*dx_[i]+1.0/(n_-1)*dx_[i-1]*dx_[i-1]*dx_[i-1];
521
0
                        Q_[i][i+1]=7.0/8*1.0/(n_-1)*dx_[i]*dx_[i]*dx_[i];
522
0
                    }
523
0
                    Q_[n_-1][n_-2]=7.0/8*1.0/(n_-1)*dx_[n_-2]*dx_[n_-2]*dx_[n_-2];
524
0
                    Q_[n_-1][n_-1]=1.0/(n_-1)*dx_[n_-2]*dx_[n_-2]*dx_[n_-2];
525
0
                    Matrix J_ = (I_-V_*inverse(transpose(V_)*Q_*V_)*transpose(V_)*Q_)*W_;
526
0
                    Array Y_(n_);
527
0
                    for (Size i=0; i<n_; ++i)
528
0
                        Y_[i]=this->yBegin_[i];
529
0
                    Array D_ = J_*Y_;
530
0
                    for (Size i=0; i<n_-1; ++i)
531
0
                        tmp_[i]=(Y_[i+1]-Y_[i])/dx_[i]-(2.0*D_[i]+D_[i+1])*dx_[i]/6.0;
532
0
                    tmp_[n_-1]=tmp_[n_-2]+D_[n_-2]*dx_[n_-2]+(D_[n_-1]-D_[n_-2])*dx_[n_-2]/2.0;
533
534
0
                } else if (da_==CubicInterpolation::SplineOM2) {
535
0
                    Matrix T_(n_-2, n_, 0.0);
536
0
                    for (Size i=0; i<n_-2; ++i) {
537
0
                        T_[i][i]=dx_[i]/6.0;
538
0
                        T_[i][i+1]=(dx_[i]+dx_[i+1])/3.0;
539
0
                        T_[i][i+2]=dx_[i+1]/6.0;
540
0
                    }
541
0
                    Matrix S_(n_-2, n_, 0.0);
542
0
                    for (Size i=0; i<n_-2; ++i) {
543
0
                        S_[i][i]=1.0/dx_[i];
544
0
                        S_[i][i+1]=-(1.0/dx_[i+1]+1.0/dx_[i]);
545
0
                        S_[i][i+2]=1.0/dx_[i+1];
546
0
                    }
547
0
                    Matrix Up_(n_, 2, 0.0);
548
0
                    Up_[0][0]=1;
549
0
                    Up_[n_-1][1]=1;
550
0
                    Matrix Us_(n_, n_-2, 0.0);
551
0
                    for (Size i=0; i<n_-2; ++i)
552
0
                        Us_[i+1][i]=1;
553
0
                    Matrix Z_ = Us_*inverse(T_*Us_);
554
0
                    Matrix I_(n_, n_, 0.0);
555
0
                    for (Size i=0; i<n_; ++i)
556
0
                        I_[i][i]=1;
557
0
                    Matrix V_ = (I_-Z_*T_)*Up_;
558
0
                    Matrix W_ = Z_*S_;
559
0
                    Matrix Q_(n_, n_, 0.0);
560
0
                    Q_[0][0]=1.0/(n_-1)*dx_[0];
561
0
                    Q_[0][1]=1.0/2*1.0/(n_-1)*dx_[0];
562
0
                    for (Size i=1; i<n_-1; ++i) {
563
0
                        Q_[i][i-1]=1.0/2*1.0/(n_-1)*dx_[i-1];
564
0
                        Q_[i][i]=1.0/(n_-1)*dx_[i]+1.0/(n_-1)*dx_[i-1];
565
0
                        Q_[i][i+1]=1.0/2*1.0/(n_-1)*dx_[i];
566
0
                    }
567
0
                    Q_[n_-1][n_-2]=1.0/2*1.0/(n_-1)*dx_[n_-2];
568
0
                    Q_[n_-1][n_-1]=1.0/(n_-1)*dx_[n_-2];
569
0
                    Matrix J_ = (I_-V_*inverse(transpose(V_)*Q_*V_)*transpose(V_)*Q_)*W_;
570
0
                    Array Y_(n_);
571
0
                    for (Size i=0; i<n_; ++i)
572
0
                        Y_[i]=this->yBegin_[i];
573
0
                    Array D_ = J_*Y_;
574
0
                    for (Size i=0; i<n_-1; ++i)
575
0
                        tmp_[i]=(Y_[i+1]-Y_[i])/dx_[i]-(2.0*D_[i]+D_[i+1])*dx_[i]/6.0;
576
0
                    tmp_[n_-1]=tmp_[n_-2]+D_[n_-2]*dx_[n_-2]+(D_[n_-1]-D_[n_-2])*dx_[n_-2]/2.0;
577
0
                } else { // local schemes
578
0
                    if (n_==2)
579
0
                        tmp_[0] = tmp_[1] = S_[0];
580
0
                    else {
581
0
                        switch (da_) {
582
0
                            case CubicInterpolation::FourthOrder:
583
0
                                QL_FAIL("FourthOrder not implemented yet");
584
0
                                break;
585
0
                            case CubicInterpolation::Parabolic:
586
                                // intermediate points
587
0
                                for (Size i=1; i<n_-1; ++i)
588
0
                                    tmp_[i] = (dx_[i-1]*S_[i]+dx_[i]*S_[i-1])/(dx_[i]+dx_[i-1]);
589
                                // end points
590
0
                                tmp_[0]    = ((2.0*dx_[   0]+dx_[   1])*S_[   0] - dx_[   0]*S_[   1]) / (dx_[   0]+dx_[   1]);
591
0
                                tmp_[n_-1] = ((2.0*dx_[n_-2]+dx_[n_-3])*S_[n_-2] - dx_[n_-2]*S_[n_-3]) / (dx_[n_-2]+dx_[n_-3]);
592
0
                                break;
593
0
                            case CubicInterpolation::FritschButland:
594
                                // intermediate points
595
0
                                for (Size i=1; i<n_-1; ++i) {
596
0
                                    Real Smin = std::min(S_[i-1], S_[i]);
597
0
                                    Real Smax = std::max(S_[i-1], S_[i]);
598
0
                                    if(Smax+2.0*Smin == 0){
599
0
                                        if (Smin*Smax < 0)
600
0
                                            tmp_[i] = QL_MIN_REAL;
601
0
                                        else if (Smin*Smax == 0)
602
0
                                            tmp_[i] = 0;
603
0
                                        else
604
0
                                            tmp_[i] = QL_MAX_REAL;
605
0
                                    }
606
0
                                    else
607
0
                                        tmp_[i] = 3.0*Smin*Smax/(Smax+2.0*Smin);
608
0
                                }
609
                                // end points
610
0
                                tmp_[0]    = ((2.0*dx_[   0]+dx_[   1])*S_[   0] - dx_[   0]*S_[   1]) / (dx_[   0]+dx_[   1]);
611
0
                                tmp_[n_-1] = ((2.0*dx_[n_-2]+dx_[n_-3])*S_[n_-2] - dx_[n_-2]*S_[n_-3]) / (dx_[n_-2]+dx_[n_-3]);
612
0
                                break;
613
0
                            case CubicInterpolation::Akima:
614
0
                                tmp_[0] = (std::abs(S_[1]-S_[0])*2*S_[0]*S_[1]+std::abs(2*S_[0]*S_[1]-4*S_[0]*S_[0]*S_[1])*S_[0])/(std::abs(S_[1]-S_[0])+std::abs(2*S_[0]*S_[1]-4*S_[0]*S_[0]*S_[1]));
615
0
                                tmp_[1] = (std::abs(S_[2]-S_[1])*S_[0]+std::abs(S_[0]-2*S_[0]*S_[1])*S_[1])/(std::abs(S_[2]-S_[1])+std::abs(S_[0]-2*S_[0]*S_[1]));
616
0
                                for (Size i=2; i<n_-2; ++i) {
617
0
                                    if ((S_[i-2]==S_[i-1]) && (S_[i]!=S_[i+1]))
618
0
                                        tmp_[i] = S_[i-1];
619
0
                                    else if ((S_[i-2]!=S_[i-1]) && (S_[i]==S_[i+1]))
620
0
                                        tmp_[i] = S_[i];
621
0
                                    else if (S_[i]==S_[i-1])
622
0
                                        tmp_[i] = S_[i];
623
0
                                    else if ((S_[i-2]==S_[i-1]) && (S_[i-1]!=S_[i]) && (S_[i]==S_[i+1]))
624
0
                                        tmp_[i] = (S_[i-1]+S_[i])/2.0;
625
0
                                    else
626
0
                                        tmp_[i] = (std::abs(S_[i+1]-S_[i])*S_[i-1]+std::abs(S_[i-1]-S_[i-2])*S_[i])/(std::abs(S_[i+1]-S_[i])+std::abs(S_[i-1]-S_[i-2]));
627
0
                                 }
628
0
                                 tmp_[n_-2] = (std::abs(2*S_[n_-2]*S_[n_-3]-S_[n_-2])*S_[n_-3]+std::abs(S_[n_-3]-S_[n_-4])*S_[n_-2])/(std::abs(2*S_[n_-2]*S_[n_-3]-S_[n_-2])+std::abs(S_[n_-3]-S_[n_-4]));
629
0
                                 tmp_[n_-1] = (std::abs(4*S_[n_-2]*S_[n_-2]*S_[n_-3]-2*S_[n_-2]*S_[n_-3])*S_[n_-2]+std::abs(S_[n_-2]-S_[n_-3])*2*S_[n_-2]*S_[n_-3])/(std::abs(4*S_[n_-2]*S_[n_-2]*S_[n_-3]-2*S_[n_-2]*S_[n_-3])+std::abs(S_[n_-2]-S_[n_-3]));
630
0
                                 break;
631
0
                            case CubicInterpolation::Kruger:
632
                                // intermediate points
633
0
                                for (Size i=1; i<n_-1; ++i) {
634
0
                                    if (S_[i-1]*S_[i]<0.0)
635
                                        // slope changes sign at point
636
0
                                        tmp_[i] = 0.0;
637
0
                                    else
638
                                        // slope will be between the slopes of the adjacent
639
                                        // straight lines and should approach zero if the
640
                                        // slope of either line approaches zero
641
0
                                        tmp_[i] = 2.0/(1.0/S_[i-1]+1.0/S_[i]);
642
0
                                }
643
                                // end points
644
0
                                tmp_[0] = (3.0*S_[0]-tmp_[1])/2.0;
645
0
                                tmp_[n_-1] = (3.0*S_[n_-2]-tmp_[n_-2])/2.0;
646
0
                                break;
647
0
                            case CubicInterpolation::Harmonic:
648
                                // intermediate points
649
0
                                for (Size i=1; i<n_-1; ++i) {
650
0
                                    Real w1 = 2*dx_[i]+dx_[i-1];
651
0
                                    Real w2 = dx_[i]+2*dx_[i-1];
652
0
                                    if (S_[i-1]*S_[i]<=0.0)
653
                                        // slope changes sign at point
654
0
                                        tmp_[i] = 0.0;
655
0
                                    else
656
                                        // weighted harmonic mean of S_[i] and S_[i-1] if they
657
                                        // have the same sign; otherwise 0
658
0
                                        tmp_[i] = (w1+w2)/(w1/S_[i-1]+w2/S_[i]);
659
0
                                }
660
                                // end points [0]
661
0
                                tmp_[0] = ((2 * dx_[0] + dx_[1])*S_[0] - dx_[0] * S_[1]) / (dx_[1] + dx_[0]);
662
0
                                if (tmp_[0]*S_[0]<0.0) {
663
0
                                    tmp_[0] = 0;
664
0
                                }
665
0
                                else if (S_[0]*S_[1]<0) {
666
0
                                    if (std::fabs(tmp_[0])>std::fabs(3*S_[0])) {
667
0
                                            tmp_[0] = 3*S_[0];
668
0
                                    }
669
0
                                }
670
                                // end points [n-1]
671
0
                                tmp_[n_-1] = ((2*dx_[n_-2]+dx_[n_-3])*S_[n_-2]-dx_[n_-2]*S_[n_-3])/(dx_[n_-3]+dx_[n_-2]);
672
0
                                if (tmp_[n_-1]*S_[n_-2]<0.0) {
673
0
                                    tmp_[n_-1] = 0;
674
0
                                }
675
0
                                else if (S_[n_-2]*S_[n_-3]<0) {
676
0
                                    if (std::fabs(tmp_[n_-1])>std::fabs(3*S_[n_-2])) {
677
0
                                        tmp_[n_-1] = 3*S_[n_-2];
678
0
                                    }
679
0
                                }
680
0
                                break;
681
0
                            default:
682
0
                                QL_FAIL("unknown scheme");
683
0
                        }
684
0
                    }
685
0
                }
686
687
6.90k
                auto& monotonicityAdjustments = this->monotonicityAdjustments_;
688
6.90k
                std::fill(monotonicityAdjustments.begin(),
689
6.90k
                          monotonicityAdjustments.end(), false);
690
                // Hyman monotonicity constrained filter
691
6.90k
                if (monotonic_) {
692
6.78k
                    Real correction;
693
6.78k
                    Real pm, pu, pd, M;
694
461k
                    for (Size i=0; i<n_; ++i) {
695
454k
                        if (i==0) {
696
6.78k
                            if (tmp_[i]*S_[0]>0.0) {
697
5.62k
                                correction = tmp_[i]/std::fabs(tmp_[i]) *
698
5.62k
                                    std::min<Real>(std::fabs(tmp_[i]),
699
5.62k
                                                   std::fabs(3.0*S_[0]));
700
5.62k
                            } else {
701
1.16k
                                correction = 0.0;
702
1.16k
                            }
703
6.78k
                            if (correction!=tmp_[i]) {
704
692
                                tmp_[i] = correction;
705
692
                                monotonicityAdjustments[i] = true;
706
692
                            }
707
448k
                        } else if (i==n_-1) {
708
6.78k
                            if (tmp_[i]*S_[n_-2]>0.0) {
709
5.81k
                                correction = tmp_[i]/std::fabs(tmp_[i]) *
710
5.81k
                                    std::min<Real>(std::fabs(tmp_[i]),
711
5.81k
                                                   std::fabs(3.0*S_[n_-2]));
712
5.81k
                            } else {
713
968
                                correction = 0.0;
714
968
                            }
715
6.78k
                            if (correction!=tmp_[i]) {
716
283
                                tmp_[i] = correction;
717
283
                                monotonicityAdjustments[i] = true;
718
283
                            }
719
441k
                        } else {
720
441k
                            pm=(S_[i-1]*dx_[i]+S_[i]*dx_[i-1])/
721
441k
                                (dx_[i-1]+dx_[i]);
722
441k
                            M = 3.0 * std::min({
723
441k
                                    std::fabs(S_[i-1]),
724
441k
                                    std::fabs(S_[i]),
725
441k
                                    std::fabs(pm)
726
441k
                                });
727
441k
                            if (i>1) {
728
434k
                                if ((S_[i-1]-S_[i-2])*(S_[i]-S_[i-1])>0.0) {
729
346k
                                    pd=(S_[i-1]*(2.0*dx_[i-1]+dx_[i-2])
730
346k
                                        -S_[i-2]*dx_[i-1])/
731
346k
                                        (dx_[i-2]+dx_[i-1]);
732
346k
                                    if (pm*pd>0.0 && pm*(S_[i-1]-S_[i-2])>0.0) {
733
268k
                                        M = std::max<Real>(M, 1.5*std::min(
734
268k
                                                std::fabs(pm),std::fabs(pd)));
735
268k
                                    }
736
346k
                                }
737
434k
                            }
738
441k
                            if (i<n_-2) {
739
434k
                                if ((S_[i]-S_[i-1])*(S_[i+1]-S_[i])>0.0) {
740
346k
                                    pu=(S_[i]*(2.0*dx_[i]+dx_[i+1])-S_[i+1]*dx_[i])/
741
346k
                                        (dx_[i]+dx_[i+1]);
742
346k
                                    if (pm*pu>0.0 && -pm*(S_[i]-S_[i-1])>0.0) {
743
80.1k
                                        M = std::max<Real>(M, 1.5*std::min(
744
80.1k
                                                std::fabs(pm),std::fabs(pu)));
745
80.1k
                                    }
746
346k
                                }
747
434k
                            }
748
441k
                            if (tmp_[i]*pm>0.0) {
749
377k
                                correction = tmp_[i]/std::fabs(tmp_[i]) *
750
377k
                                    std::min(std::fabs(tmp_[i]), M);
751
377k
                            } else {
752
64.1k
                                correction = 0.0;
753
64.1k
                            }
754
441k
                            if (correction!=tmp_[i]) {
755
44.4k
                                tmp_[i] = correction;
756
44.4k
                                monotonicityAdjustments[i] = true;
757
44.4k
                            }
758
441k
                        }
759
454k
                    }
760
6.78k
                }
761
762
763
                // cubic coefficients
764
456k
                for (Size i=0; i<n_-1; ++i) {
765
449k
                    this->a_[i] = tmp_[i];
766
449k
                    this->b_[i] = (3.0*S_[i] - tmp_[i+1] - 2.0*tmp_[i])/dx_[i];
767
449k
                    this->c_[i] = (tmp_[i+1] + tmp_[i] - 2.0*S_[i])/(dx_[i]*dx_[i]);
768
449k
                }
769
770
6.90k
                auto& primitiveConst = this->primitiveConst_;
771
6.90k
                primitiveConst[0] = 0.0;
772
449k
                for (Size i=1; i<n_-1; ++i) {
773
442k
                    primitiveConst[i] = primitiveConst[i-1]
774
442k
                        + dx_[i-1] *
775
442k
                        (this->yBegin_[i-1] + dx_[i-1] *
776
442k
                         (this->a_[i-1]/2.0 + dx_[i-1] *
777
442k
                          (this->b_[i-1]/3.0 + dx_[i-1] * this->c_[i-1]/4.0)));
778
442k
                }
779
6.90k
            }
QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*> >::update()
Line
Count
Source
410
122
            void update() override {
411
412
1.35k
                for (Size i=0; i<n_-1; ++i) {
413
1.23k
                    dx_[i] = this->xBegin_[i+1] - this->xBegin_[i];
414
1.23k
                    S_[i] = (this->yBegin_[i+1] - this->yBegin_[i])/dx_[i];
415
1.23k
                }
416
417
                // first derivative approximation
418
122
                if (da_==CubicInterpolation::Spline) {
419
1.23k
                    for (Size i=1; i<n_-1; ++i) {
420
1.11k
                        L_.setMidRow(i, dx_[i], 2.0*(dx_[i]+dx_[i-1]), dx_[i-1]);
421
1.11k
                        tmp_[i] = 3.0*(dx_[i]*S_[i-1] + dx_[i-1]*S_[i]);
422
1.11k
                    }
423
424
                    // left boundary condition
425
122
                    switch (leftType_) {
426
0
                      case CubicInterpolation::NotAKnot:
427
                        // ignoring end condition value
428
0
                        L_.setFirstRow(dx_[1]*(dx_[1]+dx_[0]),
429
0
                                      (dx_[0]+dx_[1])*(dx_[0]+dx_[1]));
430
0
                        tmp_[0] = S_[0]*dx_[1]*(2.0*dx_[1]+3.0*dx_[0]) +
431
0
                                 S_[1]*dx_[0]*dx_[0];
432
0
                        break;
433
0
                      case CubicInterpolation::FirstDerivative:
434
0
                        L_.setFirstRow(1.0, 0.0);
435
0
                        tmp_[0] = this->leftValue_;
436
0
                        break;
437
122
                      case CubicInterpolation::SecondDerivative:
438
122
                        L_.setFirstRow(2.0, 1.0);
439
122
                        tmp_[0] = 3.0*S_[0] - this->leftValue_*dx_[0]/2.0;
440
122
                        break;
441
0
                      case CubicInterpolation::Periodic:
442
0
                        QL_FAIL("this end condition is not implemented yet");
443
0
                      case CubicInterpolation::Lagrange:
444
0
                        L_.setFirstRow(1.0, 0.0);
445
0
                        tmp_[0] = cubicInterpolatingPolynomialDerivative(
446
0
                                            this->xBegin_[0],this->xBegin_[1],
447
0
                                            this->xBegin_[2],this->xBegin_[3],
448
0
                                            this->yBegin_[0],this->yBegin_[1],
449
0
                                            this->yBegin_[2],this->yBegin_[3],
450
0
                                            this->xBegin_[0]);
451
0
                        break;
452
0
                      default:
453
0
                        QL_FAIL("unknown end condition");
454
122
                    }
455
456
                    // right boundary condition
457
122
                    switch (rightType_) {
458
0
                      case CubicInterpolation::NotAKnot:
459
                        // ignoring end condition value
460
0
                        L_.setLastRow(-(dx_[n_-2]+dx_[n_-3])*(dx_[n_-2]+dx_[n_-3]),
461
0
                                     -dx_[n_-3]*(dx_[n_-3]+dx_[n_-2]));
462
0
                        tmp_[n_-1] = -S_[n_-3]*dx_[n_-2]*dx_[n_-2] -
463
0
                                     S_[n_-2]*dx_[n_-3]*(3.0*dx_[n_-2]+2.0*dx_[n_-3]);
464
0
                        break;
465
0
                      case CubicInterpolation::FirstDerivative:
466
0
                        L_.setLastRow(0.0, 1.0);
467
0
                        tmp_[n_-1] = this->rightValue_;
468
0
                        break;
469
122
                      case CubicInterpolation::SecondDerivative:
470
122
                        L_.setLastRow(1.0, 2.0);
471
122
                        tmp_[n_-1] = 3.0*S_[n_-2] + this->rightValue_*dx_[n_-2]/2.0;
472
122
                        break;
473
0
                      case CubicInterpolation::Periodic:
474
0
                        QL_FAIL("this end condition is not implemented yet");
475
0
                      case CubicInterpolation::Lagrange:
476
0
                        L_.setLastRow(0.0,1.0);
477
0
                        tmp_[n_-1] = cubicInterpolatingPolynomialDerivative(
478
0
                                      this->xBegin_[n_-4],this->xBegin_[n_-3],
479
0
                                      this->xBegin_[n_-2],this->xBegin_[n_-1],
480
0
                                      this->yBegin_[n_-4],this->yBegin_[n_-3],
481
0
                                      this->yBegin_[n_-2],this->yBegin_[n_-1],
482
0
                                      this->xBegin_[n_-1]);
483
0
                        break;
484
0
                      default:
485
0
                        QL_FAIL("unknown end condition");
486
122
                    }
487
488
                    // solve the system
489
122
                    L_.solveFor(tmp_, tmp_);
490
122
                } else if (da_==CubicInterpolation::SplineOM1) {
491
0
                    Matrix T_(n_-2, n_, 0.0);
492
0
                    for (Size i=0; i<n_-2; ++i) {
493
0
                        T_[i][i]=dx_[i]/6.0;
494
0
                        T_[i][i+1]=(dx_[i+1]+dx_[i])/3.0;
495
0
                        T_[i][i+2]=dx_[i+1]/6.0;
496
0
                    }
497
0
                    Matrix S_(n_-2, n_, 0.0);
498
0
                    for (Size i=0; i<n_-2; ++i) {
499
0
                        S_[i][i]=1.0/dx_[i];
500
0
                        S_[i][i+1]=-(1.0/dx_[i+1]+1.0/dx_[i]);
501
0
                        S_[i][i+2]=1.0/dx_[i+1];
502
0
                    }
503
0
                    Matrix Up_(n_, 2, 0.0);
504
0
                    Up_[0][0]=1;
505
0
                    Up_[n_-1][1]=1;
506
0
                    Matrix Us_(n_, n_-2, 0.0);
507
0
                    for (Size i=0; i<n_-2; ++i)
508
0
                        Us_[i+1][i]=1;
509
0
                    Matrix Z_ = Us_*inverse(T_*Us_);
510
0
                    Matrix I_(n_, n_, 0.0);
511
0
                    for (Size i=0; i<n_; ++i)
512
0
                        I_[i][i]=1;
513
0
                    Matrix V_ = (I_-Z_*T_)*Up_;
514
0
                    Matrix W_ = Z_*S_;
515
0
                    Matrix Q_(n_, n_, 0.0);
516
0
                    Q_[0][0]=1.0/(n_-1)*dx_[0]*dx_[0]*dx_[0];
517
0
                    Q_[0][1]=7.0/8*1.0/(n_-1)*dx_[0]*dx_[0]*dx_[0];
518
0
                    for (Size i=1; i<n_-1; ++i) {
519
0
                        Q_[i][i-1]=7.0/8*1.0/(n_-1)*dx_[i-1]*dx_[i-1]*dx_[i-1];
520
0
                        Q_[i][i]=1.0/(n_-1)*dx_[i]*dx_[i]*dx_[i]+1.0/(n_-1)*dx_[i-1]*dx_[i-1]*dx_[i-1];
521
0
                        Q_[i][i+1]=7.0/8*1.0/(n_-1)*dx_[i]*dx_[i]*dx_[i];
522
0
                    }
523
0
                    Q_[n_-1][n_-2]=7.0/8*1.0/(n_-1)*dx_[n_-2]*dx_[n_-2]*dx_[n_-2];
524
0
                    Q_[n_-1][n_-1]=1.0/(n_-1)*dx_[n_-2]*dx_[n_-2]*dx_[n_-2];
525
0
                    Matrix J_ = (I_-V_*inverse(transpose(V_)*Q_*V_)*transpose(V_)*Q_)*W_;
526
0
                    Array Y_(n_);
527
0
                    for (Size i=0; i<n_; ++i)
528
0
                        Y_[i]=this->yBegin_[i];
529
0
                    Array D_ = J_*Y_;
530
0
                    for (Size i=0; i<n_-1; ++i)
531
0
                        tmp_[i]=(Y_[i+1]-Y_[i])/dx_[i]-(2.0*D_[i]+D_[i+1])*dx_[i]/6.0;
532
0
                    tmp_[n_-1]=tmp_[n_-2]+D_[n_-2]*dx_[n_-2]+(D_[n_-1]-D_[n_-2])*dx_[n_-2]/2.0;
533
534
0
                } else if (da_==CubicInterpolation::SplineOM2) {
535
0
                    Matrix T_(n_-2, n_, 0.0);
536
0
                    for (Size i=0; i<n_-2; ++i) {
537
0
                        T_[i][i]=dx_[i]/6.0;
538
0
                        T_[i][i+1]=(dx_[i]+dx_[i+1])/3.0;
539
0
                        T_[i][i+2]=dx_[i+1]/6.0;
540
0
                    }
541
0
                    Matrix S_(n_-2, n_, 0.0);
542
0
                    for (Size i=0; i<n_-2; ++i) {
543
0
                        S_[i][i]=1.0/dx_[i];
544
0
                        S_[i][i+1]=-(1.0/dx_[i+1]+1.0/dx_[i]);
545
0
                        S_[i][i+2]=1.0/dx_[i+1];
546
0
                    }
547
0
                    Matrix Up_(n_, 2, 0.0);
548
0
                    Up_[0][0]=1;
549
0
                    Up_[n_-1][1]=1;
550
0
                    Matrix Us_(n_, n_-2, 0.0);
551
0
                    for (Size i=0; i<n_-2; ++i)
552
0
                        Us_[i+1][i]=1;
553
0
                    Matrix Z_ = Us_*inverse(T_*Us_);
554
0
                    Matrix I_(n_, n_, 0.0);
555
0
                    for (Size i=0; i<n_; ++i)
556
0
                        I_[i][i]=1;
557
0
                    Matrix V_ = (I_-Z_*T_)*Up_;
558
0
                    Matrix W_ = Z_*S_;
559
0
                    Matrix Q_(n_, n_, 0.0);
560
0
                    Q_[0][0]=1.0/(n_-1)*dx_[0];
561
0
                    Q_[0][1]=1.0/2*1.0/(n_-1)*dx_[0];
562
0
                    for (Size i=1; i<n_-1; ++i) {
563
0
                        Q_[i][i-1]=1.0/2*1.0/(n_-1)*dx_[i-1];
564
0
                        Q_[i][i]=1.0/(n_-1)*dx_[i]+1.0/(n_-1)*dx_[i-1];
565
0
                        Q_[i][i+1]=1.0/2*1.0/(n_-1)*dx_[i];
566
0
                    }
567
0
                    Q_[n_-1][n_-2]=1.0/2*1.0/(n_-1)*dx_[n_-2];
568
0
                    Q_[n_-1][n_-1]=1.0/(n_-1)*dx_[n_-2];
569
0
                    Matrix J_ = (I_-V_*inverse(transpose(V_)*Q_*V_)*transpose(V_)*Q_)*W_;
570
0
                    Array Y_(n_);
571
0
                    for (Size i=0; i<n_; ++i)
572
0
                        Y_[i]=this->yBegin_[i];
573
0
                    Array D_ = J_*Y_;
574
0
                    for (Size i=0; i<n_-1; ++i)
575
0
                        tmp_[i]=(Y_[i+1]-Y_[i])/dx_[i]-(2.0*D_[i]+D_[i+1])*dx_[i]/6.0;
576
0
                    tmp_[n_-1]=tmp_[n_-2]+D_[n_-2]*dx_[n_-2]+(D_[n_-1]-D_[n_-2])*dx_[n_-2]/2.0;
577
0
                } else { // local schemes
578
0
                    if (n_==2)
579
0
                        tmp_[0] = tmp_[1] = S_[0];
580
0
                    else {
581
0
                        switch (da_) {
582
0
                            case CubicInterpolation::FourthOrder:
583
0
                                QL_FAIL("FourthOrder not implemented yet");
584
0
                                break;
585
0
                            case CubicInterpolation::Parabolic:
586
                                // intermediate points
587
0
                                for (Size i=1; i<n_-1; ++i)
588
0
                                    tmp_[i] = (dx_[i-1]*S_[i]+dx_[i]*S_[i-1])/(dx_[i]+dx_[i-1]);
589
                                // end points
590
0
                                tmp_[0]    = ((2.0*dx_[   0]+dx_[   1])*S_[   0] - dx_[   0]*S_[   1]) / (dx_[   0]+dx_[   1]);
591
0
                                tmp_[n_-1] = ((2.0*dx_[n_-2]+dx_[n_-3])*S_[n_-2] - dx_[n_-2]*S_[n_-3]) / (dx_[n_-2]+dx_[n_-3]);
592
0
                                break;
593
0
                            case CubicInterpolation::FritschButland:
594
                                // intermediate points
595
0
                                for (Size i=1; i<n_-1; ++i) {
596
0
                                    Real Smin = std::min(S_[i-1], S_[i]);
597
0
                                    Real Smax = std::max(S_[i-1], S_[i]);
598
0
                                    if(Smax+2.0*Smin == 0){
599
0
                                        if (Smin*Smax < 0)
600
0
                                            tmp_[i] = QL_MIN_REAL;
601
0
                                        else if (Smin*Smax == 0)
602
0
                                            tmp_[i] = 0;
603
0
                                        else
604
0
                                            tmp_[i] = QL_MAX_REAL;
605
0
                                    }
606
0
                                    else
607
0
                                        tmp_[i] = 3.0*Smin*Smax/(Smax+2.0*Smin);
608
0
                                }
609
                                // end points
610
0
                                tmp_[0]    = ((2.0*dx_[   0]+dx_[   1])*S_[   0] - dx_[   0]*S_[   1]) / (dx_[   0]+dx_[   1]);
611
0
                                tmp_[n_-1] = ((2.0*dx_[n_-2]+dx_[n_-3])*S_[n_-2] - dx_[n_-2]*S_[n_-3]) / (dx_[n_-2]+dx_[n_-3]);
612
0
                                break;
613
0
                            case CubicInterpolation::Akima:
614
0
                                tmp_[0] = (std::abs(S_[1]-S_[0])*2*S_[0]*S_[1]+std::abs(2*S_[0]*S_[1]-4*S_[0]*S_[0]*S_[1])*S_[0])/(std::abs(S_[1]-S_[0])+std::abs(2*S_[0]*S_[1]-4*S_[0]*S_[0]*S_[1]));
615
0
                                tmp_[1] = (std::abs(S_[2]-S_[1])*S_[0]+std::abs(S_[0]-2*S_[0]*S_[1])*S_[1])/(std::abs(S_[2]-S_[1])+std::abs(S_[0]-2*S_[0]*S_[1]));
616
0
                                for (Size i=2; i<n_-2; ++i) {
617
0
                                    if ((S_[i-2]==S_[i-1]) && (S_[i]!=S_[i+1]))
618
0
                                        tmp_[i] = S_[i-1];
619
0
                                    else if ((S_[i-2]!=S_[i-1]) && (S_[i]==S_[i+1]))
620
0
                                        tmp_[i] = S_[i];
621
0
                                    else if (S_[i]==S_[i-1])
622
0
                                        tmp_[i] = S_[i];
623
0
                                    else if ((S_[i-2]==S_[i-1]) && (S_[i-1]!=S_[i]) && (S_[i]==S_[i+1]))
624
0
                                        tmp_[i] = (S_[i-1]+S_[i])/2.0;
625
0
                                    else
626
0
                                        tmp_[i] = (std::abs(S_[i+1]-S_[i])*S_[i-1]+std::abs(S_[i-1]-S_[i-2])*S_[i])/(std::abs(S_[i+1]-S_[i])+std::abs(S_[i-1]-S_[i-2]));
627
0
                                 }
628
0
                                 tmp_[n_-2] = (std::abs(2*S_[n_-2]*S_[n_-3]-S_[n_-2])*S_[n_-3]+std::abs(S_[n_-3]-S_[n_-4])*S_[n_-2])/(std::abs(2*S_[n_-2]*S_[n_-3]-S_[n_-2])+std::abs(S_[n_-3]-S_[n_-4]));
629
0
                                 tmp_[n_-1] = (std::abs(4*S_[n_-2]*S_[n_-2]*S_[n_-3]-2*S_[n_-2]*S_[n_-3])*S_[n_-2]+std::abs(S_[n_-2]-S_[n_-3])*2*S_[n_-2]*S_[n_-3])/(std::abs(4*S_[n_-2]*S_[n_-2]*S_[n_-3]-2*S_[n_-2]*S_[n_-3])+std::abs(S_[n_-2]-S_[n_-3]));
630
0
                                 break;
631
0
                            case CubicInterpolation::Kruger:
632
                                // intermediate points
633
0
                                for (Size i=1; i<n_-1; ++i) {
634
0
                                    if (S_[i-1]*S_[i]<0.0)
635
                                        // slope changes sign at point
636
0
                                        tmp_[i] = 0.0;
637
0
                                    else
638
                                        // slope will be between the slopes of the adjacent
639
                                        // straight lines and should approach zero if the
640
                                        // slope of either line approaches zero
641
0
                                        tmp_[i] = 2.0/(1.0/S_[i-1]+1.0/S_[i]);
642
0
                                }
643
                                // end points
644
0
                                tmp_[0] = (3.0*S_[0]-tmp_[1])/2.0;
645
0
                                tmp_[n_-1] = (3.0*S_[n_-2]-tmp_[n_-2])/2.0;
646
0
                                break;
647
0
                            case CubicInterpolation::Harmonic:
648
                                // intermediate points
649
0
                                for (Size i=1; i<n_-1; ++i) {
650
0
                                    Real w1 = 2*dx_[i]+dx_[i-1];
651
0
                                    Real w2 = dx_[i]+2*dx_[i-1];
652
0
                                    if (S_[i-1]*S_[i]<=0.0)
653
                                        // slope changes sign at point
654
0
                                        tmp_[i] = 0.0;
655
0
                                    else
656
                                        // weighted harmonic mean of S_[i] and S_[i-1] if they
657
                                        // have the same sign; otherwise 0
658
0
                                        tmp_[i] = (w1+w2)/(w1/S_[i-1]+w2/S_[i]);
659
0
                                }
660
                                // end points [0]
661
0
                                tmp_[0] = ((2 * dx_[0] + dx_[1])*S_[0] - dx_[0] * S_[1]) / (dx_[1] + dx_[0]);
662
0
                                if (tmp_[0]*S_[0]<0.0) {
663
0
                                    tmp_[0] = 0;
664
0
                                }
665
0
                                else if (S_[0]*S_[1]<0) {
666
0
                                    if (std::fabs(tmp_[0])>std::fabs(3*S_[0])) {
667
0
                                            tmp_[0] = 3*S_[0];
668
0
                                    }
669
0
                                }
670
                                // end points [n-1]
671
0
                                tmp_[n_-1] = ((2*dx_[n_-2]+dx_[n_-3])*S_[n_-2]-dx_[n_-2]*S_[n_-3])/(dx_[n_-3]+dx_[n_-2]);
672
0
                                if (tmp_[n_-1]*S_[n_-2]<0.0) {
673
0
                                    tmp_[n_-1] = 0;
674
0
                                }
675
0
                                else if (S_[n_-2]*S_[n_-3]<0) {
676
0
                                    if (std::fabs(tmp_[n_-1])>std::fabs(3*S_[n_-2])) {
677
0
                                        tmp_[n_-1] = 3*S_[n_-2];
678
0
                                    }
679
0
                                }
680
0
                                break;
681
0
                            default:
682
0
                                QL_FAIL("unknown scheme");
683
0
                        }
684
0
                    }
685
0
                }
686
687
122
                auto& monotonicityAdjustments = this->monotonicityAdjustments_;
688
122
                std::fill(monotonicityAdjustments.begin(),
689
122
                          monotonicityAdjustments.end(), false);
690
                // Hyman monotonicity constrained filter
691
122
                if (monotonic_) {
692
0
                    Real correction;
693
0
                    Real pm, pu, pd, M;
694
0
                    for (Size i=0; i<n_; ++i) {
695
0
                        if (i==0) {
696
0
                            if (tmp_[i]*S_[0]>0.0) {
697
0
                                correction = tmp_[i]/std::fabs(tmp_[i]) *
698
0
                                    std::min<Real>(std::fabs(tmp_[i]),
699
0
                                                   std::fabs(3.0*S_[0]));
700
0
                            } else {
701
0
                                correction = 0.0;
702
0
                            }
703
0
                            if (correction!=tmp_[i]) {
704
0
                                tmp_[i] = correction;
705
0
                                monotonicityAdjustments[i] = true;
706
0
                            }
707
0
                        } else if (i==n_-1) {
708
0
                            if (tmp_[i]*S_[n_-2]>0.0) {
709
0
                                correction = tmp_[i]/std::fabs(tmp_[i]) *
710
0
                                    std::min<Real>(std::fabs(tmp_[i]),
711
0
                                                   std::fabs(3.0*S_[n_-2]));
712
0
                            } else {
713
0
                                correction = 0.0;
714
0
                            }
715
0
                            if (correction!=tmp_[i]) {
716
0
                                tmp_[i] = correction;
717
0
                                monotonicityAdjustments[i] = true;
718
0
                            }
719
0
                        } else {
720
0
                            pm=(S_[i-1]*dx_[i]+S_[i]*dx_[i-1])/
721
0
                                (dx_[i-1]+dx_[i]);
722
0
                            M = 3.0 * std::min({
723
0
                                    std::fabs(S_[i-1]),
724
0
                                    std::fabs(S_[i]),
725
0
                                    std::fabs(pm)
726
0
                                });
727
0
                            if (i>1) {
728
0
                                if ((S_[i-1]-S_[i-2])*(S_[i]-S_[i-1])>0.0) {
729
0
                                    pd=(S_[i-1]*(2.0*dx_[i-1]+dx_[i-2])
730
0
                                        -S_[i-2]*dx_[i-1])/
731
0
                                        (dx_[i-2]+dx_[i-1]);
732
0
                                    if (pm*pd>0.0 && pm*(S_[i-1]-S_[i-2])>0.0) {
733
0
                                        M = std::max<Real>(M, 1.5*std::min(
734
0
                                                std::fabs(pm),std::fabs(pd)));
735
0
                                    }
736
0
                                }
737
0
                            }
738
0
                            if (i<n_-2) {
739
0
                                if ((S_[i]-S_[i-1])*(S_[i+1]-S_[i])>0.0) {
740
0
                                    pu=(S_[i]*(2.0*dx_[i]+dx_[i+1])-S_[i+1]*dx_[i])/
741
0
                                        (dx_[i]+dx_[i+1]);
742
0
                                    if (pm*pu>0.0 && -pm*(S_[i]-S_[i-1])>0.0) {
743
0
                                        M = std::max<Real>(M, 1.5*std::min(
744
0
                                                std::fabs(pm),std::fabs(pu)));
745
0
                                    }
746
0
                                }
747
0
                            }
748
0
                            if (tmp_[i]*pm>0.0) {
749
0
                                correction = tmp_[i]/std::fabs(tmp_[i]) *
750
0
                                    std::min(std::fabs(tmp_[i]), M);
751
0
                            } else {
752
0
                                correction = 0.0;
753
0
                            }
754
0
                            if (correction!=tmp_[i]) {
755
0
                                tmp_[i] = correction;
756
0
                                monotonicityAdjustments[i] = true;
757
0
                            }
758
0
                        }
759
0
                    }
760
0
                }
761
762
763
                // cubic coefficients
764
1.35k
                for (Size i=0; i<n_-1; ++i) {
765
1.23k
                    this->a_[i] = tmp_[i];
766
1.23k
                    this->b_[i] = (3.0*S_[i] - tmp_[i+1] - 2.0*tmp_[i])/dx_[i];
767
1.23k
                    this->c_[i] = (tmp_[i+1] + tmp_[i] - 2.0*S_[i])/(dx_[i]*dx_[i]);
768
1.23k
                }
769
770
122
                auto& primitiveConst = this->primitiveConst_;
771
122
                primitiveConst[0] = 0.0;
772
1.23k
                for (Size i=1; i<n_-1; ++i) {
773
1.11k
                    primitiveConst[i] = primitiveConst[i-1]
774
1.11k
                        + dx_[i-1] *
775
1.11k
                        (this->yBegin_[i-1] + dx_[i-1] *
776
1.11k
                         (this->a_[i-1]/2.0 + dx_[i-1] *
777
1.11k
                          (this->b_[i-1]/3.0 + dx_[i-1] * this->c_[i-1]/4.0)));
778
1.11k
                }
779
122
            }
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double*>, double const*>::update()
QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, double*>::update()
Line
Count
Source
410
6.78k
            void update() override {
411
412
454k
                for (Size i=0; i<n_-1; ++i) {
413
448k
                    dx_[i] = this->xBegin_[i+1] - this->xBegin_[i];
414
448k
                    S_[i] = (this->yBegin_[i+1] - this->yBegin_[i])/dx_[i];
415
448k
                }
416
417
                // first derivative approximation
418
6.78k
                if (da_==CubicInterpolation::Spline) {
419
448k
                    for (Size i=1; i<n_-1; ++i) {
420
441k
                        L_.setMidRow(i, dx_[i], 2.0*(dx_[i]+dx_[i-1]), dx_[i-1]);
421
441k
                        tmp_[i] = 3.0*(dx_[i]*S_[i-1] + dx_[i-1]*S_[i]);
422
441k
                    }
423
424
                    // left boundary condition
425
6.78k
                    switch (leftType_) {
426
0
                      case CubicInterpolation::NotAKnot:
427
                        // ignoring end condition value
428
0
                        L_.setFirstRow(dx_[1]*(dx_[1]+dx_[0]),
429
0
                                      (dx_[0]+dx_[1])*(dx_[0]+dx_[1]));
430
0
                        tmp_[0] = S_[0]*dx_[1]*(2.0*dx_[1]+3.0*dx_[0]) +
431
0
                                 S_[1]*dx_[0]*dx_[0];
432
0
                        break;
433
0
                      case CubicInterpolation::FirstDerivative:
434
0
                        L_.setFirstRow(1.0, 0.0);
435
0
                        tmp_[0] = this->leftValue_;
436
0
                        break;
437
6.78k
                      case CubicInterpolation::SecondDerivative:
438
6.78k
                        L_.setFirstRow(2.0, 1.0);
439
6.78k
                        tmp_[0] = 3.0*S_[0] - this->leftValue_*dx_[0]/2.0;
440
6.78k
                        break;
441
0
                      case CubicInterpolation::Periodic:
442
0
                        QL_FAIL("this end condition is not implemented yet");
443
0
                      case CubicInterpolation::Lagrange:
444
0
                        L_.setFirstRow(1.0, 0.0);
445
0
                        tmp_[0] = cubicInterpolatingPolynomialDerivative(
446
0
                                            this->xBegin_[0],this->xBegin_[1],
447
0
                                            this->xBegin_[2],this->xBegin_[3],
448
0
                                            this->yBegin_[0],this->yBegin_[1],
449
0
                                            this->yBegin_[2],this->yBegin_[3],
450
0
                                            this->xBegin_[0]);
451
0
                        break;
452
0
                      default:
453
0
                        QL_FAIL("unknown end condition");
454
6.78k
                    }
455
456
                    // right boundary condition
457
6.78k
                    switch (rightType_) {
458
0
                      case CubicInterpolation::NotAKnot:
459
                        // ignoring end condition value
460
0
                        L_.setLastRow(-(dx_[n_-2]+dx_[n_-3])*(dx_[n_-2]+dx_[n_-3]),
461
0
                                     -dx_[n_-3]*(dx_[n_-3]+dx_[n_-2]));
462
0
                        tmp_[n_-1] = -S_[n_-3]*dx_[n_-2]*dx_[n_-2] -
463
0
                                     S_[n_-2]*dx_[n_-3]*(3.0*dx_[n_-2]+2.0*dx_[n_-3]);
464
0
                        break;
465
0
                      case CubicInterpolation::FirstDerivative:
466
0
                        L_.setLastRow(0.0, 1.0);
467
0
                        tmp_[n_-1] = this->rightValue_;
468
0
                        break;
469
6.78k
                      case CubicInterpolation::SecondDerivative:
470
6.78k
                        L_.setLastRow(1.0, 2.0);
471
6.78k
                        tmp_[n_-1] = 3.0*S_[n_-2] + this->rightValue_*dx_[n_-2]/2.0;
472
6.78k
                        break;
473
0
                      case CubicInterpolation::Periodic:
474
0
                        QL_FAIL("this end condition is not implemented yet");
475
0
                      case CubicInterpolation::Lagrange:
476
0
                        L_.setLastRow(0.0,1.0);
477
0
                        tmp_[n_-1] = cubicInterpolatingPolynomialDerivative(
478
0
                                      this->xBegin_[n_-4],this->xBegin_[n_-3],
479
0
                                      this->xBegin_[n_-2],this->xBegin_[n_-1],
480
0
                                      this->yBegin_[n_-4],this->yBegin_[n_-3],
481
0
                                      this->yBegin_[n_-2],this->yBegin_[n_-1],
482
0
                                      this->xBegin_[n_-1]);
483
0
                        break;
484
0
                      default:
485
0
                        QL_FAIL("unknown end condition");
486
6.78k
                    }
487
488
                    // solve the system
489
6.78k
                    L_.solveFor(tmp_, tmp_);
490
6.78k
                } else if (da_==CubicInterpolation::SplineOM1) {
491
0
                    Matrix T_(n_-2, n_, 0.0);
492
0
                    for (Size i=0; i<n_-2; ++i) {
493
0
                        T_[i][i]=dx_[i]/6.0;
494
0
                        T_[i][i+1]=(dx_[i+1]+dx_[i])/3.0;
495
0
                        T_[i][i+2]=dx_[i+1]/6.0;
496
0
                    }
497
0
                    Matrix S_(n_-2, n_, 0.0);
498
0
                    for (Size i=0; i<n_-2; ++i) {
499
0
                        S_[i][i]=1.0/dx_[i];
500
0
                        S_[i][i+1]=-(1.0/dx_[i+1]+1.0/dx_[i]);
501
0
                        S_[i][i+2]=1.0/dx_[i+1];
502
0
                    }
503
0
                    Matrix Up_(n_, 2, 0.0);
504
0
                    Up_[0][0]=1;
505
0
                    Up_[n_-1][1]=1;
506
0
                    Matrix Us_(n_, n_-2, 0.0);
507
0
                    for (Size i=0; i<n_-2; ++i)
508
0
                        Us_[i+1][i]=1;
509
0
                    Matrix Z_ = Us_*inverse(T_*Us_);
510
0
                    Matrix I_(n_, n_, 0.0);
511
0
                    for (Size i=0; i<n_; ++i)
512
0
                        I_[i][i]=1;
513
0
                    Matrix V_ = (I_-Z_*T_)*Up_;
514
0
                    Matrix W_ = Z_*S_;
515
0
                    Matrix Q_(n_, n_, 0.0);
516
0
                    Q_[0][0]=1.0/(n_-1)*dx_[0]*dx_[0]*dx_[0];
517
0
                    Q_[0][1]=7.0/8*1.0/(n_-1)*dx_[0]*dx_[0]*dx_[0];
518
0
                    for (Size i=1; i<n_-1; ++i) {
519
0
                        Q_[i][i-1]=7.0/8*1.0/(n_-1)*dx_[i-1]*dx_[i-1]*dx_[i-1];
520
0
                        Q_[i][i]=1.0/(n_-1)*dx_[i]*dx_[i]*dx_[i]+1.0/(n_-1)*dx_[i-1]*dx_[i-1]*dx_[i-1];
521
0
                        Q_[i][i+1]=7.0/8*1.0/(n_-1)*dx_[i]*dx_[i]*dx_[i];
522
0
                    }
523
0
                    Q_[n_-1][n_-2]=7.0/8*1.0/(n_-1)*dx_[n_-2]*dx_[n_-2]*dx_[n_-2];
524
0
                    Q_[n_-1][n_-1]=1.0/(n_-1)*dx_[n_-2]*dx_[n_-2]*dx_[n_-2];
525
0
                    Matrix J_ = (I_-V_*inverse(transpose(V_)*Q_*V_)*transpose(V_)*Q_)*W_;
526
0
                    Array Y_(n_);
527
0
                    for (Size i=0; i<n_; ++i)
528
0
                        Y_[i]=this->yBegin_[i];
529
0
                    Array D_ = J_*Y_;
530
0
                    for (Size i=0; i<n_-1; ++i)
531
0
                        tmp_[i]=(Y_[i+1]-Y_[i])/dx_[i]-(2.0*D_[i]+D_[i+1])*dx_[i]/6.0;
532
0
                    tmp_[n_-1]=tmp_[n_-2]+D_[n_-2]*dx_[n_-2]+(D_[n_-1]-D_[n_-2])*dx_[n_-2]/2.0;
533
534
0
                } else if (da_==CubicInterpolation::SplineOM2) {
535
0
                    Matrix T_(n_-2, n_, 0.0);
536
0
                    for (Size i=0; i<n_-2; ++i) {
537
0
                        T_[i][i]=dx_[i]/6.0;
538
0
                        T_[i][i+1]=(dx_[i]+dx_[i+1])/3.0;
539
0
                        T_[i][i+2]=dx_[i+1]/6.0;
540
0
                    }
541
0
                    Matrix S_(n_-2, n_, 0.0);
542
0
                    for (Size i=0; i<n_-2; ++i) {
543
0
                        S_[i][i]=1.0/dx_[i];
544
0
                        S_[i][i+1]=-(1.0/dx_[i+1]+1.0/dx_[i]);
545
0
                        S_[i][i+2]=1.0/dx_[i+1];
546
0
                    }
547
0
                    Matrix Up_(n_, 2, 0.0);
548
0
                    Up_[0][0]=1;
549
0
                    Up_[n_-1][1]=1;
550
0
                    Matrix Us_(n_, n_-2, 0.0);
551
0
                    for (Size i=0; i<n_-2; ++i)
552
0
                        Us_[i+1][i]=1;
553
0
                    Matrix Z_ = Us_*inverse(T_*Us_);
554
0
                    Matrix I_(n_, n_, 0.0);
555
0
                    for (Size i=0; i<n_; ++i)
556
0
                        I_[i][i]=1;
557
0
                    Matrix V_ = (I_-Z_*T_)*Up_;
558
0
                    Matrix W_ = Z_*S_;
559
0
                    Matrix Q_(n_, n_, 0.0);
560
0
                    Q_[0][0]=1.0/(n_-1)*dx_[0];
561
0
                    Q_[0][1]=1.0/2*1.0/(n_-1)*dx_[0];
562
0
                    for (Size i=1; i<n_-1; ++i) {
563
0
                        Q_[i][i-1]=1.0/2*1.0/(n_-1)*dx_[i-1];
564
0
                        Q_[i][i]=1.0/(n_-1)*dx_[i]+1.0/(n_-1)*dx_[i-1];
565
0
                        Q_[i][i+1]=1.0/2*1.0/(n_-1)*dx_[i];
566
0
                    }
567
0
                    Q_[n_-1][n_-2]=1.0/2*1.0/(n_-1)*dx_[n_-2];
568
0
                    Q_[n_-1][n_-1]=1.0/(n_-1)*dx_[n_-2];
569
0
                    Matrix J_ = (I_-V_*inverse(transpose(V_)*Q_*V_)*transpose(V_)*Q_)*W_;
570
0
                    Array Y_(n_);
571
0
                    for (Size i=0; i<n_; ++i)
572
0
                        Y_[i]=this->yBegin_[i];
573
0
                    Array D_ = J_*Y_;
574
0
                    for (Size i=0; i<n_-1; ++i)
575
0
                        tmp_[i]=(Y_[i+1]-Y_[i])/dx_[i]-(2.0*D_[i]+D_[i+1])*dx_[i]/6.0;
576
0
                    tmp_[n_-1]=tmp_[n_-2]+D_[n_-2]*dx_[n_-2]+(D_[n_-1]-D_[n_-2])*dx_[n_-2]/2.0;
577
0
                } else { // local schemes
578
0
                    if (n_==2)
579
0
                        tmp_[0] = tmp_[1] = S_[0];
580
0
                    else {
581
0
                        switch (da_) {
582
0
                            case CubicInterpolation::FourthOrder:
583
0
                                QL_FAIL("FourthOrder not implemented yet");
584
0
                                break;
585
0
                            case CubicInterpolation::Parabolic:
586
                                // intermediate points
587
0
                                for (Size i=1; i<n_-1; ++i)
588
0
                                    tmp_[i] = (dx_[i-1]*S_[i]+dx_[i]*S_[i-1])/(dx_[i]+dx_[i-1]);
589
                                // end points
590
0
                                tmp_[0]    = ((2.0*dx_[   0]+dx_[   1])*S_[   0] - dx_[   0]*S_[   1]) / (dx_[   0]+dx_[   1]);
591
0
                                tmp_[n_-1] = ((2.0*dx_[n_-2]+dx_[n_-3])*S_[n_-2] - dx_[n_-2]*S_[n_-3]) / (dx_[n_-2]+dx_[n_-3]);
592
0
                                break;
593
0
                            case CubicInterpolation::FritschButland:
594
                                // intermediate points
595
0
                                for (Size i=1; i<n_-1; ++i) {
596
0
                                    Real Smin = std::min(S_[i-1], S_[i]);
597
0
                                    Real Smax = std::max(S_[i-1], S_[i]);
598
0
                                    if(Smax+2.0*Smin == 0){
599
0
                                        if (Smin*Smax < 0)
600
0
                                            tmp_[i] = QL_MIN_REAL;
601
0
                                        else if (Smin*Smax == 0)
602
0
                                            tmp_[i] = 0;
603
0
                                        else
604
0
                                            tmp_[i] = QL_MAX_REAL;
605
0
                                    }
606
0
                                    else
607
0
                                        tmp_[i] = 3.0*Smin*Smax/(Smax+2.0*Smin);
608
0
                                }
609
                                // end points
610
0
                                tmp_[0]    = ((2.0*dx_[   0]+dx_[   1])*S_[   0] - dx_[   0]*S_[   1]) / (dx_[   0]+dx_[   1]);
611
0
                                tmp_[n_-1] = ((2.0*dx_[n_-2]+dx_[n_-3])*S_[n_-2] - dx_[n_-2]*S_[n_-3]) / (dx_[n_-2]+dx_[n_-3]);
612
0
                                break;
613
0
                            case CubicInterpolation::Akima:
614
0
                                tmp_[0] = (std::abs(S_[1]-S_[0])*2*S_[0]*S_[1]+std::abs(2*S_[0]*S_[1]-4*S_[0]*S_[0]*S_[1])*S_[0])/(std::abs(S_[1]-S_[0])+std::abs(2*S_[0]*S_[1]-4*S_[0]*S_[0]*S_[1]));
615
0
                                tmp_[1] = (std::abs(S_[2]-S_[1])*S_[0]+std::abs(S_[0]-2*S_[0]*S_[1])*S_[1])/(std::abs(S_[2]-S_[1])+std::abs(S_[0]-2*S_[0]*S_[1]));
616
0
                                for (Size i=2; i<n_-2; ++i) {
617
0
                                    if ((S_[i-2]==S_[i-1]) && (S_[i]!=S_[i+1]))
618
0
                                        tmp_[i] = S_[i-1];
619
0
                                    else if ((S_[i-2]!=S_[i-1]) && (S_[i]==S_[i+1]))
620
0
                                        tmp_[i] = S_[i];
621
0
                                    else if (S_[i]==S_[i-1])
622
0
                                        tmp_[i] = S_[i];
623
0
                                    else if ((S_[i-2]==S_[i-1]) && (S_[i-1]!=S_[i]) && (S_[i]==S_[i+1]))
624
0
                                        tmp_[i] = (S_[i-1]+S_[i])/2.0;
625
0
                                    else
626
0
                                        tmp_[i] = (std::abs(S_[i+1]-S_[i])*S_[i-1]+std::abs(S_[i-1]-S_[i-2])*S_[i])/(std::abs(S_[i+1]-S_[i])+std::abs(S_[i-1]-S_[i-2]));
627
0
                                 }
628
0
                                 tmp_[n_-2] = (std::abs(2*S_[n_-2]*S_[n_-3]-S_[n_-2])*S_[n_-3]+std::abs(S_[n_-3]-S_[n_-4])*S_[n_-2])/(std::abs(2*S_[n_-2]*S_[n_-3]-S_[n_-2])+std::abs(S_[n_-3]-S_[n_-4]));
629
0
                                 tmp_[n_-1] = (std::abs(4*S_[n_-2]*S_[n_-2]*S_[n_-3]-2*S_[n_-2]*S_[n_-3])*S_[n_-2]+std::abs(S_[n_-2]-S_[n_-3])*2*S_[n_-2]*S_[n_-3])/(std::abs(4*S_[n_-2]*S_[n_-2]*S_[n_-3]-2*S_[n_-2]*S_[n_-3])+std::abs(S_[n_-2]-S_[n_-3]));
630
0
                                 break;
631
0
                            case CubicInterpolation::Kruger:
632
                                // intermediate points
633
0
                                for (Size i=1; i<n_-1; ++i) {
634
0
                                    if (S_[i-1]*S_[i]<0.0)
635
                                        // slope changes sign at point
636
0
                                        tmp_[i] = 0.0;
637
0
                                    else
638
                                        // slope will be between the slopes of the adjacent
639
                                        // straight lines and should approach zero if the
640
                                        // slope of either line approaches zero
641
0
                                        tmp_[i] = 2.0/(1.0/S_[i-1]+1.0/S_[i]);
642
0
                                }
643
                                // end points
644
0
                                tmp_[0] = (3.0*S_[0]-tmp_[1])/2.0;
645
0
                                tmp_[n_-1] = (3.0*S_[n_-2]-tmp_[n_-2])/2.0;
646
0
                                break;
647
0
                            case CubicInterpolation::Harmonic:
648
                                // intermediate points
649
0
                                for (Size i=1; i<n_-1; ++i) {
650
0
                                    Real w1 = 2*dx_[i]+dx_[i-1];
651
0
                                    Real w2 = dx_[i]+2*dx_[i-1];
652
0
                                    if (S_[i-1]*S_[i]<=0.0)
653
                                        // slope changes sign at point
654
0
                                        tmp_[i] = 0.0;
655
0
                                    else
656
                                        // weighted harmonic mean of S_[i] and S_[i-1] if they
657
                                        // have the same sign; otherwise 0
658
0
                                        tmp_[i] = (w1+w2)/(w1/S_[i-1]+w2/S_[i]);
659
0
                                }
660
                                // end points [0]
661
0
                                tmp_[0] = ((2 * dx_[0] + dx_[1])*S_[0] - dx_[0] * S_[1]) / (dx_[1] + dx_[0]);
662
0
                                if (tmp_[0]*S_[0]<0.0) {
663
0
                                    tmp_[0] = 0;
664
0
                                }
665
0
                                else if (S_[0]*S_[1]<0) {
666
0
                                    if (std::fabs(tmp_[0])>std::fabs(3*S_[0])) {
667
0
                                            tmp_[0] = 3*S_[0];
668
0
                                    }
669
0
                                }
670
                                // end points [n-1]
671
0
                                tmp_[n_-1] = ((2*dx_[n_-2]+dx_[n_-3])*S_[n_-2]-dx_[n_-2]*S_[n_-3])/(dx_[n_-3]+dx_[n_-2]);
672
0
                                if (tmp_[n_-1]*S_[n_-2]<0.0) {
673
0
                                    tmp_[n_-1] = 0;
674
0
                                }
675
0
                                else if (S_[n_-2]*S_[n_-3]<0) {
676
0
                                    if (std::fabs(tmp_[n_-1])>std::fabs(3*S_[n_-2])) {
677
0
                                        tmp_[n_-1] = 3*S_[n_-2];
678
0
                                    }
679
0
                                }
680
0
                                break;
681
0
                            default:
682
0
                                QL_FAIL("unknown scheme");
683
0
                        }
684
0
                    }
685
0
                }
686
687
6.78k
                auto& monotonicityAdjustments = this->monotonicityAdjustments_;
688
6.78k
                std::fill(monotonicityAdjustments.begin(),
689
6.78k
                          monotonicityAdjustments.end(), false);
690
                // Hyman monotonicity constrained filter
691
6.78k
                if (monotonic_) {
692
6.78k
                    Real correction;
693
6.78k
                    Real pm, pu, pd, M;
694
461k
                    for (Size i=0; i<n_; ++i) {
695
454k
                        if (i==0) {
696
6.78k
                            if (tmp_[i]*S_[0]>0.0) {
697
5.62k
                                correction = tmp_[i]/std::fabs(tmp_[i]) *
698
5.62k
                                    std::min<Real>(std::fabs(tmp_[i]),
699
5.62k
                                                   std::fabs(3.0*S_[0]));
700
5.62k
                            } else {
701
1.16k
                                correction = 0.0;
702
1.16k
                            }
703
6.78k
                            if (correction!=tmp_[i]) {
704
692
                                tmp_[i] = correction;
705
692
                                monotonicityAdjustments[i] = true;
706
692
                            }
707
448k
                        } else if (i==n_-1) {
708
6.78k
                            if (tmp_[i]*S_[n_-2]>0.0) {
709
5.81k
                                correction = tmp_[i]/std::fabs(tmp_[i]) *
710
5.81k
                                    std::min<Real>(std::fabs(tmp_[i]),
711
5.81k
                                                   std::fabs(3.0*S_[n_-2]));
712
5.81k
                            } else {
713
968
                                correction = 0.0;
714
968
                            }
715
6.78k
                            if (correction!=tmp_[i]) {
716
283
                                tmp_[i] = correction;
717
283
                                monotonicityAdjustments[i] = true;
718
283
                            }
719
441k
                        } else {
720
441k
                            pm=(S_[i-1]*dx_[i]+S_[i]*dx_[i-1])/
721
441k
                                (dx_[i-1]+dx_[i]);
722
441k
                            M = 3.0 * std::min({
723
441k
                                    std::fabs(S_[i-1]),
724
441k
                                    std::fabs(S_[i]),
725
441k
                                    std::fabs(pm)
726
441k
                                });
727
441k
                            if (i>1) {
728
434k
                                if ((S_[i-1]-S_[i-2])*(S_[i]-S_[i-1])>0.0) {
729
346k
                                    pd=(S_[i-1]*(2.0*dx_[i-1]+dx_[i-2])
730
346k
                                        -S_[i-2]*dx_[i-1])/
731
346k
                                        (dx_[i-2]+dx_[i-1]);
732
346k
                                    if (pm*pd>0.0 && pm*(S_[i-1]-S_[i-2])>0.0) {
733
268k
                                        M = std::max<Real>(M, 1.5*std::min(
734
268k
                                                std::fabs(pm),std::fabs(pd)));
735
268k
                                    }
736
346k
                                }
737
434k
                            }
738
441k
                            if (i<n_-2) {
739
434k
                                if ((S_[i]-S_[i-1])*(S_[i+1]-S_[i])>0.0) {
740
346k
                                    pu=(S_[i]*(2.0*dx_[i]+dx_[i+1])-S_[i+1]*dx_[i])/
741
346k
                                        (dx_[i]+dx_[i+1]);
742
346k
                                    if (pm*pu>0.0 && -pm*(S_[i]-S_[i-1])>0.0) {
743
80.1k
                                        M = std::max<Real>(M, 1.5*std::min(
744
80.1k
                                                std::fabs(pm),std::fabs(pu)));
745
80.1k
                                    }
746
346k
                                }
747
434k
                            }
748
441k
                            if (tmp_[i]*pm>0.0) {
749
377k
                                correction = tmp_[i]/std::fabs(tmp_[i]) *
750
377k
                                    std::min(std::fabs(tmp_[i]), M);
751
377k
                            } else {
752
64.1k
                                correction = 0.0;
753
64.1k
                            }
754
441k
                            if (correction!=tmp_[i]) {
755
44.4k
                                tmp_[i] = correction;
756
44.4k
                                monotonicityAdjustments[i] = true;
757
44.4k
                            }
758
441k
                        }
759
454k
                    }
760
6.78k
                }
761
762
763
                // cubic coefficients
764
454k
                for (Size i=0; i<n_-1; ++i) {
765
448k
                    this->a_[i] = tmp_[i];
766
448k
                    this->b_[i] = (3.0*S_[i] - tmp_[i+1] - 2.0*tmp_[i])/dx_[i];
767
448k
                    this->c_[i] = (tmp_[i+1] + tmp_[i] - 2.0*S_[i])/(dx_[i]*dx_[i]);
768
448k
                }
769
770
6.78k
                auto& primitiveConst = this->primitiveConst_;
771
6.78k
                primitiveConst[0] = 0.0;
772
448k
                for (Size i=1; i<n_-1; ++i) {
773
441k
                    primitiveConst[i] = primitiveConst[i-1]
774
441k
                        + dx_[i-1] *
775
441k
                        (this->yBegin_[i-1] + dx_[i-1] *
776
441k
                         (this->a_[i-1]/2.0 + dx_[i-1] *
777
441k
                          (this->b_[i-1]/3.0 + dx_[i-1] * this->c_[i-1]/4.0)));
778
441k
                }
779
6.78k
            }
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, double const*>::update()
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double*> >::update()
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<double const*, double*>::update()
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<double*, double*>::update()
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*> >::update()
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<double const*, double const*>::update()
780
11.5k
            Real value(Real x) const override {
781
11.5k
                Size j = this->locate(x);
782
11.5k
                Real dx_ = x-this->xBegin_[j];
783
11.5k
                return this->yBegin_[j] + dx_*(this->a_[j] + dx_*(this->b_[j] + dx_*this->c_[j]));
784
11.5k
            }
QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*> >::value(double) const
Line
Count
Source
780
1.41k
            Real value(Real x) const override {
781
1.41k
                Size j = this->locate(x);
782
1.41k
                Real dx_ = x-this->xBegin_[j];
783
1.41k
                return this->yBegin_[j] + dx_*(this->a_[j] + dx_*(this->b_[j] + dx_*this->c_[j]));
784
1.41k
            }
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double*>, double const*>::value(double) const
QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, double*>::value(double) const
Line
Count
Source
780
10.1k
            Real value(Real x) const override {
781
10.1k
                Size j = this->locate(x);
782
10.1k
                Real dx_ = x-this->xBegin_[j];
783
10.1k
                return this->yBegin_[j] + dx_*(this->a_[j] + dx_*(this->b_[j] + dx_*this->c_[j]));
784
10.1k
            }
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, double const*>::value(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double*> >::value(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<double const*, double*>::value(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<double*, double*>::value(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*> >::value(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<double const*, double const*>::value(double) const
785
1.41k
            Real primitive(Real x) const override {
786
1.41k
                Size j = this->locate(x);
787
1.41k
                Real dx_ = x-this->xBegin_[j];
788
1.41k
                return this->primitiveConst_[j]
789
1.41k
                    + dx_*(this->yBegin_[j] + dx_*(this->a_[j]/2.0
790
1.41k
                    + dx_*(this->b_[j]/3.0 + dx_*this->c_[j]/4.0)));
791
1.41k
            }
QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*> >::primitive(double) const
Line
Count
Source
785
1.41k
            Real primitive(Real x) const override {
786
1.41k
                Size j = this->locate(x);
787
1.41k
                Real dx_ = x-this->xBegin_[j];
788
1.41k
                return this->primitiveConst_[j]
789
1.41k
                    + dx_*(this->yBegin_[j] + dx_*(this->a_[j]/2.0
790
1.41k
                    + dx_*(this->b_[j]/3.0 + dx_*this->c_[j]/4.0)));
791
1.41k
            }
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double*>, double const*>::primitive(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, double*>::primitive(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, double const*>::primitive(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double*> >::primitive(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<double const*, double*>::primitive(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<double*, double*>::primitive(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*> >::primitive(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<double const*, double const*>::primitive(double) const
792
8.20k
            Real derivative(Real x) const override {
793
8.20k
                Size j = this->locate(x);
794
8.20k
                Real dx_ = x-this->xBegin_[j];
795
8.20k
                return this->a_[j] + (2.0*this->b_[j] + 3.0*this->c_[j]*dx_)*dx_;
796
8.20k
            }
QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*> >::derivative(double) const
Line
Count
Source
792
1.41k
            Real derivative(Real x) const override {
793
1.41k
                Size j = this->locate(x);
794
1.41k
                Real dx_ = x-this->xBegin_[j];
795
1.41k
                return this->a_[j] + (2.0*this->b_[j] + 3.0*this->c_[j]*dx_)*dx_;
796
1.41k
            }
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double*>, double const*>::derivative(double) const
QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, double*>::derivative(double) const
Line
Count
Source
792
6.78k
            Real derivative(Real x) const override {
793
6.78k
                Size j = this->locate(x);
794
6.78k
                Real dx_ = x-this->xBegin_[j];
795
6.78k
                return this->a_[j] + (2.0*this->b_[j] + 3.0*this->c_[j]*dx_)*dx_;
796
6.78k
            }
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, double const*>::derivative(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double*> >::derivative(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<double const*, double*>::derivative(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<double*, double*>::derivative(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*> >::derivative(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<double const*, double const*>::derivative(double) const
797
4.80k
            Real secondDerivative(Real x) const override {
798
4.80k
                Size j = this->locate(x);
799
4.80k
                Real dx_ = x-this->xBegin_[j];
800
4.80k
                return 2.0*this->b_[j] + 6.0*this->c_[j]*dx_;
801
4.80k
            }
QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*> >::secondDerivative(double) const
Line
Count
Source
797
1.41k
            Real secondDerivative(Real x) const override {
798
1.41k
                Size j = this->locate(x);
799
1.41k
                Real dx_ = x-this->xBegin_[j];
800
1.41k
                return 2.0*this->b_[j] + 6.0*this->c_[j]*dx_;
801
1.41k
            }
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double*>, double const*>::secondDerivative(double) const
QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, double*>::secondDerivative(double) const
Line
Count
Source
797
3.39k
            Real secondDerivative(Real x) const override {
798
3.39k
                Size j = this->locate(x);
799
3.39k
                Real dx_ = x-this->xBegin_[j];
800
3.39k
                return 2.0*this->b_[j] + 6.0*this->c_[j]*dx_;
801
3.39k
            }
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, double const*>::secondDerivative(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double*> >::secondDerivative(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<double const*, double*>::secondDerivative(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<double*, double*>::secondDerivative(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*> >::secondDerivative(double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<double const*, double const*>::secondDerivative(double) const
802
803
          private:
804
            Size n_;
805
            CubicInterpolation::DerivativeApprox da_;
806
            bool monotonic_;
807
            CubicInterpolation::BoundaryCondition leftType_, rightType_;
808
            mutable Array tmp_;
809
            mutable std::vector<Real> dx_, S_;
810
            mutable TridiagonalOperator L_;
811
812
            Real cubicInterpolatingPolynomialDerivative(
813
                               Real a, Real b, Real c, Real d,
814
0
                               Real u, Real v, Real w, Real z, Real x) const {
815
0
                return (-((((a-c)*(b-c)*(c-x)*z-(a-d)*(b-d)*(d-x)*w)*(a-x+b-x)
816
0
                           +((a-c)*(b-c)*z-(a-d)*(b-d)*w)*(a-x)*(b-x))*(a-b)+
817
0
                          ((a-c)*(a-d)*v-(b-c)*(b-d)*u)*(c-d)*(c-x)*(d-x)
818
0
                          +((a-c)*(a-d)*(a-x)*v-(b-c)*(b-d)*(b-x)*u)
819
0
                          *(c-x+d-x)*(c-d)))/
820
0
                    ((a-b)*(a-c)*(a-d)*(b-c)*(b-d)*(c-d));
821
0
            }
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double*>, std::__1::__wrap_iter<double*> >::cubicInterpolatingPolynomialDerivative(double, double, double, double, double, double, double, double, double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double*>, double const*>::cubicInterpolatingPolynomialDerivative(double, double, double, double, double, double, double, double, double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, double*>::cubicInterpolatingPolynomialDerivative(double, double, double, double, double, double, double, double, double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, double const*>::cubicInterpolatingPolynomialDerivative(double, double, double, double, double, double, double, double, double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double*> >::cubicInterpolatingPolynomialDerivative(double, double, double, double, double, double, double, double, double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<double const*, double*>::cubicInterpolatingPolynomialDerivative(double, double, double, double, double, double, double, double, double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<double*, double*>::cubicInterpolatingPolynomialDerivative(double, double, double, double, double, double, double, double, double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<std::__1::__wrap_iter<double const*>, std::__1::__wrap_iter<double const*> >::cubicInterpolatingPolynomialDerivative(double, double, double, double, double, double, double, double, double) const
Unexecuted instantiation: QuantLib::detail::CubicInterpolationImpl<double const*, double const*>::cubicInterpolatingPolynomialDerivative(double, double, double, double, double, double, double, double, double) const
822
        };
823
824
    }
825
826
}
827
828
#endif