/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 |