Constrained fitting in QuantLib
Below is a short example illustrating fitting of a function to observables, demonstrating also how to put some constraints on the parameters. Placing such constraints is useful when, for example, a model is well defined for certain values of the parameters.
// Bojan Nikolic <bojan@bnikolic.co.uk>
//
// Example of using QuantLib Optimisation routines to do a contrained
// fit
#include <iostream>
#include <boost/assign/list_of.hpp>
#include <ql/quantlib.hpp>
/*! This class defines the problem to be optimised -- in this case
fitting a sine wave to numbr of observed points
*/
class SinFit:
public QuantLib::LeastSquareProblem
{
const QuantLib::Array x_;
const QuantLib::Array yobs_;
public :
/*!
*/
SinFit(const std::vector<double> &x,
const std::vector<double> &yobs):
x_(QuantLib::Array(x.begin(), x.end())),
yobs_(QuantLib::Array(yobs.begin(), yobs.end()))
{}
//! Size of the least square problem
virtual size_t size()
{
return x_.size();
}
//! return function and target values
virtual void targetAndValue(const QuantLib::Array& p,
QuantLib::Array& target,
QuantLib::Array& y)
{
target = yobs_;
for (size_t i=0; i<x_.size(); ++i)
{
y[i] = p[0]*std::sin(p[1]+p[2]*x_[i]);
}
}
//! return function, target and first derivatives values
virtual void targetValueAndGradient(const QuantLib::Array& p,
QuantLib::Matrix& dy,
QuantLib::Array& target,
QuantLib::Array& y)
{
target = yobs_;
const double a=p[0];
const double b=p[1];
const double c=p[2];
for (size_t i=0; i<x_.size(); ++i)
{
y[i] = a*std::sin(b+c*x_[i]);
dy[i][0]=std::sin(b+c*x_[i]);
dy[i][1]=a*std::cos(b+c*x_[i]);
dy[i][2]=a*x_[i]*std::cos(b+c*x_[i]);
}
}
};
int main(void)
{
std::vector<double> x=boost::assign::list_of(0)(0.1)(0.2)(0.3)(1.0)(2.0);
std::vector<double> yobs(x.size());
for(size_t i=0; i<x.size(); ++i)
yobs[i]=0.5*std::sin(1.1*x[i]);
SinFit f(x, yobs);
QuantLib::Real accuracy = 1e-20;
QuantLib::Size maxiter = 10000;
/* Starting point for the minimisation */
QuantLib::Array p0(3, 1.0);
{ // no Constraint optimisation
QuantLib::NoConstraint nc;
QuantLib::NonLinearLeastSquare lsqnonlin(nc,
accuracy,
maxiter);
// Set initial values
lsqnonlin.setInitialValue(p0);
QuantLib::Array solution = lsqnonlin.perform(f);
std::cout<<solution<<std::endl;
}
{ // All parameters must be positive
QuantLib::PositiveConstraint pc;
QuantLib::NonLinearLeastSquare lsqnonlin(pc,
accuracy,
maxiter);
// Set initial values
lsqnonlin.setInitialValue(p0);
QuantLib::Array solution = lsqnonlin.perform(f);
std::cout<<solution<<std::endl;
}
{ // Box constraint containing the optimum. Note that the same
// bounds applied to all of the parameters
QuantLib::BoundaryConstraint bc(-1,2);
QuantLib::NonLinearLeastSquare lsqnonlin(bc,
accuracy,
maxiter);
// Set initial values
lsqnonlin.setInitialValue(p0);
QuantLib::Array solution = lsqnonlin.perform(f);
std::cout<<solution<<std::endl;
}
{ // Box constraint not containing the optimum
QuantLib::BoundaryConstraint bc(0.7,2);
QuantLib::NonLinearLeastSquare lsqnonlin(bc,
accuracy,
maxiter);
// Set initial values
lsqnonlin.setInitialValue(p0);
QuantLib::Array solution = lsqnonlin.perform(f);
std::cout<<solution<<std::endl;
}
}