CMS 3D CMS Logo

HybridMinimizer.cc
Go to the documentation of this file.
1 // @(#)root/minuit2:$Id$
2 // Author: L. Moneta Wed Oct 18 11:48:00 2006
3 
4 /**********************************************************************
5  * *
6  * Copyright (c) 2006 LCG ROOT Math Team, CERN/PH-SFT *
7  * *
8  * *
9  **********************************************************************/
10 
11 // by lhx: Note copied and modifed from the Minuit2Minimizer to suit our purpose
12 // Changes mainly to make the SetMinimizerType public so that user can re-new to
13 // different minimizer...
14 // Implementation file for class HybridMinimizer
15 
17 
18 #include "Math/IFunction.h"
19 #include "Math/IOptions.h"
20 
21 #include "Minuit2/FCNAdapter.h"
22 #include "Minuit2/FumiliFCNAdapter.h"
23 #include "Minuit2/FCNGradAdapter.h"
24 #include "Minuit2/FunctionMinimum.h"
25 #include "Minuit2/MnMigrad.h"
26 #include "Minuit2/MnMinos.h"
27 #include "Minuit2/MinosError.h"
28 #include "Minuit2/MnHesse.h"
29 #include "Minuit2/MinuitParameter.h"
30 #include "Minuit2/MnUserFcn.h"
31 #include "Minuit2/MnPrint.h"
32 #include "Minuit2/FunctionMinimum.h"
33 #include "Minuit2/VariableMetricMinimizer.h"
34 #include "Minuit2/SimplexMinimizer.h"
35 #include "Minuit2/CombinedMinimizer.h"
36 #include "Minuit2/ScanMinimizer.h"
37 #include "Minuit2/FumiliMinimizer.h"
38 #include "Minuit2/MnParameterScan.h"
39 #include "Minuit2/MnContours.h"
40 
41 #include <cassert>
42 #include <iostream>
43 #include <algorithm>
44 #include <functional>
45 
46 namespace PSFitter{
47 
48  using namespace ROOT::Minuit2;
49 
50  // functions needed to control siwthc off of Minuit2 printing level
51 #ifdef USE_ROOT_ERROR
52  int TurnOffPrintInfoLevel() {
53  // switch off Minuit2 printing of INFO message (cut off is 1001)
54  int prevErrorIgnoreLevel = gErrorIgnoreLevel;
55  if (prevErrorIgnoreLevel < 1001) {
56  gErrorIgnoreLevel = 1001;
57  return prevErrorIgnoreLevel;
58  }
59  return -2; // no op in this case
60 }
61 
62 void RestoreGlobalPrintLevel(int value) {
64 }
65 #else
66  // dummy functions
67  int TurnOffPrintInfoLevel() { return -1; }
68  int ControlPrintLevel( ) { return -1;}
69  void RestoreGlobalPrintLevel(int ) {}
70 #endif
71 
72 
74  Minimizer(),
75  fDim(0),
76  fMinimizer(nullptr),
77  fMinuitFCN(nullptr),
78  fMinimum(nullptr)
79 {
80  // Default constructor implementation depending on minimizer type
81  SetMinimizerType(type);
82 }
83 
85  Minimizer(),
86  fDim(0),
90 {
91  // constructor from a string
92 
93  std::string algoname(type);
94  // tolower() is not an std function (Windows)
95  std::transform(algoname.begin(), algoname.end(), algoname.begin(), (int(*)(int)) tolower );
96 
98  if (algoname == "simplex") algoType = kSimplex;
99  if (algoname == "minimize" ) algoType = kCombined;
100  if (algoname == "scan" ) algoType = kScan;
101  if (algoname == "fumili" ) algoType = kFumili;
102 
103  SetMinimizerType(algoType);
104 }
105 
107  // Set minimizer algorithm type
108  fUseFumili = false;
109 
110  if (fMinimizer) delete fMinimizer;
111 
112  switch (type) {
113  case kMigrad:
114  //std::cout << "HybridMinimizer: minimize using MIGRAD " << std::endl;
115  SetMinimizer( new ROOT::Minuit2::VariableMetricMinimizer() );
116  return;
117  case kSimplex:
118  //std::cout << "HybridMinimizer: minimize using SIMPLEX " << std::endl;
119  SetMinimizer( new ROOT::Minuit2::SimplexMinimizer() );
120  return;
121  case kCombined:
122  SetMinimizer( new ROOT::Minuit2::CombinedMinimizer() );
123  return;
124  case kScan:
125  SetMinimizer( new ROOT::Minuit2::ScanMinimizer() );
126  return;
127  case kFumili:
128  SetMinimizer( new ROOT::Minuit2::FumiliMinimizer() );
129  fUseFumili = true;
130  return;
131  default:
132  //migrad minimizer
133  SetMinimizer( new ROOT::Minuit2::VariableMetricMinimizer() );
134  }
135 }
136 
137 
139 {
140  // Destructor implementation.
141  if (fMinimizer) delete fMinimizer;
142  if (fMinuitFCN) delete fMinuitFCN;
143  if (fMinimum) delete fMinimum;
144 }
145 
147  ROOT::Math::Minimizer()
148 {
149  // Implementation of copy constructor.
150 }
151 
153 {
154  // Implementation of assignment operator.
155  if (this == &rhs) return *this; // time saving self-test
156  return *this;
157 }
158 
159 
161  // delete the state in case of consecutive minimizations
162  fState = MnUserParameterState();
163  // clear also the function minimum
164  if (fMinimum) delete fMinimum;
165  fMinimum = nullptr;
166 }
167 
168 
169 // set variables
170 
171 bool HybridMinimizer::SetVariable(unsigned int ivar, const std::string & name, double val, double step) {
172  // set a free variable.
173  // Add the variable if not existing otherwise set value if exists already
174  // this is implemented in MnUserParameterState::Add
175  // if index is wrong (i.e. variable already exists but with a different index return false) but
176  // value is set for corresponding variable name
177 
178 // std::cout << " add parameter " << name << " " << val << " step " << step << std::endl;
179 
180  if (step <= 0) {
181  std::string txtmsg = "Parameter " + name + " has zero or invalid step size - consider it as constant ";
182  MN_INFO_MSG2("HybridMinimizer::SetVariable",txtmsg);
183  fState.Add(name, val);
184  }
185  else
186  fState.Add(name, val, step);
187 
188  unsigned int minuit2Index = fState.Index(name );
189  if ( minuit2Index != ivar) {
190  std::string txtmsg("Wrong index used for the variable " + name);
191  MN_INFO_MSG2("HybridMinimizer::SetVariable",txtmsg);
192  MN_INFO_VAL2("HybridMinimizer::SetVariable",minuit2Index);
193  ivar = minuit2Index;
194  return false;
195  }
196  fState.RemoveLimits(ivar);
197 
198  return true;
199 }
200 
201 bool HybridMinimizer::SetLowerLimitedVariable(unsigned int ivar , const std::string & name , double val , double step , double lower ) {
202  // add a lower bounded variable
203  if (!SetVariable(ivar, name, val, step) ) return false;
204  fState.SetLowerLimit(ivar, lower);
205  return true;
206 }
207 
208 bool HybridMinimizer::SetUpperLimitedVariable(unsigned int ivar , const std::string & name , double val , double step , double upper ) {
209  // add a upper bounded variable
210  if (!SetVariable(ivar, name, val, step) ) return false;
211  fState.SetUpperLimit(ivar, upper);
212  return true;
213 }
214 
215 
216 
217 bool HybridMinimizer::SetLimitedVariable(unsigned int ivar , const std::string & name , double val , double step , double lower , double upper) {
218  // add a double bound variable
219  if (!SetVariable(ivar, name, val, step) ) return false;
220  fState.SetLimits(ivar, lower, upper);
221  return true;
222 }
223 
224 bool HybridMinimizer::SetFixedVariable(unsigned int ivar , const std::string & name , double val ) {
225  // add a fixed variable
226  // need a step size otherwise treated as a constant
227  // use 10%
228  double step = ( val != 0) ? 0.1 * std::abs(val) : 0.1;
229  if (!SetVariable(ivar, name, val, step ) ) {
230  ivar = fState.Index(name );
231  }
232  fState.Fix(ivar);
233  return true;
234 }
235 
236 std::string HybridMinimizer::VariableName(unsigned int ivar) const {
237  // return the variable name
238  if (ivar >= fState.MinuitParameters().size() ) return std::string();
239  return fState.GetName(ivar);
240 }
241 
242 
244  // return the variable index
245  // check if variable exist
246  return fState.Trafo().FindIndex(name);
247 }
248 
249 
250 bool HybridMinimizer::SetVariableValue(unsigned int ivar, double val) {
251  // set value for variable ivar (only for existing parameters)
252  if (ivar >= fState.MinuitParameters().size() ) return false;
253  fState.SetValue(ivar, val);
254  return true;
255 }
256 
257 bool HybridMinimizer::SetVariableValues(const double * x) {
258  // set value for variable ivar (only for existing parameters)
259  unsigned int n = fState.MinuitParameters().size();
260  if (n== 0) return false;
261  for (unsigned int ivar = 0; ivar < n; ++ivar)
262  fState.SetValue(ivar, x[ivar]);
263  return true;
264 }
265 
266 
267 void HybridMinimizer::SetFunction(const ROOT::Math::IMultiGenFunction & func) {
268  // set function to be minimized
269  if (fMinuitFCN) delete fMinuitFCN;
270  fDim = func.NDim();
271  if (!fUseFumili) {
272  fMinuitFCN = new ROOT::Minuit2::FCNAdapter<ROOT::Math::IMultiGenFunction> (func, ErrorDef() );
273  }
274  else {
275  // for Fumili the fit method function interface is required
276  const ROOT::Math::FitMethodFunction * fcnfunc = dynamic_cast<const ROOT::Math::FitMethodFunction *>(&func);
277  if (!fcnfunc) {
278  MN_ERROR_MSG("HybridMinimizer: Wrong Fit method function for Fumili");
279  return;
280  }
281  fMinuitFCN = new ROOT::Minuit2::FumiliFCNAdapter<ROOT::Math::FitMethodFunction> (*fcnfunc, fDim, ErrorDef() );
282  }
283 }
284 
285 void HybridMinimizer::SetFunction(const ROOT::Math::IMultiGradFunction & func) {
286  // set function to be minimized
287  fDim = func.NDim();
288  if (fMinuitFCN) delete fMinuitFCN;
289  if (!fUseFumili) {
290  fMinuitFCN = new ROOT::Minuit2::FCNGradAdapter<ROOT::Math::IMultiGradFunction> (func, ErrorDef() );
291  }
292  else {
293  // for Fumili the fit method function interface is required
294  const ROOT::Math::FitMethodGradFunction * fcnfunc = dynamic_cast<const ROOT::Math::FitMethodGradFunction*>(&func);
295  if (!fcnfunc) {
296  MN_ERROR_MSG("HybridMinimizer: Wrong Fit method function for Fumili");
297  return;
298  }
299  fMinuitFCN = new ROOT::Minuit2::FumiliFCNAdapter<ROOT::Math::FitMethodGradFunction> (*fcnfunc, fDim, ErrorDef() );
300  }
301 }
302 
304  // perform the minimization
305  // store a copy of FunctionMinimum
306  if (!fMinuitFCN) {
307  MN_ERROR_MSG2("HybridMinimizer::Minimize","FCN function has not been set");
308  return false;
309  }
310 
311  assert(GetMinimizer() != nullptr );
312 
313  // delete result of previous minimization
314  if (fMinimum) delete fMinimum;
315  fMinimum = nullptr;
316 
317 
318  int maxfcn = MaxFunctionCalls();
319  double tol = Tolerance();
320  int strategyLevel = Strategy();
321  fMinuitFCN->SetErrorDef(ErrorDef() );
322 
323  if (PrintLevel() >=1) {
324  // print the real number of maxfcn used (defined in ModularFuncitonMinimizer)
325  int maxfcn_used = maxfcn;
326  if (maxfcn_used == 0) {
327  int nvar = fState.VariableParameters();
328  maxfcn_used = 200 + 100*nvar + 5*nvar*nvar;
329  }
330 // std::cout << "HybridMinimizer: Minimize with max-calls " << maxfcn_used
331 // << " convergence for edm < " << tol << " strategy "
332 // << strategyLevel << std::endl;
333  }
334 
335  // internal minuit messages
336  MnPrint::SetLevel(PrintLevel() );
337 
338  // switch off Minuit2 printing
339  int prev_level = (PrintLevel() <= 0 ) ? TurnOffPrintInfoLevel() : -2;
340 
341  // set the precision if needed
342  if (Precision() > 0) fState.SetPrecision(Precision());
343 
344  // set strategy and add extra options if needed
345  ROOT::Minuit2::MnStrategy strategy(strategyLevel);
346  ROOT::Math::IOptions * minuit2Opt = ROOT::Math::MinimizerOptions::FindDefault("Minuit2");
347  if (minuit2Opt) {
348  // set extra strategy options
349  int nGradCycles = strategy.GradientNCycles();
350  int nHessCycles = strategy.HessianNCycles();
351  int nHessGradCycles = strategy.HessianGradientNCycles();
352 
353  double gradTol = strategy.GradientTolerance();
354  double gradStepTol = strategy.GradientStepTolerance();
355  double hessStepTol = strategy.HessianStepTolerance();
356  double hessG2Tol = strategy.HessianG2Tolerance();
357 
358  minuit2Opt->GetValue("GradientNCycles",nGradCycles);
359  minuit2Opt->GetValue("HessianNCycles",nHessCycles);
360  minuit2Opt->GetValue("HessianGradientNCycles",nHessGradCycles);
361 
362  minuit2Opt->GetValue("GradientTolerance",gradTol);
363  minuit2Opt->GetValue("GradientStepTolerance",gradStepTol);
364  minuit2Opt->GetValue("HessianStepTolerance",hessStepTol);
365  minuit2Opt->GetValue("HessianG2Tolerance",hessG2Tol);
366 
367  strategy.SetGradientNCycles(nGradCycles);
368  strategy.SetHessianNCycles(nHessCycles);
369  strategy.SetHessianGradientNCycles(nHessGradCycles);
370 
371  strategy.SetGradientTolerance(gradTol);
372  strategy.SetGradientStepTolerance(gradStepTol);
373  strategy.SetHessianStepTolerance(hessStepTol);
374  strategy.SetHessianG2Tolerance(hessStepTol);
375 
376  if (PrintLevel() > 0) {
377 // std::cout << "HybridMinimizer::Minuit - Changing default stratgey options" << std::endl;
378  minuit2Opt->Print();
379  }
380 
381  }
382 
383  const ROOT::Minuit2::FCNGradientBase * gradFCN = dynamic_cast<const ROOT::Minuit2::FCNGradientBase *>( fMinuitFCN );
384  if ( gradFCN != nullptr) {
385  // use gradient
386  //SetPrintLevel(3);
387  ROOT::Minuit2::FunctionMinimum min = GetMinimizer()->Minimize(*gradFCN, fState, strategy, maxfcn, tol);
388  fMinimum = new ROOT::Minuit2::FunctionMinimum (min);
389  }
390  else {
391  ROOT::Minuit2::FunctionMinimum min = GetMinimizer()->Minimize(*GetFCN(), fState, strategy, maxfcn, tol);
392  fMinimum = new ROOT::Minuit2::FunctionMinimum (min);
393  }
394 
395  // check if Hesse needs to be run
396  if (fMinimum->IsValid() && IsValidError() && fMinimum->State().Error().Dcovar() != 0 ) {
397  // run Hesse (Hesse will add results in the last state of fMinimum
398  ROOT::Minuit2::MnHesse hesse(strategy );
399  hesse( *fMinuitFCN, *fMinimum, maxfcn);
400  }
401 
402  // -2 is the highest low invalid value for gErrorIgnoreLevel
403  if (prev_level > -2) RestoreGlobalPrintLevel(prev_level);
404 
405  fState = fMinimum->UserState();
406  bool ok = ExamineMinimum(*fMinimum);
407  //fMinimum = 0;
408  return ok;
409 }
410 
411 bool HybridMinimizer::ExamineMinimum(const ROOT::Minuit2::FunctionMinimum & min) {
413 
414  // debug ( print all the states)
415  int debugLevel = PrintLevel();
416  if (debugLevel >= 3) {
417 /*
418  const std::vector<ROOT::Minuit2::MinimumState>& iterationStates = min.States();
419  std::cout << "Number of iterations " << iterationStates.size() << std::endl;
420  for (unsigned int i = 0; i < iterationStates.size(); ++i) {
421  //std::cout << iterationStates[i] << std::endl;
422  const ROOT::Minuit2::MinimumState & st = iterationStates[i];
423  std::cout << "----------> Iteration " << i << std::endl;
424  int pr = std::cout.precision(12);
425  std::cout << " FVAL = " << st.Fval() << " Edm = " << st.Edm() << " Nfcn = " << st.NFcn() << std::endl;
426  std::cout.precision(pr);
427  std::cout << " Error matrix change = " << st.Error().Dcovar() << std::endl;
428  std::cout << " Parameters : ";
429  // need to transform from internal to external
430  for (int j = 0; j < st.size() ; ++j) std::cout << " p" << j << " = " << fState.Int2ext( j, st.Vec()(j) );
431  std::cout << std::endl;
432  }
433 */
434  }
435 
436  fStatus = 0;
437  std::string txt;
438  if (min.HasMadePosDefCovar() ) {
439  txt = "Covar was made pos def";
440  fStatus = 1;
441  }
442  if (min.HesseFailed() ) {
443  txt = "Hesse is not valid";
444  fStatus = 2;
445  }
446  if (min.IsAboveMaxEdm() ) {
447  txt = "Edm is above max";
448  fStatus = 3;
449  }
450  if (min.HasReachedCallLimit() ) {
451  txt = "Reached call limit";
452  fStatus = 4;
453  }
454 
455 
456  bool validMinimum = min.IsValid();
457  if (validMinimum) {
458  // print a warning message in case something is not ok
459  if (fStatus != 0 && debugLevel > 0) MN_INFO_MSG2("HybridMinimizer::Minimize",txt);
460  }
461  else {
462  // minimum is not valid when state is not valid and edm is over max or has passed call limits
463  if (fStatus == 0) {
464  // this should not happen
465  txt = "unknown failure";
466  fStatus = 5;
467  }
468  std::string msg = "Minimization did NOT converge, " + txt;
469  MN_INFO_MSG2("HybridMinimizer::Minimize",msg);
470  }
471 
472  if (debugLevel >= 1) PrintResults();
473  return validMinimum;
474 }
475 
476 
478  // print results of minimization
479  if (!fMinimum) return;
480  if (fMinimum->IsValid() ) {
481  // valid minimum
482 /*
483  std::cout << "HybridMinimizer : Valid minimum - status = " << fStatus << std::endl;
484  int pr = std::cout.precision(18);
485  std::cout << "FVAL = " << fState.Fval() << std::endl;
486  std::cout << "Edm = " << fState.Edm() << std::endl;
487  std::cout.precision(pr);
488  std::cout << "Nfcn = " << fState.NFcn() << std::endl;
489  for (unsigned int i = 0; i < fState.MinuitParameters().size(); ++i) {
490  const MinuitParameter & par = fState.Parameter(i);
491  std::cout << par.Name() << "\t = " << par.Value() << "\t ";
492  if (par.IsFixed() ) std::cout << "(fixed)" << std::endl;
493  else if (par.IsConst() ) std::cout << "(const)" << std::endl;
494  else if (par.HasLimits() )
495  std::cout << "+/- " << par.Error() << "\t(limited)"<< std::endl;
496  else
497  std::cout << "+/- " << par.Error() << std::endl;
498  }
499 */
500  }
501  else {
502 /*
503  std::cout << "HybridMinimizer : Invalid Minimum - status = " << fStatus << std::endl;
504  std::cout << "FVAL = " << fState.Fval() << std::endl;
505  std::cout << "Edm = " << fState.Edm() << std::endl;
506  std::cout << "Nfcn = " << fState.NFcn() << std::endl;
507 */
508  }
509 }
510 
511 const double * HybridMinimizer::X() const {
512  // return values at minimum
513  const std::vector<MinuitParameter> & paramsObj = fState.MinuitParameters();
514  if (paramsObj.empty()) return nullptr;
515  assert(fDim == paramsObj.size());
516  // be careful for multiple calls of this function. I will redo an allocation here
517  // only when size of vectors has changed (e.g. after a new minimization)
518  if (fValues.size() != fDim) fValues.resize(fDim);
519  for (unsigned int i = 0; i < fDim; ++i) {
520  fValues[i] = paramsObj[i].Value();
521  }
522 
523  return &fValues.front();
524 }
525 
526 
527 const double * HybridMinimizer::Errors() const {
528  // return error at minimum (set to zero for fixed and constant params)
529  const std::vector<MinuitParameter> & paramsObj = fState.MinuitParameters();
530  if (paramsObj.empty()) return nullptr;
531  assert(fDim == paramsObj.size());
532  // be careful for multiple calls of this function. I will redo an allocation here
533  // only when size of vectors has changed (e.g. after a new minimization)
534  if (fErrors.size() != fDim) fErrors.resize( fDim );
535  for (unsigned int i = 0; i < fDim; ++i) {
536  const MinuitParameter & par = paramsObj[i];
537  if (par.IsFixed() || par.IsConst() )
538  fErrors[i] = 0;
539  else
540  fErrors[i] = par.Error();
541  }
542 
543  return &fErrors.front();
544 }
545 
546 
547 double HybridMinimizer::CovMatrix(unsigned int i, unsigned int j) const {
548  // get value of covariance matrices (transform from external to internal indices)
549  if ( i >= fDim || i >= fDim) return 0;
550  if ( !fState.HasCovariance() ) return 0; // no info available when minimization has failed
551  if (fState.Parameter(i).IsFixed() || fState.Parameter(i).IsConst() ) return 0;
552  if (fState.Parameter(j).IsFixed() || fState.Parameter(j).IsConst() ) return 0;
553  unsigned int k = fState.IntOfExt(i);
554  unsigned int l = fState.IntOfExt(j);
555  return fState.Covariance()(k,l);
556 }
557 
558 bool HybridMinimizer::GetCovMatrix(double * cov) const {
559  // get value of covariance matrices
560  if ( !fState.HasCovariance() ) return false; // no info available when minimization has failed
561  for (unsigned int i = 0; i < fDim; ++i) {
562  if (fState.Parameter(i).IsFixed() || fState.Parameter(i).IsConst() ) {
563  for (unsigned int j = 0; j < fDim; ++j) { cov[i*fDim + j] = 0; }
564  }
565  else
566  {
567  unsigned int l = fState.IntOfExt(i);
568  for (unsigned int j = 0; j < fDim; ++j) {
569  // could probably speed up this loop (if needed)
570  int k = i*fDim + j;
571  if (fState.Parameter(j).IsFixed() || fState.Parameter(j).IsConst() )
572  cov[k] = 0;
573  else {
574  // need to transform from external to internal indices)
575  // for taking care of the removed fixed row/columns in the Minuit2 representation
576  unsigned int m = fState.IntOfExt(j);
577  cov[k] = fState.Covariance()(l,m);
578  }
579  }
580  }
581  }
582  return true;
583 }
584 
585 bool HybridMinimizer::GetHessianMatrix(double * hess) const {
586  // get value of Hessian matrix
587  // this is the second derivative matrices
588  if ( !fState.HasCovariance() ) return false; // no info available when minimization has failed
589  for (unsigned int i = 0; i < fDim; ++i) {
590  if (fState.Parameter(i).IsFixed() || fState.Parameter(i).IsConst() ) {
591  for (unsigned int j = 0; j < fDim; ++j) { hess[i*fDim + j] = 0; }
592  }
593  else {
594  unsigned int l = fState.IntOfExt(i);
595  for (unsigned int j = 0; j < fDim; ++j) {
596  // could probably speed up this loop (if needed)
597  int k = i*fDim + j;
598  if (fState.Parameter(j).IsFixed() || fState.Parameter(j).IsConst() )
599  hess[k] = 0;
600  else {
601  // need to transform from external to internal indices)
602  // for taking care of the removed fixed row/columns in the Minuit2 representation
603  unsigned int m = fState.IntOfExt(j);
604  hess[k] = fState.Hessian()(l,m);
605  }
606  }
607  }
608  }
609 
610  return true;
611 }
612 
613 
614 double HybridMinimizer::Correlation(unsigned int i, unsigned int j) const {
615  // get correlation between parameter i and j
616  if ( i >= fDim || i >= fDim) return 0;
617  if ( !fState.HasCovariance() ) return 0; // no info available when minimization has failed
618  if (fState.Parameter(i).IsFixed() || fState.Parameter(i).IsConst() ) return 0;
619  if (fState.Parameter(j).IsFixed() || fState.Parameter(j).IsConst() ) return 0;
620  unsigned int k = fState.IntOfExt(i);
621  unsigned int l = fState.IntOfExt(j);
622  double cij = fState.IntCovariance()(k,l);
623  double tmp = std::sqrt( std::abs ( fState.IntCovariance()(k,k) * fState.IntCovariance()(l,l) ) );
624  if (tmp > 0 ) return cij/tmp;
625  return 0;
626 }
627 
628 double HybridMinimizer::GlobalCC(unsigned int i) const {
629  // get global correlation coefficient for the parameter i. This is a number between zero and one which gives
630  // the correlation between the i-th parameter and that linear combination of all other parameters which
631  // is most strongly correlated with i.
632 
633  if ( i >= fDim || i >= fDim) return 0;
634  // no info available when minimization has failed or has some problems
635  if ( !fState.HasGlobalCC() ) return 0;
636  if (fState.Parameter(i).IsFixed() || fState.Parameter(i).IsConst() ) return 0;
637  unsigned int k = fState.IntOfExt(i);
638  return fState.GlobalCC().GlobalCC()[k];
639 }
640 
641 
642 bool HybridMinimizer::GetMinosError(unsigned int i, double & errLow, double & errUp, int runopt) {
643  // return the minos error for parameter i
644  // if a minimum does not exist an error is returned
645  // runopt is a flag which specifies if only lower or upper error needs to be run
646  // if runopt = 0 both, = 1 only lower, + 2 only upper errors
647  errLow = 0; errUp = 0;
648  bool runLower = runopt != 2;
649  bool runUpper = runopt != 1;
650 
651  assert( fMinuitFCN );
652 
653  // need to know if parameter is const or fixed
654  if ( fState.Parameter(i).IsConst() || fState.Parameter(i).IsFixed() ) {
655  return false;
656  }
657 
658  int debugLevel = PrintLevel();
659  // internal minuit messages
660  MnPrint::SetLevel( debugLevel );
661 
662  // to run minos I need function minimum class
663  // redo minimization from current state
664 // ROOT::Minuit2::FunctionMinimum min =
665 // GetMinimizer()->Minimize(*GetFCN(),fState, ROOT::Minuit2::MnStrategy(strategy), MaxFunctionCalls(), Tolerance());
666 // fState = min.UserState();
667  if (fMinimum == nullptr) {
668  MN_ERROR_MSG("HybridMinimizer::GetMinosErrors: failed - no function minimum existing");
669  return false;
670  }
671 
672  if (!fMinimum->IsValid() ) {
673  MN_ERROR_MSG("HybridMinimizer::MINOS failed due to invalid function minimum");
674  return false;
675  }
676 
677  fMinuitFCN->SetErrorDef(ErrorDef() );
678  // if error def has been changed update it in FunctionMinimum
679  if (ErrorDef() != fMinimum->Up() )
680  fMinimum->SetErrorDef(ErrorDef() );
681 
682  // switch off Minuit2 printing
683  int prev_level = (PrintLevel() <= 0 ) ? TurnOffPrintInfoLevel() : -2;
684 
685  // set the precision if needed
686  if (Precision() > 0) fState.SetPrecision(Precision());
687 
688 
689  ROOT::Minuit2::MnMinos minos( *fMinuitFCN, *fMinimum);
690 
691  // run MnCross
692  MnCross low;
693  MnCross up;
694  int maxfcn = MaxFunctionCalls();
695  double tol = Tolerance();
696 
697 // const char * par_name = fState.Name(i);
698 
699  // now input tolerance for migrad calls inside Minos (MnFunctionCross)
700  // before it was fixed to 0.05
701  // cut off too small tolerance (they are not needed)
702  tol = std::max(tol, 0.01);
703 
704  if (PrintLevel() >=1) {
705  // print the real number of maxfcn used (defined in MnMinos)
706  int maxfcn_used = maxfcn;
707  if (maxfcn_used == 0) {
708  int nvar = fState.VariableParameters();
709  maxfcn_used = 2*(nvar+1)*(200 + 100*nvar + 5*nvar*nvar);
710  }
711 // std::cout << "HybridMinimizer::GetMinosError for parameter " << i << " " << par_name
712 // << " using max-calls " << maxfcn_used << ", tolerance " << tol << std::endl;
713  }
714 
715 
716  if (runLower) low = minos.Loval(i,maxfcn,tol);
717  if (runUpper) up = minos.Upval(i,maxfcn,tol);
718 
719  ROOT::Minuit2::MinosError me(i, fMinimum->UserState().Value(i),low, up);
720 
721  if (prev_level > -2) RestoreGlobalPrintLevel(prev_level);
722 
723  // debug result of Minos
724  // print error message in Minos
725 
726 
727  if (debugLevel >= 1) {
728 /*
729  if (runLower) {
730  if (!me.LowerValid() )
731  std::cout << "Minos: Invalid lower error for parameter " << par_name << std::endl;
732  if(me.AtLowerLimit())
733  std::cout << "Minos: Parameter : " << par_name << " is at Lower limit."<<std::endl;
734  if(me.AtLowerMaxFcn())
735  std::cout << "Minos: Maximum number of function calls exceeded when running for lower error" <<std::endl;
736  if(me.LowerNewMin() )
737  std::cout << "Minos: New Minimum found while running Minos for lower error" <<std::endl;
738 
739  if (debugLevel > 1) std::cout << "Minos: Lower error for parameter " << par_name << " : " << me.Lower() << std::endl;
740 
741  }
742  if (runUpper) {
743  if (!me.UpperValid() )
744  std::cout << "Minos: Invalid upper error for parameter " << par_name << std::endl;
745  if(me.AtUpperLimit())
746  std::cout << "Minos: Parameter " << par_name << " is at Upper limit."<<std::endl;
747  if(me.AtUpperMaxFcn())
748  std::cout << "Minos: Maximum number of function calls exceeded when running for upper error" <<std::endl;
749  if(me.UpperNewMin() )
750  std::cout << "Minos: New Minimum found while running Minos for upper error" <<std::endl;
751 
752  if (debugLevel > 1) std::cout << "Minos: Upper error for parameter " << par_name << " : " << me.Upper() << std::endl;
753  }
754 */
755  }
756 
757  bool lowerInvalid = (runLower && !me.LowerValid() );
758  bool upperInvalid = (runUpper && !me.UpperValid() );
759  int mstatus = 0;
760  if (lowerInvalid || upperInvalid ) {
761  // set status accroding to bit
762  // bit 1: lower invalid Minos errors
763  // bit 2: uper invalid Minos error
764  // bit 3: invalid because max FCN
765  // bit 4 : invalid because a new minimum has been found
766  if (lowerInvalid) {
767  mstatus |= 1;
768  if (me.AtLowerMaxFcn() ) mstatus |= 4;
769  if (me.LowerNewMin() ) mstatus |= 8;
770  }
771  if(upperInvalid) {
772  mstatus |= 3;
773  if (me.AtUpperMaxFcn() ) mstatus |= 4;
774  if (me.UpperNewMin() ) mstatus |= 8;
775  }
776  //std::cout << "Error running Minos for parameter " << i << std::endl;
777  fStatus += 10*mstatus;
778  }
779 
780  errLow = me.Lower();
781  errUp = me.Upper();
782 
783  bool isValid = (runLower && me.LowerValid() ) || (runUpper && me.UpperValid() );
784  return isValid;
785 }
786 
787 bool HybridMinimizer::Scan(unsigned int ipar, unsigned int & nstep, double * x, double * y, double xmin, double xmax) {
788  // scan a parameter (variable) around the minimum value
789  // the parameters must have been set before
790  // if xmin=0 && xmax == 0 by default scan around 2 sigma of the error
791  // if the errors are also zero then scan from min and max of parameter range
792 
793  if (!fMinuitFCN) {
794  MN_ERROR_MSG2("HybridMinimizer::Scan"," Function must be set before using Scan");
795  return false;
796  }
797 
798  if ( ipar > fState.MinuitParameters().size() ) {
799  MN_ERROR_MSG2("HybridMinimizer::Scan"," Invalid number. Minimizer variables must be set before using Scan");
800  return false;
801  }
802 
803  // switch off Minuit2 printing
804  int prev_level = (PrintLevel() <= 0 ) ? TurnOffPrintInfoLevel() : -2;
805 
806  MnPrint::SetLevel( PrintLevel() );
807 
808 
809  // set the precision if needed
810  if (Precision() > 0) fState.SetPrecision(Precision());
811 
812  MnParameterScan scan( *fMinuitFCN, fState.Parameters() );
813  double amin = scan.Fval(); // fcn value of the function before scan
814 
815  // first value is param value
816  std::vector<std::pair<double, double> > result = scan(ipar, nstep-1, xmin, xmax);
817 
818  if (prev_level > -2) RestoreGlobalPrintLevel(prev_level);
819 
820  if (result.size() != nstep) {
821  MN_ERROR_MSG2("HybridMinimizer::Scan"," Invalid result from MnParameterScan");
822  return false;
823  }
824  // sort also the returned points in x
825  std::sort(result.begin(), result.end() );
826 
827 
828  for (unsigned int i = 0; i < nstep; ++i ) {
829  x[i] = result[i].first;
830  y[i] = result[i].second;
831  }
832 
833  // what to do if a new minimum has been found ?
834  // use that as new minimum
835  if (scan.Fval() < amin ) {
836  if (PrintLevel() > 0) MN_INFO_MSG2("HybridMinimizer::Scan","A new minimum has been found");
837  fState.SetValue(ipar, scan.Parameters().Value(ipar) );
838 
839  }
840 
841 
842  return true;
843 }
844 
845 bool HybridMinimizer::Contour(unsigned int ipar, unsigned int jpar, unsigned int & npoints, double * x, double * y) {
846  // contour plot for parameter i and j
847  // need a valid FunctionMinimum otherwise exits
848  if (fMinimum == nullptr) {
849  MN_ERROR_MSG2("HybridMinimizer::Contour"," no function minimum existing. Must minimize function before");
850  return false;
851  }
852 
853  if (!fMinimum->IsValid() ) {
854  MN_ERROR_MSG2("HybridMinimizer::Contour","Invalid function minimum");
855  return false;
856  }
857  assert(fMinuitFCN);
858 
859  fMinuitFCN->SetErrorDef(ErrorDef() );
860  // if error def has been changed update it in FunctionMinimum
861  if (ErrorDef() != fMinimum->Up() )
862  fMinimum->SetErrorDef(ErrorDef() );
863 
864  // switch off Minuit2 printing (for level of 0,1)
865  int prev_level = (PrintLevel() <= 1 ) ? TurnOffPrintInfoLevel() : -2;
866 
867  MnPrint::SetLevel( PrintLevel() );
868 
869  // set the precision if needed
870  if (Precision() > 0) fState.SetPrecision(Precision());
871 
872  // eventually one should specify tolerance in contours
873  MnContours contour(*fMinuitFCN, *fMinimum, Strategy() );
874 
875  if (prev_level > -2) RestoreGlobalPrintLevel(prev_level);
876 
877  std::vector<std::pair<double,double> > result = contour(ipar,jpar, npoints);
878  if (result.size() != npoints) {
879  MN_ERROR_MSG2("HybridMinimizer::Contour"," Invalid result from MnContours");
880  return false;
881  }
882  for (unsigned int i = 0; i < npoints; ++i ) {
883  x[i] = result[i].first;
884  y[i] = result[i].second;
885  }
886 
887 
888  return true;
889 
890 
891 }
892 
894  // find Hessian (full second derivative calculations)
895  // the contained state will be updated with the Hessian result
896  // in case a function minimum exists and is valid the result will be
897  // appended in the function minimum
898 
899  if (!fMinuitFCN) {
900  MN_ERROR_MSG2("HybridMinimizer::Hesse","FCN function has not been set");
901  return false;
902  }
903 
904  int strategy = Strategy();
905  int maxfcn = MaxFunctionCalls();
906 
907  // switch off Minuit2 printing
908  int prev_level = (PrintLevel() <= 0 ) ? TurnOffPrintInfoLevel() : -2;
909 
910  MnPrint::SetLevel( PrintLevel() );
911 
912  // set the precision if needed
913  if (Precision() > 0) fState.SetPrecision(Precision());
914 
915  ROOT::Minuit2::MnHesse hesse( strategy );
916 
917  // case when function minimum exists
918  if (fMinimum ) {
919  // run hesse and function minimum will be updated with Hesse result
920  hesse( *fMinuitFCN, *fMinimum, maxfcn );
921  fState = fMinimum->UserState();
922  }
923 
924  else {
925  // run Hesse on point stored in current state (independent of function minimum validity)
926  // (x == 0)
927  fState = hesse( *fMinuitFCN, fState, maxfcn);
928  }
929 
930  if (prev_level > -2) RestoreGlobalPrintLevel(prev_level);
931 
932  if (PrintLevel() >= 3) {
933 // std::cout << "State returned from Hesse " << std::endl;
934 // std::cout << fState << std::endl;
935  }
936 
937  if (!fState.HasCovariance() ) {
938  // if false means error is not valid and this is due to a failure in Hesse
939  if (PrintLevel() > 0) MN_INFO_MSG2("HybridMinimizer::Hesse","Hesse failed ");
940  // update minimizer error status
941  int hstatus = 4;
942  // information on error state can be retrieved only if fMinimum is available
943  if (fMinimum) {
944  if (fMinimum->Error().HesseFailed() ) hstatus = 1;
945  if (fMinimum->Error().InvertFailed() ) hstatus = 2;
946  else if (!(fMinimum->Error().IsPosDef()) ) hstatus = 3;
947  }
948  fStatus += 100*hstatus;
949  return false;
950  }
951 
952  return true;
953 }
954 
956  // return status of covariance matrix
957  //-1 - not available (inversion failed or Hesse failed)
958  // 0 - available but not positive defined
959  // 1 - covariance only approximate
960  // 2 full matrix but forced pos def
961  // 3 full accurate matrix
962 
963  if (fMinimum) {
964  // case a function minimum is available
965  if (fMinimum->HasAccurateCovar() ) return 3;
966  else if (fMinimum->HasMadePosDefCovar() ) return 2;
967  else if (fMinimum->HasValidCovariance() ) return 1;
968  else if (fMinimum->HasCovariance() ) return 0;
969  return -1;
970  }
971  else {
972  // case fMinimum is not available - use state information
973  return fState.CovarianceStatus();
974  }
975  return 0;
976 }
977 
978 }
Definition: BitonicSort.h:8
type
Definition: HCALResponse.h:21
int CovMatrixStatus() const override
bool SetVariable(unsigned int ivar, const std::string &name, double val, double step) override
set free variable
double Correlation(unsigned int i, unsigned int j) const override
bool Contour(unsigned int i, unsigned int j, unsigned int &npoints, double *xi, double *xj) override
ROOT::Minuit2::MnUserParameterState fState
ROOT::Minuit2::FCNBase * fMinuitFCN
ROOT::Minuit2::FunctionMinimum * fMinimum
HybridMinimizer(EMinimizerType type=kMigrad)
std::string VariableName(unsigned int ivar) const override
get name of variables (override if minimizer support storing of variable names)
#define nullptr
void SetFunction(const ROOT::Math::IMultiGenFunction &func) override
set the function to minimize
bool SetVariableValue(unsigned int ivar, double val) override
set variable
bool SetLowerLimitedVariable(unsigned int ivar, const std::string &name, double val, double step, double lower) override
set lower limit variable (override if minimizer supports them )
const double * Errors() const override
return errors at the minimum
void SetMinimizerType(EMinimizerType type)
bool GetMinosError(unsigned int i, double &errLow, double &errUp, int=0) override
std::vector< double > fErrors
int ControlPrintLevel()
bool SetFixedVariable(unsigned int, const std::string &, double) override
set fixed variable (override if minimizer supports them )
bool ExamineMinimum(const ROOT::Minuit2::FunctionMinimum &min)
examine the minimum result
T sqrt(T t)
Definition: SSEVec.h:18
double GlobalCC(unsigned int i) const override
virtual void SetMinimizer(ROOT::Minuit2::ModularFunctionMinimizer *m)
bool GetCovMatrix(double *cov) const override
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
bool SetVariableValues(const double *val) override
static const int npoints
Definition: value.py:1
T min(T a, T b)
Definition: MathUtil.h:58
HybridMinimizer & operator=(const HybridMinimizer &rhs)
int k[5][pyjets_maxn]
int TurnOffPrintInfoLevel()
int VariableIndex(const std::string &name) const override
tuple msg
Definition: mps_check.py:277
const double * X() const override
return pointer to X values at the minimum
gErrorIgnoreLevel
Definition: utils.py:25
std::vector< double > fValues
void RestoreGlobalPrintLevel(int)
std::vector< std::vector< double > > tmp
Definition: MVATrainer.cc:100
bool GetHessianMatrix(double *h) const override
ROOT::Minuit2::ModularFunctionMinimizer * fMinimizer
bool SetLimitedVariable(unsigned int ivar, const std::string &name, double val, double step, double, double) override
set upper/lower limited variable (override if minimizer supports them )
virtual const ROOT::Minuit2::ModularFunctionMinimizer * GetMinimizer() const
double CovMatrix(unsigned int i, unsigned int j) const override
step
void PrintResults() override
print result of minimization
virtual const ROOT::Minuit2::FCNBase * GetFCN() const
bool Scan(unsigned int i, unsigned int &nstep, double *x, double *y, double xmin=0, double xmax=0) override
bool SetUpperLimitedVariable(unsigned int ivar, const std::string &name, double val, double step, double upper) override
set upper limit variable (override if minimizer supports them )