// @(#)root/mathmore:$Id$ // Author: L. Moneta Oct 2012 /********************************************************************** * * * Copyright (c) 2006 LCG ROOT Math Team, CERN/PH-SFT * * * * * **********************************************************************/ // Implementation file for class BasicMinimizer #include "Math/BasicMinimizer.h" #include "Math/IFunction.h" #include "Math/FitMethodFunction.h" #include "Math/MinimTransformFunction.h" #include "Math/Error.h" #include "Fit/ParameterSettings.h" #include #include #include #include #include #include #include // need to use c version of tolower defined here #include namespace ROOT { namespace Math { BasicMinimizer::BasicMinimizer( ) : fDim(0), fObjFunc(0), fMinVal(0) { fValues.reserve(10); fNames.reserve(10); fSteps.reserve(10); int niter = ROOT::Math::MinimizerOptions::DefaultMaxIterations(); if (niter <=0 ) niter = 1000; SetMaxIterations(niter); SetPrintLevel(ROOT::Math::MinimizerOptions::DefaultPrintLevel()); } BasicMinimizer::~BasicMinimizer () { if (fObjFunc) delete fObjFunc; } bool BasicMinimizer::SetVariable(unsigned int ivar, const std::string & name, double val, double step) { // set variable in minimizer - support only free variables // no transformation implemented - so far if (ivar > fValues.size() ) return false; if (ivar == fValues.size() ) { fValues.push_back(val); fNames.push_back(name); fSteps.push_back(step); fVarTypes.push_back(kDefault); } else { fValues[ivar] = val; fNames[ivar] = name; fSteps[ivar] = step; fVarTypes[ivar] = kDefault; // remove bounds if needed std::map >::iterator iter = fBounds.find(ivar); if ( iter != fBounds.end() ) fBounds.erase (iter); } return true; } bool BasicMinimizer::SetLowerLimitedVariable(unsigned int ivar, const std::string & name, double val, double step, double lower) { // set lower limited variable bool ret = SetVariable(ivar, name, val, step); if (!ret) return false; const double upper = std::numeric_limits::infinity(); fBounds[ivar] = std::make_pair( lower, upper); fVarTypes[ivar] = kLowBound; return true; } bool BasicMinimizer::SetUpperLimitedVariable(unsigned int ivar, const std::string & name, double val, double step, double upper ) { // set upper limited variable bool ret = SetVariable(ivar, name, val, step); if (!ret) return false; const double lower = -std::numeric_limits::infinity(); fBounds[ivar] = std::make_pair( lower, upper); fVarTypes[ivar] = kUpBound; return true; } bool BasicMinimizer::SetLimitedVariable(unsigned int ivar, const std::string & name, double val, double step, double lower, double upper) { // set double bounded variable bool ret = SetVariable(ivar, name, val, step); if (!ret) return false; fBounds[ivar] = std::make_pair( lower, upper); fVarTypes[ivar] = kBounds; return true; } bool BasicMinimizer::SetFixedVariable(unsigned int ivar , const std::string & name , double val ) { /// set fixed variable bool ret = SetVariable(ivar, name, val, 0.); if (!ret) return false; fVarTypes[ivar] = kFix; return true; } bool BasicMinimizer::SetVariableValue(unsigned int ivar, double val) { // set variable value in minimizer // no change to transformation or variable status if (ivar > fValues.size() ) return false; fValues[ivar] = val; return true; } bool BasicMinimizer::SetVariableValues( const double * x) { // set all variable values in minimizer if (x == 0) return false; std::copy(x,x+fValues.size(), fValues.begin() ); return true; } bool BasicMinimizer::SetVariableStepSize(unsigned int ivar, double step) { // set step size if (ivar > fValues.size() ) return false; fSteps[ivar] = step; return true; } bool BasicMinimizer::SetVariableLowerLimit(unsigned int ivar, double lower) { // set variable lower limit double upper = (fBounds.count(ivar)) ? fBounds[ivar].second : std::numeric_limits::infinity(); return SetVariableLimits(ivar, lower, upper); } bool BasicMinimizer::SetVariableUpperLimit(unsigned int ivar, double upper) { // set variable upper limit double lower = (fBounds.count(ivar)) ? fBounds[ivar].first : - std::numeric_limits::infinity(); return SetVariableLimits(ivar, lower, upper); } bool BasicMinimizer::SetVariableLimits(unsigned int ivar, double lower, double upper) { // set variable limits (remove limits if lower >= upper) if (ivar > fVarTypes.size() ) return false; // if limits do not exists add them or update fBounds[ivar] = std::make_pair( lower, upper); if (lower > upper || (lower == - std::numeric_limits::infinity() && upper == std::numeric_limits::infinity() ) ) { fBounds.erase(ivar); fVarTypes[ivar] = kDefault; } else if (lower == upper) FixVariable(ivar); else { if (lower == - std::numeric_limits::infinity() ) fVarTypes[ivar] = kLowBound; else if (upper == std::numeric_limits::infinity() ) fVarTypes[ivar] = kUpBound; else fVarTypes[ivar] = kBounds; } return true; } bool BasicMinimizer::FixVariable(unsigned int ivar) { // fix variable if (ivar > fVarTypes.size() ) return false; fVarTypes[ivar] = kFix; return true; } bool BasicMinimizer::ReleaseVariable(unsigned int ivar) { // fix variable if (ivar > fVarTypes.size() ) return false; if (fBounds.count(ivar) == 0) { fVarTypes[ivar] = kDefault; return true; } if (fBounds[ivar].first == - std::numeric_limits::infinity() ) fVarTypes[ivar] = kLowBound; else if (fBounds[ivar].second == std::numeric_limits::infinity() ) fVarTypes[ivar] = kUpBound; else fVarTypes[ivar] = kBounds; return true; } bool BasicMinimizer::IsFixedVariable(unsigned int ivar) const { if (ivar > fVarTypes.size() ) return false; return (fVarTypes[ivar] == kFix ) ; } bool BasicMinimizer::GetVariableSettings(unsigned int ivar, ROOT::Fit::ParameterSettings & varObj) const { if (ivar > fValues.size() ) return false; assert(fValues.size() == fNames.size() && fValues.size() == fVarTypes.size() ); varObj.Set(fNames[ivar],fValues[ivar],fSteps[ivar]); std::map< unsigned int , std::pair< double, double> >::const_iterator itr = fBounds.find(ivar); if (itr != fBounds.end() ) { double lower = (itr->second).first; double upper = (itr->second).second; if (fVarTypes[ivar] == kLowBound) varObj.SetLowerLimit( lower ); if (fVarTypes[ivar] == kUpBound) varObj.SetUpperLimit( upper ); else varObj.SetLimits( lower,upper); } if (fVarTypes[ivar] == kFix ) varObj.Fix(); return true; } std::string BasicMinimizer::VariableName(unsigned int ivar) const { if (ivar > fNames.size() ) return ""; return fNames[ivar]; } int BasicMinimizer::VariableIndex(const std::string & name) const { std::vector::const_iterator itr = std::find( fNames.begin(), fNames.end(), name); if (itr == fNames.end() ) return -1; return itr - fNames.begin(); } void BasicMinimizer::SetFunction(const ROOT::Math::IMultiGenFunction & func) { // set the function to minimizer fObjFunc = func.Clone(); fDim = fObjFunc->NDim(); } void BasicMinimizer::SetFunction(const ROOT::Math::IMultiGradFunction & func) { // set the function to minimize fObjFunc = dynamic_cast( func.Clone()); assert(fObjFunc != 0); fDim = fObjFunc->NDim(); } bool BasicMinimizer::CheckDimension() const { unsigned int npar = fValues.size(); if (npar == 0 || npar < fDim ) { MATH_ERROR_MSGVAL("BasicMinimizer::CheckDimension","Wrong number of parameters",npar); return false; } return true; } bool BasicMinimizer::CheckObjFunction() const { if (fObjFunc == 0) { MATH_ERROR_MSG("BasicMinimizer::CheckFunction","Function has not been set"); return false; } return true; } MinimTransformFunction * BasicMinimizer::CreateTransformation(std::vector & startValues, const ROOT::Math::IMultiGradFunction * func) { bool doTransform = (fBounds.size() > 0); unsigned int ivar = 0; while (!doTransform && ivar < fVarTypes.size() ) { doTransform = (fVarTypes[ivar++] != kDefault ); } startValues = std::vector(fValues.begin(), fValues.end() ); MinimTransformFunction * trFunc = 0; // in case of transformation wrap objective function in a new transformation function // and transform from external variables to internals one // Transformations are supported only for gradient function const IMultiGradFunction * gradObjFunc = (func) ? func : dynamic_cast(fObjFunc); doTransform &= (gradObjFunc != 0); if (doTransform) { // minim transform function manages the passed function pointer (gradObjFunc) trFunc = new MinimTransformFunction ( gradObjFunc, fVarTypes, fValues, fBounds ); // transform from external to internal trFunc->InvTransformation(&fValues.front(), &startValues[0]); // size can be different since internal parameter can have smaller size // if there are fixed parameters startValues.resize( trFunc->NDim() ); // no need to save fObjFunc since trFunc will manage it fObjFunc = trFunc; } else { if (func) fObjFunc = func; // to manege the passed function object } // std::cout << " f has transform " << doTransform << " " << fBounds.size() << " " << startValues.size() << " ndim " << fObjFunc->NDim() << std::endl; std::cout << "InitialValues external : "; // for (int i = 0; i < fValues.size(); ++i) std::cout << fValues[i] << " "; // std::cout << "\n"; // std::cout << "InitialValues internal : "; // for (int i = 0; i < startValues.size(); ++i) std::cout << startValues[i] << " "; // std::cout << "\n"; return trFunc; } bool BasicMinimizer::Minimize() { // do nothing return false; } void BasicMinimizer::SetFinalValues(const double * x) { // check to see if a transformation need to be applied const MinimTransformFunction * trFunc = TransformFunction(); if (trFunc) { assert(fValues.size() >= trFunc->NTot() ); trFunc->Transformation(x, &fValues[0]); } else { // case of no transformation applied assert( fValues.size() >= NDim() ); std::copy(x, x + NDim(), fValues.begin() ); } } void BasicMinimizer::PrintResult() const { int pr = std::cout.precision(18); std::cout << "FVAL = " << fMinVal << std::endl; std::cout.precision(pr); // std::cout << "Edm = " << fState.Edm() << std::endl; std::cout << "Niterations = " << NIterations() << std::endl; unsigned int ncalls = NCalls(); if (ncalls) std::cout << "NCalls = " << ncalls << std::endl; for (unsigned int i = 0; i < fDim; ++i) std::cout << fNames[i] << "\t = " << fValues[i] << std::endl; } const ROOT::Math::IMultiGradFunction * BasicMinimizer::GradObjFunction() const { return dynamic_cast(fObjFunc); } const MinimTransformFunction * BasicMinimizer::TransformFunction() const { return dynamic_cast(fObjFunc); } unsigned int BasicMinimizer::NFree() const { // number of free variables unsigned int nfree = fValues.size(); for (unsigned int i = 0; i < fVarTypes.size(); ++i) if (fVarTypes[i] == kFix) nfree--; return nfree; } } // end namespace Math } // end namespace ROOT