1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
|
// @(#)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/IFunctionfwd.h"
#include "Math/IParamFunctionfwd.h"
#include "Math/FitMethodFunction.h"
#include "Math/MinimTransformFunction.h"
#include "Math/Error.h"
#include "Fit/ParameterSettings.h"
#include <cassert>
#include <iostream>
#include <iomanip>
#include <cmath>
#include <algorithm>
#include <functional>
#include <ctype.h> // need to use c version of tolower defined here
#include <limits>
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<unsigned int, std::pair<double, double> >::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<double>::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<double>::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<double>::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<double>::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<double>::infinity() &&
upper == std::numeric_limits<double>::infinity() ) ) {
fBounds.erase(ivar);
fVarTypes[ivar] = kDefault;
}
else if (lower == upper)
FixVariable(ivar);
else {
if (lower == - std::numeric_limits<double>::infinity() )
fVarTypes[ivar] = kLowBound;
else if (upper == std::numeric_limits<double>::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<double>::infinity() )
fVarTypes[ivar] = kLowBound;
else if (fBounds[ivar].second == std::numeric_limits<double>::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<std::string>::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<const ROOT::Math::IMultiGradFunction *>( 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<double> & 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<double>(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<const IMultiGradFunction *>(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<const ROOT::Math::IMultiGradFunction *>(fObjFunc);
}
const MinimTransformFunction * BasicMinimizer::TransformFunction() const {
return dynamic_cast<const MinimTransformFunction *>(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
|