Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move transformation used in GlobalBootstrap into Traits #2135

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 5 additions & 19 deletions ql/termstructures/globalbootstrap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ template <class Curve> class GlobalBootstrap {
The additional helpers are treated like the usual rate helpers, but no standard pillar dates are added for them.

WARNING: This class is known to work with Traits Discount, ZeroYield, Forward, i.e. the usual traits for IR curves
in QL. It requires Traits::minValueGlobal() and Traits::maxValueGlobal() to be implemented. Also, check the usage
in QL. It requires Traits::transformDirect() and Traits::transformInverse() to be implemented. Also, check the usage
of Traits::updateGuess(), Traits::guess() in this class.
*/
GlobalBootstrap(std::vector<ext::shared_ptr<typename Traits::helper> > additionalHelpers,
Expand Down Expand Up @@ -200,6 +200,7 @@ template <class Curve> void GlobalBootstrap<Curve>::initialize() const {
// but reasonable numbers might be needed for the whole data vector
// because, e.g., of interpolation's early checks
ts_->data_ = std::vector<Real>(dates.size(), Traits::initialValue(ts_));
validCurve_ = false;
}
initialized_ = true;
}
Expand Down Expand Up @@ -242,26 +243,10 @@ template <class Curve> void GlobalBootstrap<Curve>::calculate() const {
ts_->interpolator_.interpolate(ts_->times_.begin(), ts_->times_.end(), ts_->data_.begin());
}

// determine bounds, we use an unconstrained optimisation transforming the free variables to [lowerBound,upperBound]
const Size numberBounds = ts_->times_.size() - 1;
std::vector<Real> lowerBounds(numberBounds), upperBounds(numberBounds);
for (Size i = 0; i < numberBounds; ++i) {
lowerBounds[i] = Traits::minValueGlobal(i + 1, ts_, validCurve_);
upperBounds[i] = Traits::maxValueGlobal(i + 1, ts_, validCurve_);
}

// setup cost function
auto transformDirect = [&](const Real x, const Size i) {
return (std::atan(x) + M_PI_2) / M_PI * (upperBounds[i] - lowerBounds[i]) + lowerBounds[i];
};

auto transformInverse = [&](const Real y, const Size i) {
return std::tan((y - lowerBounds[i]) * M_PI / (upperBounds[i] - lowerBounds[i]) - M_PI_2);
};

SimpleCostFunction cost([&](const Array& x) {
for (Size i = 0; i < x.size(); ++i) {
Traits::updateGuess(ts_->data_, transformDirect(x[i], i), i + 1);
Traits::updateGuess(ts_->data_, Traits::transformDirect(x[i], i + 1, ts_), i + 1);
}
ts_->interpolation_.update();
std::vector<Real> result(numberHelpers_);
Expand All @@ -280,12 +265,13 @@ template <class Curve> void GlobalBootstrap<Curve>::calculate() const {
});

// setup guess
const Size numberBounds = ts_->times_.size() - 1;
Array guess(numberBounds);
for (Size i = 0; i < numberBounds; ++i) {
// just pass zero as the first alive helper, it's not used in the standard QL traits anyway
// update ts_->data_ since Traits::guess() usually depends on previous values
Traits::updateGuess(ts_->data_, Traits::guess(i + 1, ts_, validCurve_, 0), i + 1);
guess[i] = transformInverse(ts_->data_[i + 1], i);
guess[i] = Traits::transformInverse(ts_->data_[i + 1], i + 1, ts_);
}

// setup problem
Expand Down
41 changes: 20 additions & 21 deletions ql/termstructures/yield/bootstraptraits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ namespace QuantLib {
namespace detail {
const Real avgRate = 0.05;
const Real maxRate = 1.0;
const Real maxDF = 10.0;
}

//! Discount-curve traits
Expand Down Expand Up @@ -102,16 +101,16 @@ namespace QuantLib {
return c->data()[i-1] * std::exp(detail::maxRate * dt);
}

// possible constraints for global optimization
// transformation to add constraints to an unconstrained optimization
template <class C>
static Real minValueGlobal(Size i, const C* c, bool validData)
static Real transformDirect(Real x, Size i, const C* c)
{
return 0;
return std::exp(x);
}
template <class C>
static Real maxValueGlobal(Size i, const C* c, bool validData)
static Real transformInverse(Real x, Size i, const C* c)
{
return detail::maxDF;
return std::log(x);
}

// root-finding update
Expand Down Expand Up @@ -193,16 +192,16 @@ namespace QuantLib {
return detail::maxRate;
}

// possible constraints for global optimization
// transformation to add constraints to an unconstrained optimization
template <class C>
static Real minValueGlobal(Size i, const C* c, bool validData)
static Real transformDirect(Real x, Size i, const C* c)
{
return -detail::maxRate;
return x;
}
template <class C>
static Real maxValueGlobal(Size i, const C* c, bool validData)
static Real transformInverse(Real x, Size i, const C* c)
{
return detail::maxRate;
return x;
}

// root-finding update
Expand Down Expand Up @@ -286,16 +285,16 @@ namespace QuantLib {
return detail::maxRate;
}

// possible constraints for global optimization
// transformation to add constraints to an unconstrained optimization
template <class C>
static Real minValueGlobal(Size i, const C* c, bool validData)
static Real transformDirect(Real x, Size i, const C* c)
{
return -detail::maxRate;
return x;
}
template <class C>
static Real maxValueGlobal(Size i, const C* c, bool validData)
static Real transformInverse(Real x, Size i, const C* c)
{
return detail::maxRate;
return x;
}

// root-finding update
Expand Down Expand Up @@ -381,16 +380,16 @@ namespace QuantLib {
return detail::maxRate;
}

// possible constraints for global optimization
// transformation to add constraints to an unconstrained optimization
template <class C>
static Real minValueGlobal(Size i, const C* c, bool validData)
static Real transformDirect(Real x, Size i, const C* c)
{
return std::max(-detail::maxRate, -1.0 / c->times()[i] + 1E-8);
return std::exp(x) + (-1.0 / c->times()[i] + 1E-8);
}
template <class C>
static Real maxValueGlobal(Size i, const C* c, bool validData)
static Real transformInverse(Real x, Size i, const C* c)
{
return detail::maxRate;
return std::log(x - (-1.0 / c->times()[i] + 1E-8));
}

// root-finding update
Expand Down
Loading