QuantLib: a free/open-source library for quantitative finance
fully annotated source code - version 1.34
Loading...
Searching...
No Matches
convexmonotoneinterpolation.hpp
Go to the documentation of this file.
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3/*
4 Copyright (C) 2008 Simon Ibbotson
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 <http://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 convexmonotoneinterpolation.hpp
21 \brief convex monotone interpolation method
22*/
23
24#ifndef quantlib_convex_monotone_interpolation_hpp
25#define quantlib_convex_monotone_interpolation_hpp
26
28#include <map>
29
30namespace QuantLib {
31
32 namespace detail {
33 template<class I1, class I2> class ConvexMonotoneImpl;
34 class SectionHelper;
35 }
36
37 //! Convex monotone yield-curve interpolation method.
38 /*! Enhances implementation of the convex monotone method
39 described in "Interpolation Methods for Curve Construction" by
40 Hagan & West AMF Vol 13, No2 2006.
41
42 A setting of monotonicity = 1 and quadraticity = 0 will
43 reproduce the basic Hagan/West method. However, this can
44 produce excessive gradients which can mean P&L swings for some
45 curves. Setting monotonicity < 1 and/or quadraticity > 0
46 produces smoother curves. Extra enhancement to avoid negative
47 values (if required) is in place.
48
49 \ingroup interpolations
50 \warning See the Interpolation class for information about the
51 required lifetime of the underlying data.
52 */
53 template <class I1, class I2>
55 typedef std::map<Real, ext::shared_ptr<detail::SectionHelper> >
57 public:
58 ConvexMonotoneInterpolation(const I1& xBegin, const I1& xEnd,
59 const I2& yBegin, Real quadraticity,
60 Real monotonicity, bool forcePositive,
61 bool flatFinalPeriod = false,
62 const helper_map& preExistingHelpers =
63 helper_map()) {
64 impl_ = ext::shared_ptr<Interpolation::Impl>(
66 xEnd,
67 yBegin,
68 quadraticity,
69 monotonicity,
70 forcePositive,
71 flatFinalPeriod,
72 preExistingHelpers));
73 impl_->update();
74 }
75
77 : Interpolation(interp) {}
78
79 std::map<Real, ext::shared_ptr<detail::SectionHelper> >
81 ext::shared_ptr<detail::ConvexMonotoneImpl<I1,I2> > derived =
82 ext::dynamic_pointer_cast<detail::ConvexMonotoneImpl<I1,I2>,
84 return derived->getExistingHelpers();
85 }
86 };
87
88 //! Convex-monotone interpolation factory and traits
89 /*! \ingroup interpolations */
91 public:
92 static const bool global = true;
93 static const Size requiredPoints = 2;
94 static const Size dataSizeAdjustment = 1;
95
96 ConvexMonotone(Real quadraticity = 0.3,
97 Real monotonicity = 0.7,
98 bool forcePositive = true)
99 : quadraticity_(quadraticity), monotonicity_(monotonicity),
100 forcePositive_(forcePositive) {}
101
102 template <class I1, class I2>
103 Interpolation interpolate(const I1& xBegin, const I1& xEnd,
104 const I2& yBegin) const {
105 return ConvexMonotoneInterpolation<I1,I2>(xBegin, xEnd, yBegin,
109 false);
110 }
111
112 template <class I1, class I2>
113 Interpolation localInterpolate(const I1& xBegin, const I1& xEnd,
114 const I2& yBegin, Size localisation,
115 Interpolation& prevInterpolation,
116 Size finalSize) const {
117 Size length = std::distance(xBegin, xEnd);
118 if (length - localisation == 1) { // the first time this
119 // function is called
120 if (length == finalSize) {
121 return ConvexMonotoneInterpolation<I1,I2>(xBegin, xEnd,
122 yBegin,
126 false);
127 } else {
128 return ConvexMonotoneInterpolation<I1,I2>(xBegin, xEnd,
129 yBegin,
133 true);
134 }
135 }
136
137 ConvexMonotoneInterpolation<I1,I2> interp(prevInterpolation);
138 if (length == finalSize) {
140 xBegin, xEnd, yBegin,
144 false,
145 interp.getExistingHelpers());
146 } else {
148 xBegin, xEnd, yBegin,
152 true,
153 interp.getExistingHelpers());
154 }
155 }
156 private:
159 };
160
161
162 namespace detail {
163
165 public:
166 virtual ~SectionHelper() = default;
167 virtual Real value(Real x) const = 0;
168 virtual Real primitive(Real x) const = 0;
169 virtual Real fNext() const = 0;
170 };
171
172 //the first value in the y-vector is ignored.
173 template <class I1, class I2>
174 class ConvexMonotoneImpl final : public Interpolation::templateImpl<I1, I2> {
175 typedef std::map<Real, ext::shared_ptr<SectionHelper> >
177 public:
183 };
184
185 ConvexMonotoneImpl(const I1& xBegin,
186 const I1& xEnd,
187 const I2& yBegin,
188 Real quadraticity,
189 Real monotonicity,
190 bool forcePositive,
191 bool constantLastPeriod,
192 const helper_map& preExistingHelpers)
193 : Interpolation::templateImpl<I1,I2>(xBegin,xEnd,yBegin,
194 ConvexMonotone::requiredPoints),
195 preSectionHelpers_(preExistingHelpers),
196 forcePositive_(forcePositive),
197 constantLastPeriod_(constantLastPeriod),
198 quadraticity_(quadraticity), monotonicity_(monotonicity),
199 length_(xEnd-xBegin) {
200
202 "Monotonicity must lie between 0 and 1");
204 "Quadraticity must lie between 0 and 1");
205 QL_REQUIRE(length_ >= 2,
206 "Single point provided, not supported by convex "
207 "monotone method as first point is ignored");
208 QL_REQUIRE((length_ - preExistingHelpers.size()) > 1,
209 "Too many existing helpers have been supplied");
210 }
211
212 void update() override;
213
214 Real value(Real x) const override;
215 Real primitive(Real x) const override;
216 Real derivative(Real) const override {
217 QL_FAIL("Convex-monotone spline derivative not implemented");
218 }
219 Real secondDerivative(Real) const override {
220 QL_FAIL("Convex-monotone spline second derivative "
221 "not implemented");
222 }
223
225 helper_map retArray(sectionHelpers_);
227 retArray.erase(*(this->xEnd_-1));
228 return retArray;
229 }
230 private:
233 ext::shared_ptr<SectionHelper> extrapolationHelper_;
238 };
239
240
241 class ComboHelper : public SectionHelper {
242 public:
243 ComboHelper(ext::shared_ptr<SectionHelper>& quadraticHelper,
244 ext::shared_ptr<SectionHelper>& convMonoHelper,
245 Real quadraticity)
246 : quadraticity_(quadraticity),
247 quadraticHelper_(quadraticHelper),
248 convMonoHelper_(convMonoHelper) {
249 QL_REQUIRE(quadraticity < 1.0 && quadraticity > 0.0,
250 "Quadratic value must lie between 0 and 1"); }
251
252 Real value(Real x) const override {
253 return( quadraticity_*quadraticHelper_->value(x) + (1.0-quadraticity_)*convMonoHelper_->value(x) );
254 }
255 Real primitive(Real x) const override {
256 return( quadraticity_*quadraticHelper_->primitive(x) + (1.0-quadraticity_)*convMonoHelper_->primitive(x) );
257 }
258 Real fNext() const override {
259 return( quadraticity_*quadraticHelper_->fNext() + (1.0-quadraticity_)*convMonoHelper_->fNext() );
260 }
261
262 private:
264 ext::shared_ptr<SectionHelper> quadraticHelper_;
265 ext::shared_ptr<SectionHelper> convMonoHelper_;
266 };
267
269 public:
271 : value_(value), prevPrimitive_(prevPrimitive), xPrev_(xPrev)
272 {}
273
274 Real value(Real) const override { return value_; }
275 Real primitive(Real x) const override { return prevPrimitive_ + (x - xPrev_) * value_; }
276 Real fNext() const override { return value_; }
277
278 private:
282 };
283
285 public:
287 Real gPrev, Real gNext,
288 Real fAverage, Real eta2,
289 Real prevPrimitive)
290 : xPrev_(xPrev), xScaling_(xNext-xPrev), gPrev_(gPrev),
291 gNext_(gNext), fAverage_(fAverage), eta2_(eta2),
292 prevPrimitive_(prevPrimitive)
293 {}
294
295 Real value(Real x) const override {
296 Real xVal = (x-xPrev_)/xScaling_;
297 if (xVal <= eta2_) {
298 return( fAverage_ + gPrev_ );
299 } else {
300 return( fAverage_ + gPrev_ + (gNext_-gPrev_)/((1-eta2_)*(1-eta2_))*(xVal-eta2_)*(xVal-eta2_) );
301 }
302 }
303
304 Real primitive(Real x) const override {
305 Real xVal = (x-xPrev_)/xScaling_;
306 if (xVal <= eta2_) {
307 return( prevPrimitive_ + xScaling_*(fAverage_*xVal + gPrev_*xVal) );
308 } else {
309 return( prevPrimitive_ + xScaling_*(fAverage_*xVal + gPrev_*xVal + (gNext_-gPrev_)/((1-eta2_)*(1-eta2_)) *
310 (1.0/3.0*(xVal*xVal*xVal - eta2_*eta2_*eta2_) - eta2_*xVal*xVal + eta2_*eta2_*xVal) ) );
311 }
312 }
313 Real fNext() const override { return (fAverage_ + gNext_); }
314
315 private:
317 };
318
320 public:
322 Real gPrev, Real gNext,
323 Real fAverage, Real eta3,
324 Real prevPrimitive)
325 : xPrev_(xPrev), xScaling_(xNext-xPrev), gPrev_(gPrev),
326 gNext_(gNext), fAverage_(fAverage), eta3_(eta3), prevPrimitive_(prevPrimitive)
327 {}
328
329 Real value(Real x) const override {
330 Real xVal = (x-xPrev_)/xScaling_;
331 if (xVal <= eta3_) {
332 return( fAverage_ + gNext_ + (gPrev_-gNext_) / (eta3_*eta3_) * (eta3_-xVal)*(eta3_-xVal) );
333 } else {
334 return( fAverage_ + gNext_ );
335 }
336 }
337
338 Real primitive(Real x) const override {
339 Real xVal = (x-xPrev_)/xScaling_;
340 if (xVal <= eta3_) {
341 return( prevPrimitive_ + xScaling_ * (fAverage_*xVal + gNext_*xVal + (gPrev_-gNext_)/(eta3_*eta3_) *
342 (1.0/3.0 * xVal*xVal*xVal - eta3_*xVal*xVal + eta3_*eta3_*xVal) ) );
343 } else {
344 return( prevPrimitive_ + xScaling_ * (fAverage_*xVal + gNext_*xVal + (gPrev_-gNext_)/(eta3_*eta3_) *
345 (1.0/3.0 * eta3_*eta3_*eta3_)) );
346 }
347 }
348 Real fNext() const override { return (fAverage_ + gNext_); }
349
350 private:
352 };
353
355 public:
357 Real gPrev, Real gNext,
358 Real fAverage, Real eta4,
359 Real prevPrimitive)
360 : xPrev_(xPrev), xScaling_(xNext-xPrev), gPrev_(gPrev),
361 gNext_(gNext), fAverage_(fAverage), eta4_(eta4), prevPrimitive_(prevPrimitive) {
362 A_ = -0.5*(eta4_*gPrev_ + (1-eta4_)*gNext_);
363 }
364
365 Real value(Real x) const override {
366 Real xVal = (x-xPrev_)/xScaling_;
367 if (xVal <= eta4_) {
368 return(fAverage_ + A_ + (gPrev_-A_)*(eta4_-xVal)*(eta4_-xVal)/(eta4_*eta4_) );
369 } else {
370 return(fAverage_ + A_ + (gNext_-A_)*(xVal-eta4_)*(xVal-eta4_)/((1-eta4_)*(1-eta4_)) );
371 }
372 }
373
374 Real primitive(Real x) const override {
375 Real xVal = (x-xPrev_)/xScaling_;
376 Real retVal;
377 if (xVal <= eta4_) {
378 retVal = prevPrimitive_ + xScaling_ * (fAverage_ + A_ + (gPrev_-A_)/(eta4_*eta4_) *
379 (eta4_*eta4_ - eta4_*xVal + 1.0/3.0*xVal*xVal)) * xVal;
380 } else {
381 retVal = prevPrimitive_ + xScaling_ *(fAverage_*xVal + A_*xVal + (gPrev_-A_)*(1.0/3.0*eta4_) +
382 (gNext_-A_)/((1-eta4_)*(1-eta4_)) *
383 (1.0/3.0*xVal*xVal*xVal - eta4_*xVal*xVal + eta4_*eta4_*xVal - 1.0/3.0*eta4_*eta4_*eta4_));
384 }
385 return retVal;
386 }
387 Real fNext() const override { return (fAverage_ + gNext_); }
388
389 protected:
392 };
393
395 public:
397 Real xNext,
398 Real gPrev,
399 Real gNext,
400 Real fAverage,
401 Real eta4,
402 Real prevPrimitive)
403 : ConvexMonotone4Helper(xPrev, xNext, gPrev, gNext, fAverage, eta4, prevPrimitive) {
404 if ( A_+ fAverage_ <= 0.0 ) {
405 splitRegion_ = true;
406 Real fPrev = gPrev_+fAverage_;
408 Real reqdShift = (eta4_*fPrev + (1-eta4_)*fNext)/3.0 - fAverage_;
409 Real reqdPeriod = reqdShift * xScaling_ / (fAverage_+reqdShift);
410 Real xAdjust = xScaling_ - reqdPeriod;
411 xRatio_ = xAdjust/xScaling_;
412
413 fAverage_ += reqdShift;
415 gPrev_ = fPrev - fAverage_;
416 A_ = -(eta4_ * gPrev_ + (1.0-eta4)*gNext_)/2.0;
417 x2_ = xPrev_ + xAdjust * eta4_;
418 x3_ = xPrev_ + xScaling_ - xAdjust*(1.0-eta4_);
419 }
420 }
421
422 Real value(Real x) const override {
423 if (!splitRegion_)
425
426 Real xVal = (x-xPrev_)/xScaling_;
427 if (x <= x2_) {
428 xVal /= xRatio_;
429 return(fAverage_ + A_ + (gPrev_-A_)*(eta4_-xVal)*(eta4_-xVal)/(eta4_*eta4_));
430 } else if (x < x3_) {
431 return 0.0;
432 } else {
433 xVal = 1.0 - (1.0 - xVal) / xRatio_;
434 return(fAverage_ + A_ + (gNext_-A_)*(xVal-eta4_)*(xVal-eta4_)/((1-eta4_)*(1-eta4_)) );
435 }
436 }
437
438 Real primitive(Real x) const override {
439 if (!splitRegion_)
441
442 Real xVal = (x-xPrev_)/xScaling_;
443 if (x <= x2_) {
444 xVal /= xRatio_;
446 (eta4_*eta4_ - eta4_*xVal + 1.0/3.0*xVal*xVal)) * xVal );
447 } else if (x <= x3_) {
449 (1.0/3.0*eta4_*eta4_*eta4_)) );
450 } else {
451 xVal = 1.0 - (1.0-xVal)/xRatio_;
452 return( prevPrimitive_ + xScaling_*xRatio_*(fAverage_*xVal + A_*xVal + (gPrev_-A_)*(1.0/3.0*eta4_) +
453 (gNext_-A_) / ((1.0-eta4_)*(1.0-eta4_)) *
454 (1.0/3.0*xVal*xVal*xVal - eta4_*xVal*xVal + eta4_*eta4_*xVal - 1.0/3.0*eta4_*eta4_*eta4_)) );
455 }
456 }
457
458 private:
459 bool splitRegion_ = false;
461 };
462
464 public:
465 ConstantGradHelper(Real fPrev, Real prevPrimitive,
466 Real xPrev, Real xNext, Real fNext)
467 : fPrev_(fPrev), prevPrimitive_(prevPrimitive),
468 xPrev_(xPrev), fGrad_((fNext-fPrev)/(xNext-xPrev)),fNext_(fNext)
469 {}
470
471 Real value(Real x) const override { return (fPrev_ + (x - xPrev_) * fGrad_); }
472 Real primitive(Real x) const override {
473 return (prevPrimitive_+(x-xPrev_)*(fPrev_+0.5*(x-xPrev_)*fGrad_));
474 }
475 Real fNext() const override { return fNext_; }
476
477 private:
479 };
480
482 public:
484 Real fPrev, Real fNext,
485 Real fAverage,
486 Real prevPrimitive)
487 : xPrev_(xPrev), xNext_(xNext), fPrev_(fPrev),
488 fNext_(fNext), fAverage_(fAverage),
489 prevPrimitive_(prevPrimitive) {
490 a_ = 3*fPrev_ + 3*fNext_ - 6*fAverage_;
491 b_ = -(4*fPrev_ + 2*fNext_ - 6*fAverage_);
492 c_ = fPrev_;
494 }
495
496 Real value(Real x) const override {
497 Real xVal = (x-xPrev_)/xScaling_;
498 return( a_*xVal*xVal + b_*xVal + c_ );
499 }
500
501 Real primitive(Real x) const override {
502 Real xVal = (x-xPrev_)/xScaling_;
503 return( prevPrimitive_ + xScaling_ * (a_/3*xVal*xVal + b_/2*xVal + c_) * xVal );
504 }
505
506 Real fNext() const override { return fNext_; }
507
508 private:
511 };
512
514 public:
516 Real xPrev, Real xNext, Real fPrev, Real fNext, Real fAverage, Real prevPrimitive)
517 : x1_(xPrev), x4_(xNext), primitive1_(prevPrimitive), fAverage_(fAverage),
518 fPrev_(fPrev), fNext_(fNext) {
519 a_ = 3*fPrev_ + 3*fNext_ - 6*fAverage_;
520 b_ = -(4*fPrev_ + 2*fNext_ - 6*fAverage_);
521 c_ = fPrev_;
522 Real d = b_*b_-4*a_*c_;
523 xScaling_ = x4_-x1_;
524 if (d > 0) {
525 Real aAv = 36;
526 Real bAv = -24*(fPrev_+fNext_);
528 Real dAv = bAv*bAv - 4.0*aAv*cAv;
529 if (dAv >= 0.0) {
530 splitRegion_ = true;
531 Real avRoot = (-bAv - std::sqrt(dAv))/(2*aAv);
532
533 xRatio_ = fAverage_ / avRoot;
535
536 a_ = 3*fPrev_ + 3*fNext_ - 6*avRoot;
537 b_ = -(4*fPrev_ + 2*fNext_ - 6*avRoot);
538 c_ = fPrev_;
539 Real xRoot = -b_/(2*a_);
540 x2_ = x1_ + xRatio_ * (x4_-x1_) * xRoot;
541 x3_ = x4_ - xRatio_ * (x4_-x1_) * (1-xRoot);
543 primitive1_ + xScaling_*(a_/3*xRoot*xRoot + b_/2*xRoot + c_)*xRoot;
544 }
545 }
546 }
547
548 Real value(Real x) const override {
549 Real xVal = (x - x1_) / (x4_-x1_);
550 if (splitRegion_) {
551 if (x <= x2_) {
552 xVal /= xRatio_;
553 } else if (x < x3_) {
554 return 0.0;
555 } else {
556 xVal = 1.0 - (1.0 - xVal) / xRatio_;
557 }
558 }
559
560 return c_ + b_*xVal + a_*xVal*xVal;
561 }
562
563 Real primitive(Real x) const override {
564 Real xVal = (x - x1_) / (x4_-x1_);
565 if (splitRegion_) {
566 if (x < x2_) {
567 xVal /= xRatio_;
568 } else if (x < x3_) {
569 return primitive2_;
570 } else {
571 xVal = 1.0 - (1.0 - xVal) / xRatio_;
572 }
573 }
574 return primitive1_ + xScaling_ * (a_/3*xVal*xVal+ b_/2*xVal+c_)*xVal;
575 }
576
577 Real fNext() const override { return fNext_; }
578
579 private:
580 bool splitRegion_ = false;
585 };
586
587 template <class I1, class I2>
589 sectionHelpers_.clear();
590 if (length_ == 2) { //single period
591 ext::shared_ptr<SectionHelper> singleHelper(
592 new EverywhereConstantHelper(this->yBegin_[1],
593 0.0,
594 this->xBegin_[0]));
595 sectionHelpers_[this->xBegin_[1]] = singleHelper;
596 extrapolationHelper_ = singleHelper;
597 return;
598 }
599
600 std::vector<Real> f(length_);
601 sectionHelpers_ = preSectionHelpers_;
602 Size startPoint = sectionHelpers_.size()+1;
603
604 //first derive the boundary forwards.
605 for (Size i=startPoint; i<length_-1; ++i) {
606 Real dxPrev = this->xBegin_[i] - this->xBegin_[i-1];
607 Real dx = this->xBegin_[i+1] - this->xBegin_[i];
608 f[i] = dx/(dx+dxPrev) * this->yBegin_[i]
609 + dxPrev/(dx+dxPrev) * this->yBegin_[i+1];
610 }
611
612 if (startPoint > 1)
613 f[startPoint-1] = preSectionHelpers_.rbegin()->second->fNext();
614 if (startPoint == 1)
615 f[0] = 1.5 * this->yBegin_[1] - 0.5 * f[1];
616
617 f[length_-1] = 1.5 * this->yBegin_[length_-1] - 0.5 * f[length_-2];
618
619 if (forcePositive_) {
620 if (f[0] < 0)
621 f[0] = 0.0;
622 if (f[length_-1] < 0.0)
623 f[length_-1] = 0.0;
624 }
625
626 Real primitive = 0.0;
627 for (Size i = 0; i < startPoint-1; ++i)
628 primitive +=
629 this->yBegin_[i+1] * (this->xBegin_[i+1]-this->xBegin_[i]);
630
631 Size endPoint = length_;
632 //constantLastPeriod_ = false;
633 if (constantLastPeriod_)
634 endPoint = endPoint-1;
635
636 for (Size i=startPoint; i< endPoint; ++i) {
637 Real gPrev = f[i-1] - this->yBegin_[i];
638 Real gNext = f[i] - this->yBegin_[i];
639 //first deal with the zero gradient case
640 if ( std::fabs(gPrev) < 1.0E-14
641 && std::fabs(gNext) < 1.0E-14 ) {
642 ext::shared_ptr<SectionHelper> singleHelper(
643 new ConstantGradHelper(f[i-1], primitive,
644 this->xBegin_[i-1],
645 this->xBegin_[i],
646 f[i]));
647 sectionHelpers_[this->xBegin_[i]] = singleHelper;
648 } else {
649 Real quadraticity = quadraticity_;
650 ext::shared_ptr<SectionHelper> quadraticHelper;
651 ext::shared_ptr<SectionHelper> convMonotoneHelper;
652 if (quadraticity_ > 0.0) {
653 if (gPrev >= -2.0*gNext && gPrev > -0.5*gNext && forcePositive_) {
654 quadraticHelper =
655 ext::shared_ptr<SectionHelper>(
656 new QuadraticMinHelper(this->xBegin_[i-1],
657 this->xBegin_[i],
658 f[i-1], f[i],
659 this->yBegin_[i],
660 primitive) );
661 } else {
662 quadraticHelper =
663 ext::shared_ptr<SectionHelper>(
664 new QuadraticHelper(this->xBegin_[i-1],
665 this->xBegin_[i],
666 f[i-1], f[i],
667 this->yBegin_[i],
668 primitive) );
669 }
670 }
671 if (quadraticity_ < 1.0) {
672
673 if ((gPrev > 0.0 && -0.5*gPrev >= gNext && gNext >= -2.0*gPrev) ||
674 (gPrev < 0.0 && -0.5*gPrev <= gNext && gNext <= -2.0*gPrev)) {
675 quadraticity = 1.0;
676 if (quadraticity_ == 0) {
677 if (forcePositive_) {
678 quadraticHelper =
679 ext::shared_ptr<SectionHelper>(
681 this->xBegin_[i-1],
682 this->xBegin_[i],
683 f[i-1], f[i],
684 this->yBegin_[i],
685 primitive) );
686 } else {
687 quadraticHelper =
688 ext::shared_ptr<SectionHelper>(
689 new QuadraticHelper(
690 this->xBegin_[i-1],
691 this->xBegin_[i],
692 f[i-1], f[i],
693 this->yBegin_[i],
694 primitive) );
695 }
696 }
697 }
698 else if ( (gPrev < 0.0 && gNext > -2.0*gPrev) ||
699 (gPrev > 0.0 && gNext < -2.0*gPrev)) {
700
701 Real eta = (gNext + 2.0*gPrev)/(gNext - gPrev);
702 Real b2 = (1.0 + monotonicity_)/2.0;
703 if (eta < b2) {
704 convMonotoneHelper =
705 ext::shared_ptr<SectionHelper>(
707 this->xBegin_[i-1],
708 this->xBegin_[i],
709 gPrev, gNext,
710 this->yBegin_[i],
711 eta, primitive));
712 } else {
713 if (forcePositive_) {
714 convMonotoneHelper =
715 ext::shared_ptr<SectionHelper>(
717 this->xBegin_[i-1],
718 this->xBegin_[i],
719 gPrev, gNext,
720 this->yBegin_[i],
721 b2, primitive));
722 } else {
723 convMonotoneHelper =
724 ext::shared_ptr<SectionHelper>(
726 this->xBegin_[i-1],
727 this->xBegin_[i],
728 gPrev, gNext,
729 this->yBegin_[i],
730 b2, primitive));
731 }
732 }
733 }
734 else if ( (gPrev > 0.0 && gNext < 0.0 && gNext > -0.5*gPrev) ||
735 (gPrev < 0.0 && gNext > 0.0 && gNext < -0.5*gPrev) ) {
736 Real eta = gNext/(gNext-gPrev) * 3.0;
737 Real b3 = (1.0 - monotonicity_)/2.0;
738 if (eta > b3) {
739 convMonotoneHelper =
740 ext::shared_ptr<SectionHelper>(
742 this->xBegin_[i-1],
743 this->xBegin_[i],
744 gPrev, gNext,
745 this->yBegin_[i],
746 eta, primitive));
747 } else {
748 if (forcePositive_) {
749 convMonotoneHelper =
750 ext::shared_ptr<SectionHelper>(
752 this->xBegin_[i-1],
753 this->xBegin_[i],
754 gPrev, gNext,
755 this->yBegin_[i],
756 b3, primitive));
757 } else {
758 convMonotoneHelper =
759 ext::shared_ptr<SectionHelper>(
761 this->xBegin_[i-1],
762 this->xBegin_[i],
763 gPrev, gNext,
764 this->yBegin_[i],
765 b3, primitive));
766 }
767 }
768 } else {
769 Real eta = gNext/(gPrev + gNext);
770 Real b2 = (1.0 + monotonicity_)/2.0;
771 Real b3 = (1.0 - monotonicity_)/2.0;
772 if (eta > b2)
773 eta = b2;
774 if (eta < b3)
775 eta = b3;
776 if (forcePositive_) {
777 convMonotoneHelper =
778 ext::shared_ptr<SectionHelper>(
780 this->xBegin_[i-1],
781 this->xBegin_[i],
782 gPrev, gNext,
783 this->yBegin_[i],
784 eta, primitive));
785 } else {
786 convMonotoneHelper =
787 ext::shared_ptr<SectionHelper>(
789 this->xBegin_[i-1],
790 this->xBegin_[i],
791 gPrev, gNext,
792 this->yBegin_[i],
793 eta, primitive));
794 }
795 }
796 }
797
798 if (quadraticity == 1.0) {
799 sectionHelpers_[this->xBegin_[i]] = quadraticHelper;
800 } else if (quadraticity == 0.0) {
801 sectionHelpers_[this->xBegin_[i]] = convMonotoneHelper;
802 } else {
803 sectionHelpers_[this->xBegin_[i]] =
804 ext::shared_ptr<SectionHelper>(
805 new ComboHelper(quadraticHelper,
806 convMonotoneHelper,
807 quadraticity));
808 }
809
810 }
811 primitive +=
812 this->yBegin_[i] * (this->xBegin_[i]-this->xBegin_[i-1]);
813 }
814
815 if (constantLastPeriod_) {
816 sectionHelpers_[this->xBegin_[length_-1]] =
817 ext::shared_ptr<SectionHelper>(
818 new EverywhereConstantHelper(this->yBegin_[length_-1],
819 primitive,
820 this->xBegin_[length_-2]));
821 extrapolationHelper_ = sectionHelpers_[this->xBegin_[length_-1]];
822 } else {
823 extrapolationHelper_ =
824 ext::shared_ptr<SectionHelper>(
826 (sectionHelpers_.rbegin())->second->value(*(this->xEnd_-1)),
827 primitive,
828 *(this->xEnd_-1)));
829 }
830 }
831
832 template <class I1, class I2>
834 if (x >= *(this->xEnd_-1)) {
835 return extrapolationHelper_->value(x);
836 }
837
838 return sectionHelpers_.upper_bound(x)->second->value(x);
839 }
840
841 template <class I1, class I2>
843 if (x >= *(this->xEnd_-1)) {
844 return extrapolationHelper_->primitive(x);
845 }
846
847 return sectionHelpers_.upper_bound(x)->second->primitive(x);
848 }
849
850 }
851
852}
853
854#endif
Convex-monotone interpolation factory and traits.
Interpolation localInterpolate(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin, Size localisation, Interpolation &prevInterpolation, Size finalSize) const
Interpolation interpolate(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin) const
ConvexMonotone(Real quadraticity=0.3, Real monotonicity=0.7, bool forcePositive=true)
Convex monotone yield-curve interpolation method.
std::map< Real, ext::shared_ptr< detail::SectionHelper > > getExistingHelpers()
std::map< Real, ext::shared_ptr< detail::SectionHelper > > helper_map
ConvexMonotoneInterpolation(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin, Real quadraticity, Real monotonicity, bool forcePositive, bool flatFinalPeriod=false, const helper_map &preExistingHelpers=helper_map())
abstract base class for interpolation implementations
basic template implementation
templateImpl(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin, const int requiredPoints=2)
base class for 1-D interpolations.
ext::shared_ptr< Impl > impl_
ext::shared_ptr< SectionHelper > convMonoHelper_
ext::shared_ptr< SectionHelper > quadraticHelper_
ComboHelper(ext::shared_ptr< SectionHelper > &quadraticHelper, ext::shared_ptr< SectionHelper > &convMonoHelper, Real quadraticity)
ConstantGradHelper(Real fPrev, Real prevPrimitive, Real xPrev, Real xNext, Real fNext)
ConvexMonotone2Helper(Real xPrev, Real xNext, Real gPrev, Real gNext, Real fAverage, Real eta2, Real prevPrimitive)
ConvexMonotone3Helper(Real xPrev, Real xNext, Real gPrev, Real gNext, Real fAverage, Real eta3, Real prevPrimitive)
ConvexMonotone4Helper(Real xPrev, Real xNext, Real gPrev, Real gNext, Real fAverage, Real eta4, Real prevPrimitive)
ConvexMonotone4MinHelper(Real xPrev, Real xNext, Real gPrev, Real gNext, Real fAverage, Real eta4, Real prevPrimitive)
ConvexMonotoneImpl(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin, Real quadraticity, Real monotonicity, bool forcePositive, bool constantLastPeriod, const helper_map &preExistingHelpers)
ext::shared_ptr< SectionHelper > extrapolationHelper_
std::map< Real, ext::shared_ptr< SectionHelper > > helper_map
EverywhereConstantHelper(Real value, Real prevPrimitive, Real xPrev)
QuadraticHelper(Real xPrev, Real xNext, Real fPrev, Real fNext, Real fAverage, Real prevPrimitive)
QuadraticMinHelper(Real xPrev, Real xNext, Real fPrev, Real fNext, Real fAverage, Real prevPrimitive)
virtual Real primitive(Real x) const =0
virtual Real fNext() const =0
virtual ~SectionHelper()=default
virtual Real value(Real x) const =0
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
Definition: errors.hpp:117
#define QL_FAIL(message)
throw an error (possibly with file and line information)
Definition: errors.hpp:92
Date d
QL_REAL Real
real number
Definition: types.hpp:50
std::size_t Size
size of a container
Definition: types.hpp:58
base class for 1-D interpolations
Definition: any.hpp:35