Following is a demo for using Quantlib's Levenberg Marquardt optimizer, which is based on MINPACK's optimizer
It demonstrates fitting a function
f(x)=a*x*x*x + b*x*x + c
Following are input supplied to the optimizer:
1.A vector of independent variables which is x
2.A vector of observed values which is f(x)
3.Vector of initial guess paremeters a,b,c
4.Implementation of the function that returns difference between the observed values and the fitted values. This is done by changing code of fcn function in lmdif.hpp file.
Following are details:
1.Create new project in C++ - win32 console application. Uncheck option "precompiled header" in Application Settings dialog
2.click on Project->Add new item. Select code and C++ file.Enter name lmdif.hpp
3.Copy all the code from here :
http://quantlib.svn.sourceforge.net/viewvc/*checkout*/quantlib/branches/DevCycle/Rev14441/QuantLib/ql/math/optimization/lmdif.cpp?revision=10026Paste it into file lmdif.hpp
4.Edit lmdiff.hpp file
Comment out line 64 : #include <ql/math/optimization/levenbergmarquardt.hpp>
Comment out line 270: QuantLib::LevenbergMarquardt::fcn(m, n, x, fvec, iflag);
5.Implement function to be minimized
Modify the function fcn in file lmdif.hpp as follows:
void fcn(int m,int n, double* x, double* fvec,int *iflag)
{
//QuantLib::LevenbergMarquardt::fcn(m, n, x, fvec, iflag);
double a=x[0];
double b=x[1];
double c=x[2];
for (int i=0;i<m;i++)
{
double xi=independent_variables[i];
double observed_value=oberved_values[i];
double fitted_value=a*xi*xi*xi + b*xi*xi + c;
fvec[i]=fitted_value-observed_value;
}
}
6. In the main.cpp file call QuantLib::MINPACK::lmdif to minimize the function. This is the code:
#include "stdafx.h"
double* independent_variables;
double* oberved_values;
#include "lmdif.hpp"
int _tmain(int argc, _TCHAR* argv[])
{
int m=10; //no. of observation variables
int n=3; //no. of paremeters
independent_variables = new double[m]; //this is the vector of independent variables
oberved_values = new double[m]; //this is the vector of observed variables to be fitted
for (int i=0;i<m;i++)
{
independent_variables[i]=i*2+5;
double xi=independent_variables[i];
double yi=16*xi*xi*xi + 12*xi*xi + 15;
oberved_values[i]=yi;
}
double* x=new double[n]; //initial estimate of parameters vector
x[0]=0.1;
x[1]=0.1;
x[2]=0.1;
double* fvec=new double[m]; //no need to populate
double ftol=1e-08; //tolerance
double xtol=1e-08; //tolerance
double gtol=1e-08; //tolerance
int maxfev=400; //maximum function evaluations
double epsfcn=1e-08; //tolerance
double* diag=new double[n]; //some internal thing
int mode=1; //some internal thing
double factor=1; // a default recommended value
int nprint=0; //don't know what it does
int info=0; //output variable
int nfev=0; //output variable will store no. of function evals
double* fjac=new double[m*n]; //output array of jacobian
int ldfjac=m; //recommended setting
int* ipvt=new int[n]; //for internal use
double* qtf=new double[n]; //for internal use
double* wa1=new double[n]; //for internal use
double* wa2=new double[n]; //for internal use
double* wa3=new double[n]; //for internal use
double* wa4=new double[m]; //for internal use
QuantLib::MINPACK::lmdif( m, n, x, fvec, ftol,
xtol, gtol, maxfev, epsfcn, diag, mode, factor,
nprint, &info, &nfev, fjac,ldfjac, ipvt, qtf,
wa1, wa2, wa3, wa4);
//the below is output result. compare it with the values used to generate
//observed variables
double a=x[0];
double b=x[1];
double c=x[2];
return 0;
}