#include "TLinearMinimizer.h"
#include "Math/IParamFunction.h"
#include "TF1.h"
#include "TUUID.h"
#include "TROOT.h"
#include "Fit/Chi2FCN.h"
#include "TLinearFitter.h"
#include <iostream>
#include <cassert>
#include <algorithm>
#include <functional>
template<class Func>
struct BasisFunction {
BasisFunction(const Func & f, int k) :
fKPar(k),
fFunc(&f)
{}
double operator() ( double * x, double *) {
return fFunc->ParameterDerivative(x,fKPar);
}
unsigned int fKPar;
const Func * fFunc;
};
ClassImp(TLinearMinimizer)
TLinearMinimizer::TLinearMinimizer(int ) :
fRobust(false),
fDim(0),
fNFree(0),
fMinVal(0),
fObjFunc(0),
fFitter(0)
{
}
TLinearMinimizer::TLinearMinimizer ( const char * type ) :
fRobust(false),
fDim(0),
fNFree(0),
fMinVal(0),
fObjFunc(0),
fFitter(0)
{
std::string algoname(type);
std::transform(algoname.begin(), algoname.end(), algoname.begin(), (int(*)(int)) tolower );
if (algoname.find("robust") != std::string::npos) fRobust = true;
}
TLinearMinimizer::~TLinearMinimizer()
{
if (fFitter) delete fFitter;
}
TLinearMinimizer::TLinearMinimizer(const TLinearMinimizer &) :
Minimizer()
{
}
TLinearMinimizer & TLinearMinimizer::operator = (const TLinearMinimizer &rhs)
{
if (this == &rhs) return *this;
return *this;
}
void TLinearMinimizer::SetFunction(const ROOT::Math::IMultiGenFunction & ) {
Error("TLinearMinimizer::SetFunction(IMultiGenFunction)","Wrong type of function used for Linear fitter");
}
void TLinearMinimizer::SetFunction(const ROOT::Math::IMultiGradFunction & objfunc) {
typedef ROOT::Fit::Chi2FCN<ROOT::Math::IMultiGradFunction> Chi2Func;
const Chi2Func * chi2func = dynamic_cast<const Chi2Func *>(&objfunc);
if (chi2func ==0) {
Error("TLinearMinimizer::SetFunction(IMultiGradFunction)","Wrong type of function used for Linear fitter");
return;
}
fObjFunc = chi2func;
typedef ROOT::Math::IParamMultiGradFunction ModelFunc;
const ModelFunc * modfunc = dynamic_cast<const ModelFunc*>( &(chi2func->ModelFunction()) );
assert(modfunc != 0);
fDim = chi2func->NDim();
fNFree = fDim;
TObjArray flist;
for (unsigned int i = 0; i < fDim; ++i) {
BasisFunction<ModelFunc > bf(*modfunc,i);
TUUID u;
std::string fname = "_LinearMinimimizer_BasisFunction_" +
std::string(u.AsString() );
TF1 * f = new TF1(fname.c_str(),ROOT::Math::ParamFunctor(bf));
flist.Add(f);
gROOT->GetListOfFunctions()->Remove(f);
}
if (fFitter) delete fFitter;
fFitter = new TLinearFitter( static_cast<const ModelFunc::BaseFunc&>(*modfunc).NDim() );
fFitter->StoreData(fRobust);
fFitter->SetBasisFunctions(&flist);
const ROOT::Fit::BinData & data = chi2func->Data();
for (unsigned int i = 0; i < data.Size(); ++i) {
double y = 0;
const double * x = data.GetPoint(i,y);
double ey = 1;
if (! data.Opt().fErrors1) {
ey = data.Error(i);
}
fFitter->AddPoint( const_cast<double *>(x) , y, ey);
}
}
bool TLinearMinimizer::SetFixedVariable(unsigned int ivar, const std::string & , double val) {
if (!fFitter) return false;
fFitter->FixParameter(ivar, val);
return true;
}
bool TLinearMinimizer::Minimize() {
if (fFitter == 0 || fObjFunc == 0) return false;
int iret = 0;
if (!fRobust)
iret = fFitter->Eval();
else {
double h = Tolerance();
if (PrintLevel() > 0)
std::cout << "TLinearMinimizer: Robust fitting with h = " << h << std::endl;
iret = fFitter->EvalRobust(h);
}
fStatus = iret;
if (iret != 0) {
Warning("Minimize","TLinearFitter failed in finding the solution");
return false;
}
fParams.resize( fDim);
if (!fRobust) fErrors.resize( fDim);
for (unsigned int i = 0; i < fDim; ++i) {
fParams[i] = fFitter->GetParameter( i);
if (!fRobust) fErrors[i] = fFitter->GetParError( i );
}
fCovar.resize(fDim*fDim);
double * cov = fFitter->GetCovarianceMatrix();
if (!fRobust && cov) std::copy(cov,cov+fDim*fDim,fCovar.begin() );
fMinVal = (*fObjFunc)(&fParams.front());
return true;
}