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