29#ifndef quantlib_cubic_interpolation_hpp
30#define quantlib_cubic_interpolation_hpp
158 template <
class I1,
class I2>
165 Real leftConditionValue,
167 Real rightConditionValue) {
168 impl_ = ext::shared_ptr<Interpolation::Impl>(
new
175 rightConditionValue));
199 template <
class I1,
class I2>
212 template <
class I1,
class I2>
225 template <
class I1,
class I2>
238 template <
class I1,
class I2>
251 template <
class I1,
class I2>
264 template <
class I1,
class I2>
277 template <
class I1,
class I2>
290 template <
class I1,
class I2>
303 template <
class I1,
class I2>
316 template <
class I1,
class I2>
332 bool monotonic =
false,
335 Real leftConditionValue = 0.0,
338 Real rightConditionValue = 0.0)
342 template <
class I1,
class I2>
345 const I2& yBegin)
const {
363 template <
class I1,
class I2>
373 Real leftConditionValue,
375 Real rightConditionValue)
378 Cubic::requiredPoints),
388 "Lagrange boundary condition requires at least "
389 "4 points (" << (xEnd-xBegin) <<
" are given)");
395 for (
Size i=0; i<
n_-1; ++i) {
402 for (
Size i=1; i<
n_-1; ++i) {
425 QL_FAIL(
"this end condition is not implemented yet");
436 QL_FAIL(
"unknown end condition");
457 QL_FAIL(
"this end condition is not implemented yet");
468 QL_FAIL(
"unknown end condition");
475 for (
Size i=0; i<
n_-2; ++i) {
478 T_[i][i+2]=
dx_[i+1]/6.0;
481 for (
Size i=0; i<
n_-2; ++i) {
483 S_[i][i+1]=-(1.0/
dx_[i+1]+1.0/
dx_[i]);
484 S_[i][i+2]=1.0/
dx_[i+1];
490 for (
Size i=0; i<
n_-2; ++i)
501 for (
Size i=1; i<
n_-1; ++i) {
502 Q_[i][i-1]=7.0/8*1.0/(
n_-1)*
dx_[i-1]*
dx_[i-1]*
dx_[i-1];
513 for (
Size i=0; i<
n_-1; ++i)
514 tmp_[i]=(Y_[i+1]-Y_[i])/
dx_[i]-(2.0*D_[i]+D_[i+1])*
dx_[i]/6.0;
519 for (
Size i=0; i<
n_-2; ++i) {
522 T_[i][i+2]=
dx_[i+1]/6.0;
525 for (
Size i=0; i<
n_-2; ++i) {
527 S_[i][i+1]=-(1.0/
dx_[i+1]+1.0/
dx_[i]);
528 S_[i][i+2]=1.0/
dx_[i+1];
534 for (
Size i=0; i<
n_-2; ++i)
543 Q_[0][0]=1.0/(
n_-1)*
dx_[0];
544 Q_[0][1]=1.0/2*1.0/(
n_-1)*
dx_[0];
545 for (
Size i=1; i<
n_-1; ++i) {
546 Q_[i][i-1]=1.0/2*1.0/(
n_-1)*
dx_[i-1];
547 Q_[i][i]=1.0/(
n_-1)*
dx_[i]+1.0/(
n_-1)*
dx_[i-1];
548 Q_[i][i+1]=1.0/2*1.0/(
n_-1)*
dx_[i];
557 for (
Size i=0; i<
n_-1; ++i)
558 tmp_[i]=(Y_[i+1]-Y_[i])/
dx_[i]-(2.0*D_[i]+D_[i+1])*
dx_[i]/6.0;
566 QL_FAIL(
"FourthOrder not implemented yet");
570 for (
Size i=1; i<
n_-1; ++i)
578 for (
Size i=1; i<
n_-1; ++i) {
579 Real Smin = std::min(
S_[i-1],
S_[i]);
580 Real Smax = std::max(
S_[i-1],
S_[i]);
581 if(Smax+2.0*Smin == 0){
584 else if (Smin*Smax == 0)
590 tmp_[i] = 3.0*Smin*Smax/(Smax+2.0*Smin);
599 for (
Size i=2; i<
n_-2; ++i) {
600 if ((
S_[i-2]==
S_[i-1]) && (
S_[i]!=
S_[i+1]))
602 else if ((
S_[i-2]!=
S_[i-1]) && (
S_[i]==
S_[i+1]))
604 else if (
S_[i]==
S_[i-1])
606 else if ((
S_[i-2]==
S_[i-1]) && (
S_[i-1]!=
S_[i]) && (
S_[i]==
S_[i+1]))
609 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]));
616 for (
Size i=1; i<
n_-1; ++i) {
617 if (
S_[i-1]*
S_[i]<0.0)
624 tmp_[i] = 2.0/(1.0/
S_[i-1]+1.0/
S_[i]);
632 for (
Size i=1; i<
n_-1; ++i) {
635 if (
S_[i-1]*
S_[i]<=0.0)
641 tmp_[i] = (w1+w2)/(w1/
S_[i-1]+w2/
S_[i]);
648 else if (
S_[0]*
S_[1]<0) {
649 if (std::fabs(
tmp_[0])>std::fabs(3*
S_[0])) {
659 if (std::fabs(
tmp_[
n_-1])>std::fabs(3*
S_[
n_-2])) {
676 for (
Size i=0; i<
n_; ++i) {
679 correction =
tmp_[i]/std::fabs(
tmp_[i]) *
680 std::min<Real>(std::fabs(
tmp_[i]),
681 std::fabs(3.0*
S_[0]));
685 if (correction!=
tmp_[i]) {
686 tmp_[i] = correction;
689 }
else if (i==
n_-1) {
691 correction =
tmp_[i]/std::fabs(
tmp_[i]) *
692 std::min<Real>(std::fabs(
tmp_[i]),
693 std::fabs(3.0*
S_[
n_-2]));
697 if (correction!=
tmp_[i]) {
698 tmp_[i] = correction;
710 if ((
S_[i-1]-
S_[i-2])*(
S_[i]-
S_[i-1])>0.0) {
714 if (pm*pd>0.0 && pm*(
S_[i-1]-
S_[i-2])>0.0) {
715 M = std::max<Real>(M, 1.5*std::min(
716 std::fabs(pm),std::fabs(pd)));
721 if ((
S_[i]-
S_[i-1])*(
S_[i+1]-
S_[i])>0.0) {
724 if (pm*pu>0.0 && -pm*(
S_[i]-
S_[i-1])>0.0) {
725 M = std::max<Real>(M, 1.5*std::min(
726 std::fabs(pm),std::fabs(pu)));
730 if (
tmp_[i]*pm>0.0) {
731 correction =
tmp_[i]/std::fabs(
tmp_[i]) *
732 std::min(std::fabs(
tmp_[i]), M);
736 if (correction!=
tmp_[i]) {
737 tmp_[i] = correction;
746 for (
Size i=0; i<
n_-1; ++i) {
753 for (
Size i=1; i<
n_-1; ++i) {
757 (
a_[i-1]/2.0 +
dx_[i-1] *
758 (
b_[i-1]/3.0 +
dx_[i-1] *
c_[i-1]/4.0)));
781 return 2.0*
b_[j] + 6.0*
c_[j]*
dx_;
796 return (-((((a-c)*(
b-c)*(c-x)*z-(a-
d)*(
b-
d)*(
d-x)*w)*(a-x+
b-x)
797 +((a-c)*(
b-c)*z-(a-
d)*(
b-
d)*w)*(a-x)*(
b-x))*(a-
b)+
798 ((a-c)*(a-
d)*
v-(
b-c)*(
b-
d)*u)*(c-
d)*(c-x)*(
d-x)
799 +((a-c)*(a-
d)*(a-x)*
v-(
b-c)*(
b-
d)*(
b-x)*u)
801 ((a-
b)*(a-c)*(a-
d)*(
b-c)*(
b-
d)*(c-
d));
AkimaCubicInterpolation(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin)
1-D array used in linear algebra.
Cubic interpolation factory and traits
CubicInterpolation::DerivativeApprox da_
CubicInterpolation::BoundaryCondition rightType_
CubicInterpolation::BoundaryCondition leftType_
static const Size requiredPoints
Cubic(CubicInterpolation::DerivativeApprox da=CubicInterpolation::Kruger, bool monotonic=false, CubicInterpolation::BoundaryCondition leftCondition=CubicInterpolation::SecondDerivative, Real leftConditionValue=0.0, CubicInterpolation::BoundaryCondition rightCondition=CubicInterpolation::SecondDerivative, Real rightConditionValue=0.0)
Interpolation interpolate(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin) const
Cubic interpolation between discrete points.
const std::vector< Real > & cCoefficients() const
const std::vector< bool > & monotonicityAdjustments() const
const std::vector< Real > & bCoefficients() const
CubicInterpolation(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin, CubicInterpolation::DerivativeApprox da, bool monotonic, CubicInterpolation::BoundaryCondition leftCond, Real leftConditionValue, CubicInterpolation::BoundaryCondition rightCond, Real rightConditionValue)
const std::vector< Real > & aCoefficients() const
const std::vector< Real > & primitiveConstants() const
@ Kruger
Kruger approximation (local, monotonic, non-linear)
@ SplineOM2
Overshooting minimization 2nd derivative.
@ Parabolic
Parabolic approximation (local, non-monotonic, linear)
@ Harmonic
Weighted harmonic mean approximation (local, monotonic, non-linear)
@ FourthOrder
Fourth-order approximation (local, non-monotonic, linear)
@ SplineOM1
Overshooting minimization 1st derivative.
@ Akima
Akima approximation (local, non-monotonic, non-linear)
@ FritschButland
Fritsch-Butland approximation (local, monotonic, non-linear)
@ SecondDerivative
Match value of second derivative at end.
@ Periodic
Match first and second derivative at either end.
@ NotAKnot
Make second(-last) point an inactive knot.
@ FirstDerivative
Match value of end-slope.
const detail::CoefficientHolder & coeffs() const
CubicNaturalSpline(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin)
CubicSplineOvershootingMinimization1(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin)
CubicSplineOvershootingMinimization2(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin)
FritschButlandCubic(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin)
HarmonicCubic(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin)
basic template implementation
Size locate(Real x) const
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_
KrugerCubic(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin)
Matrix used in linear algebra.
MonotonicCubicNaturalSpline(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin)
MonotonicParabolic(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin)
Parabolic(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin)
Base implementation for tridiagonal operator.
Array solveFor(const Array &rhs) const
solve linear system for a given right-hand side
void setLastRow(Real, Real)
void setFirstRow(Real, Real)
void setMidRow(Size, Real, Real, Real)
std::vector< bool > monotonicityAdjustments_
virtual ~CoefficientHolder()=default
std::vector< Real > primitiveConst_
CoefficientHolder(Size n)
CubicInterpolation::DerivativeApprox da_
Real cubicInterpolatingPolynomialDerivative(Real a, Real b, Real c, Real d, Real u, Real v, Real w, Real z, Real x) const
Real value(Real x) const override
CubicInterpolation::BoundaryCondition rightType_
Real derivative(Real x) const override
CubicInterpolation::BoundaryCondition leftType_
CubicInterpolationImpl(const I1 &xBegin, const I1 &xEnd, const I2 &yBegin, CubicInterpolation::DerivativeApprox da, bool monotonic, CubicInterpolation::BoundaryCondition leftCondition, Real leftConditionValue, CubicInterpolation::BoundaryCondition rightCondition, Real rightConditionValue)
Real primitive(Real x) const override
Real secondDerivative(Real x) const override
#define QL_REQUIRE(condition, message)
throw an error if the given pre-condition is not verified
#define QL_FAIL(message)
throw an error (possibly with file and line information)
std::function< Real(Real)> b
std::size_t Size
size of a container
base class for 1-D interpolations
matrix used in linear algebra.
Matrix transpose(const Matrix &m)
Matrix inverse(const Matrix &m)
ext::shared_ptr< BlackVolTermStructure > v