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