#include "Math/WrappedTF1.h"
#include "Math/WrappedMultiTF1.h"
#include "TClass.h"
#include <cmath>
namespace ROOT {
namespace Math {
double WrappedTF1::fgEps = 0.001;
double WrappedMultiTF1::fgEps = 0.001;
WrappedTF1::WrappedTF1 ( TF1 & f ) :
fLinear(false),
fPolynomial(false),
fFunc(&f),
fX (),
fParams(f.GetParameters(),f.GetParameters()+f.GetNpar())
{
if (fFunc->GetMethodCall() ) fFunc->InitArgs(fX, &fParams.front() );
if (fFunc->GetNumber() >= 300 && fFunc->GetNumber() < 310) {
fLinear = true;
fPolynomial = true;
}
if (fFunc->IsLinear() ) {
unsigned int ip = 0;
fLinear = true;
while (fLinear && ip < fParams.size() ) {
fLinear &= (fFunc->GetLinearPart(ip) != 0) ;
ip++;
}
}
}
WrappedTF1::WrappedTF1(const WrappedTF1 & rhs) :
BaseFunc(),
BaseGradFunc(),
IGrad(),
fLinear(rhs.fLinear),
fPolynomial(rhs.fPolynomial),
fFunc(rhs.fFunc),
fX(),
fParams(rhs.fParams)
{
fFunc->InitArgs(fX,&fParams.front() );
}
WrappedTF1 & WrappedTF1::operator = (const WrappedTF1 & rhs) {
if (this == &rhs) return *this;
fLinear = rhs.fLinear;
fPolynomial = rhs.fPolynomial;
fFunc = rhs.fFunc;
fFunc->InitArgs(fX, &fParams.front() );
fParams = rhs.fParams;
return *this;
}
void WrappedTF1::ParameterGradient(double x, const double * par, double * grad ) const {
if (!fLinear) {
fFunc->SetParameters( par );
fFunc->GradientPar(&x,grad,fgEps);
}
else {
unsigned int np = NPar();
for (unsigned int i = 0; i < np; ++i)
grad[i] = DoParameterDerivative(x, par, i);
}
}
double WrappedTF1::DoDerivative( double x ) const {
double * p = (fParams.size() > 0) ? const_cast<double *>( &fParams.front()) : 0;
return fFunc->Derivative(x,p,fgEps);
}
double WrappedTF1::DoParameterDerivative(double x, const double * p, unsigned int ipar ) const {
if (! fLinear ) {
fFunc->SetParameters( p );
return fFunc->GradientPar(ipar, &x,fgEps);
}
else if (fPolynomial) {
return std::pow(x, static_cast<int>(ipar) );
}
else {
const TFormula * df = dynamic_cast<const TFormula*>( fFunc->GetLinearPart(ipar) );
assert(df != 0);
fX[0] = x;
return (const_cast<TFormula*> ( df) )->EvalPar( fX ) ;
}
}
void WrappedTF1::SetDerivPrecision(double eps) { fgEps = eps; }
double WrappedTF1::GetDerivPrecision( ) { return fgEps; }
WrappedMultiTF1::WrappedMultiTF1 (TF1 & f, unsigned int dim ) :
fLinear(false),
fPolynomial(false),
fOwnFunc(false),
fFunc(&f),
fDim(dim),
fParams(f.GetParameters(),f.GetParameters()+f.GetNpar())
{
if (fDim == 0) fDim = fFunc->GetNdim();
if (fFunc->IsLinear() ) {
unsigned int ip = 0;
fLinear = true;
while (fLinear && ip < fParams.size() ) {
fLinear &= (fFunc->GetLinearPart(ip) != 0) ;
ip++;
}
}
if (fDim == 1 && fFunc->GetNumber() >= 300 && fFunc->GetNumber() < 310) {
fLinear = true;
fPolynomial = true;
}
}
WrappedMultiTF1::WrappedMultiTF1(const WrappedMultiTF1 & rhs) :
BaseFunc(),
BaseParamFunc(),
fLinear(rhs.fLinear),
fPolynomial(rhs.fPolynomial),
fOwnFunc(rhs.fOwnFunc),
fFunc(rhs.fFunc),
fDim(rhs.fDim),
fParams(rhs.fParams)
{
if (fOwnFunc) SetAndCopyFunction(rhs.fFunc);
}
WrappedMultiTF1 & WrappedMultiTF1::operator= (const WrappedMultiTF1 & rhs) {
if (this == &rhs) return *this;
fLinear = rhs.fLinear;
fPolynomial = rhs.fPolynomial;
fOwnFunc = rhs.fOwnFunc;
fDim = rhs.fDim;
fParams = rhs.fParams;
if (fOwnFunc) {
TF1 * oldFunc = fFunc;
SetAndCopyFunction(rhs.fFunc);
delete oldFunc;
}
return *this;
}
void WrappedMultiTF1::ParameterGradient(const double * x, const double * par, double * grad ) const {
if (!fLinear) {
fFunc->SetParameters( par );
fFunc->GradientPar(x,grad,fgEps);
}
else {
unsigned int np = NPar();
for (unsigned int i = 0; i < np; ++i)
grad[i] = DoParameterDerivative(x, par, i);
}
}
double WrappedMultiTF1::DoParameterDerivative(const double * x, const double * p, unsigned int ipar ) const {
if (! fLinear ) {
fFunc->SetParameters( p );
return fFunc->GradientPar(ipar, x,fgEps);
}
if (fPolynomial) {
assert (fDim == 1);
return std::pow(x[0], static_cast<int>(ipar) );
}
else {
const TFormula * df = dynamic_cast<const TFormula*>( fFunc->GetLinearPart(ipar) );
assert(df != 0);
return (const_cast<TFormula*> ( df) )->EvalPar( x ) ;
}
}
void WrappedMultiTF1::SetDerivPrecision(double eps) { fgEps = eps; }
double WrappedMultiTF1::GetDerivPrecision( ) { return fgEps; }
void WrappedMultiTF1::SetAndCopyFunction(const TF1 * f) {
const TF1 * funcToCopy = (f) ? f : fFunc;
TF1 * fnew = (TF1*) funcToCopy->IsA()->New();
funcToCopy->Copy(*fnew);
fFunc = fnew;
fOwnFunc = true;
}
}
}