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  return false;
194  }
195  fState.RemoveLimits(ivar);
196 
197  return true;
198 }
199 
200 bool HybridMinimizer::SetLowerLimitedVariable(unsigned int ivar , const std::string & name , double val , double step , double lower ) {
201  // add a lower bounded variable
202  if (!SetVariable(ivar, name, val, step) ) return false;
203  fState.SetLowerLimit(ivar, lower);
204  return true;
205 }
206 
207 bool HybridMinimizer::SetUpperLimitedVariable(unsigned int ivar , const std::string & name , double val , double step , double upper ) {
208  // add a upper bounded variable
209  if (!SetVariable(ivar, name, val, step) ) return false;
210  fState.SetUpperLimit(ivar, upper);
211  return true;
212 }
213 
214 
215 
216 bool HybridMinimizer::SetLimitedVariable(unsigned int ivar , const std::string & name , double val , double step , double lower , double upper) {
217  // add a double bound variable
218  if (!SetVariable(ivar, name, val, step) ) return false;
219  fState.SetLimits(ivar, lower, upper);
220  return true;
221 }
222 
223 bool HybridMinimizer::SetFixedVariable(unsigned int ivar , const std::string & name , double val ) {
224  // add a fixed variable
225  // need a step size otherwise treated as a constant
226  // use 10%
227  double step = ( val != 0) ? 0.1 * std::abs(val) : 0.1;
228  if (!SetVariable(ivar, name, val, step ) ) {
229  ivar = fState.Index(name );
230  }
231  fState.Fix(ivar);
232  return true;
233 }
234 
235 std::string HybridMinimizer::VariableName(unsigned int ivar) const {
236  // return the variable name
237  if (ivar >= fState.MinuitParameters().size() ) return std::string();
238  return fState.GetName(ivar);
239 }
240 
241 
243  // return the variable index
244  // check if variable exist
245  return fState.Trafo().FindIndex(name);
246 }
247 
248 
249 bool HybridMinimizer::SetVariableValue(unsigned int ivar, double val) {
250  // set value for variable ivar (only for existing parameters)
251  if (ivar >= fState.MinuitParameters().size() ) return false;
252  fState.SetValue(ivar, val);
253  return true;
254 }
255 
256 bool HybridMinimizer::SetVariableValues(const double * x) {
257  // set value for variable ivar (only for existing parameters)
258  unsigned int n = fState.MinuitParameters().size();
259  if (n== 0) return false;
260  for (unsigned int ivar = 0; ivar < n; ++ivar)
261  fState.SetValue(ivar, x[ivar]);
262  return true;
263 }
264 
265 
266 void HybridMinimizer::SetFunction(const ROOT::Math::IMultiGenFunction & func) {
267  // set function to be minimized
268  if (fMinuitFCN) delete fMinuitFCN;
269  fDim = func.NDim();
270  if (!fUseFumili) {
271  fMinuitFCN = new ROOT::Minuit2::FCNAdapter<ROOT::Math::IMultiGenFunction> (func, ErrorDef() );
272  }
273  else {
274  // for Fumili the fit method function interface is required
275  const ROOT::Math::FitMethodFunction * fcnfunc = dynamic_cast<const ROOT::Math::FitMethodFunction *>(&func);
276  if (!fcnfunc) {
277  MN_ERROR_MSG("HybridMinimizer: Wrong Fit method function for Fumili");
278  return;
279  }
280  fMinuitFCN = new ROOT::Minuit2::FumiliFCNAdapter<ROOT::Math::FitMethodFunction> (*fcnfunc, fDim, ErrorDef() );
281  }
282 }
283 
284 void HybridMinimizer::SetFunction(const ROOT::Math::IMultiGradFunction & func) {
285  // set function to be minimized
286  fDim = func.NDim();
287  if (fMinuitFCN) delete fMinuitFCN;
288  if (!fUseFumili) {
289  fMinuitFCN = new ROOT::Minuit2::FCNGradAdapter<ROOT::Math::IMultiGradFunction> (func, ErrorDef() );
290  }
291  else {
292  // for Fumili the fit method function interface is required
293  const ROOT::Math::FitMethodGradFunction * fcnfunc = dynamic_cast<const ROOT::Math::FitMethodGradFunction*>(&func);
294  if (!fcnfunc) {
295  MN_ERROR_MSG("HybridMinimizer: Wrong Fit method function for Fumili");
296  return;
297  }
298  fMinuitFCN = new ROOT::Minuit2::FumiliFCNAdapter<ROOT::Math::FitMethodGradFunction> (*fcnfunc, fDim, ErrorDef() );
299  }
300 }
301 
303  // perform the minimization
304  // store a copy of FunctionMinimum
305  if (!fMinuitFCN) {
306  MN_ERROR_MSG2("HybridMinimizer::Minimize","FCN function has not been set");
307  return false;
308  }
309 
310  assert(GetMinimizer() != nullptr );
311 
312  // delete result of previous minimization
313  if (fMinimum) delete fMinimum;
314  fMinimum = nullptr;
315 
316 
317  int maxfcn = MaxFunctionCalls();
318  double tol = Tolerance();
319  int strategyLevel = Strategy();
320  fMinuitFCN->SetErrorDef(ErrorDef() );
321 
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 
336  // internal minuit messages
337  MnPrint::SetLevel(PrintLevel() );
338 
339  // switch off Minuit2 printing
340  int prev_level = (PrintLevel() <= 0 ) ? TurnOffPrintInfoLevel() : -2;
341 
342  // set the precision if needed
343  if (Precision() > 0) fState.SetPrecision(Precision());
344 
345  // set strategy and add extra options if needed
346  ROOT::Minuit2::MnStrategy strategy(strategyLevel);
347  ROOT::Math::IOptions * minuit2Opt = ROOT::Math::MinimizerOptions::FindDefault("Minuit2");
348  if (minuit2Opt) {
349  // set extra strategy options
350  int nGradCycles = strategy.GradientNCycles();
351  int nHessCycles = strategy.HessianNCycles();
352  int nHessGradCycles = strategy.HessianGradientNCycles();
353 
354  double gradTol = strategy.GradientTolerance();
355  double gradStepTol = strategy.GradientStepTolerance();
356  double hessStepTol = strategy.HessianStepTolerance();
357  double hessG2Tol = strategy.HessianG2Tolerance();
358 
359  minuit2Opt->GetValue("GradientNCycles",nGradCycles);
360  minuit2Opt->GetValue("HessianNCycles",nHessCycles);
361  minuit2Opt->GetValue("HessianGradientNCycles",nHessGradCycles);
362 
363  minuit2Opt->GetValue("GradientTolerance",gradTol);
364  minuit2Opt->GetValue("GradientStepTolerance",gradStepTol);
365  minuit2Opt->GetValue("HessianStepTolerance",hessStepTol);
366  minuit2Opt->GetValue("HessianG2Tolerance",hessG2Tol);
367 
368  strategy.SetGradientNCycles(nGradCycles);
369  strategy.SetHessianNCycles(nHessCycles);
370  strategy.SetHessianGradientNCycles(nHessGradCycles);
371 
372  strategy.SetGradientTolerance(gradTol);
373  strategy.SetGradientStepTolerance(gradStepTol);
374  strategy.SetHessianStepTolerance(hessStepTol);
375  strategy.SetHessianG2Tolerance(hessStepTol);
376 
377  if (PrintLevel() > 0) {
378 // std::cout << "HybridMinimizer::Minuit - Changing default stratgey options" << std::endl;
379  minuit2Opt->Print();
380  }
381 
382  }
383 
384  const ROOT::Minuit2::FCNGradientBase * gradFCN = dynamic_cast<const ROOT::Minuit2::FCNGradientBase *>( fMinuitFCN );
385  if ( gradFCN != nullptr) {
386  // use gradient
387  //SetPrintLevel(3);
388  ROOT::Minuit2::FunctionMinimum min = GetMinimizer()->Minimize(*gradFCN, fState, strategy, maxfcn, tol);
389  fMinimum = new ROOT::Minuit2::FunctionMinimum (min);
390  }
391  else {
392  ROOT::Minuit2::FunctionMinimum min = GetMinimizer()->Minimize(*GetFCN(), fState, strategy, maxfcn, tol);
393  fMinimum = new ROOT::Minuit2::FunctionMinimum (min);
394  }
395 
396  // check if Hesse needs to be run
397  if (fMinimum->IsValid() && IsValidError() && fMinimum->State().Error().Dcovar() != 0 ) {
398  // run Hesse (Hesse will add results in the last state of fMinimum
399  ROOT::Minuit2::MnHesse hesse(strategy );
400  hesse( *fMinuitFCN, *fMinimum, maxfcn);
401  }
402 
403  // -2 is the highest low invalid value for gErrorIgnoreLevel
404  if (prev_level > -2) RestoreGlobalPrintLevel(prev_level);
405 
406  fState = fMinimum->UserState();
407  bool ok = ExamineMinimum(*fMinimum);
408  //fMinimum = 0;
409  return ok;
410 }
411 
412 bool HybridMinimizer::ExamineMinimum(const ROOT::Minuit2::FunctionMinimum & min) {
414 
415  // debug ( print all the states)
416  int debugLevel = PrintLevel();
417  if (debugLevel >= 3) {
418 /*
419  const std::vector<ROOT::Minuit2::MinimumState>& iterationStates = min.States();
420  std::cout << "Number of iterations " << iterationStates.size() << std::endl;
421  for (unsigned int i = 0; i < iterationStates.size(); ++i) {
422  //std::cout << iterationStates[i] << std::endl;
423  const ROOT::Minuit2::MinimumState & st = iterationStates[i];
424  std::cout << "----------> Iteration " << i << std::endl;
425  int pr = std::cout.precision(12);
426  std::cout << " FVAL = " << st.Fval() << " Edm = " << st.Edm() << " Nfcn = " << st.NFcn() << std::endl;
427  std::cout.precision(pr);
428  std::cout << " Error matrix change = " << st.Error().Dcovar() << std::endl;
429  std::cout << " Parameters : ";
430  // need to transform from internal to external
431  for (int j = 0; j < st.size() ; ++j) std::cout << " p" << j << " = " << fState.Int2ext( j, st.Vec()(j) );
432  std::cout << std::endl;
433  }
434 */
435  }
436 
437  fStatus = 0;
438  std::string txt;
439  if (min.HasMadePosDefCovar() ) {
440  txt = "Covar was made pos def";
441  fStatus = 1;
442  }
443  if (min.HesseFailed() ) {
444  txt = "Hesse is not valid";
445  fStatus = 2;
446  }
447  if (min.IsAboveMaxEdm() ) {
448  txt = "Edm is above max";
449  fStatus = 3;
450  }
451  if (min.HasReachedCallLimit() ) {
452  txt = "Reached call limit";
453  fStatus = 4;
454  }
455 
456 
457  bool validMinimum = min.IsValid();
458  if (validMinimum) {
459  // print a warning message in case something is not ok
460  if (fStatus != 0 && debugLevel > 0) MN_INFO_MSG2("HybridMinimizer::Minimize",txt);
461  }
462  else {
463  // minimum is not valid when state is not valid and edm is over max or has passed call limits
464  if (fStatus == 0) {
465  // this should not happen
466  txt = "unknown failure";
467  fStatus = 5;
468  }
469  std::string msg = "Minimization did NOT converge, " + txt;
470  MN_INFO_MSG2("HybridMinimizer::Minimize",msg);
471  }
472 
473  if (debugLevel >= 1) PrintResults();
474  return validMinimum;
475 }
476 
477 
479  // print results of minimization
480  if (!fMinimum) return;
481  if (fMinimum->IsValid() ) {
482  // valid minimum
483 /*
484  std::cout << "HybridMinimizer : Valid minimum - status = " << fStatus << std::endl;
485  int pr = std::cout.precision(18);
486  std::cout << "FVAL = " << fState.Fval() << std::endl;
487  std::cout << "Edm = " << fState.Edm() << std::endl;
488  std::cout.precision(pr);
489  std::cout << "Nfcn = " << fState.NFcn() << std::endl;
490  for (unsigned int i = 0; i < fState.MinuitParameters().size(); ++i) {
491  const MinuitParameter & par = fState.Parameter(i);
492  std::cout << par.Name() << "\t = " << par.Value() << "\t ";
493  if (par.IsFixed() ) std::cout << "(fixed)" << std::endl;
494  else if (par.IsConst() ) std::cout << "(const)" << std::endl;
495  else if (par.HasLimits() )
496  std::cout << "+/- " << par.Error() << "\t(limited)"<< std::endl;
497  else
498  std::cout << "+/- " << par.Error() << std::endl;
499  }
500 */
501  }
502  else {
503 /*
504  std::cout << "HybridMinimizer : Invalid Minimum - status = " << fStatus << std::endl;
505  std::cout << "FVAL = " << fState.Fval() << std::endl;
506  std::cout << "Edm = " << fState.Edm() << std::endl;
507  std::cout << "Nfcn = " << fState.NFcn() << std::endl;
508 */
509  }
510 }
511 
512 const double * HybridMinimizer::X() const {
513  // return values at minimum
514  const std::vector<MinuitParameter> & paramsObj = fState.MinuitParameters();
515  if (paramsObj.empty()) return nullptr;
516  assert(fDim == paramsObj.size());
517  // be careful for multiple calls of this function. I will redo an allocation here
518  // only when size of vectors has changed (e.g. after a new minimization)
519  if (fValues.size() != fDim) fValues.resize(fDim);
520  for (unsigned int i = 0; i < fDim; ++i) {
521  fValues[i] = paramsObj[i].Value();
522  }
523 
524  return &fValues.front();
525 }
526 
527 
528 const double * HybridMinimizer::Errors() const {
529  // return error at minimum (set to zero for fixed and constant params)
530  const std::vector<MinuitParameter> & paramsObj = fState.MinuitParameters();
531  if (paramsObj.empty()) return nullptr;
532  assert(fDim == paramsObj.size());
533  // be careful for multiple calls of this function. I will redo an allocation here
534  // only when size of vectors has changed (e.g. after a new minimization)
535  if (fErrors.size() != fDim) fErrors.resize( fDim );
536  for (unsigned int i = 0; i < fDim; ++i) {
537  const MinuitParameter & par = paramsObj[i];
538  if (par.IsFixed() || par.IsConst() )
539  fErrors[i] = 0;
540  else
541  fErrors[i] = par.Error();
542  }
543 
544  return &fErrors.front();
545 }
546 
547 
548 double HybridMinimizer::CovMatrix(unsigned int i, unsigned int j) const {
549  // get value of covariance matrices (transform from external to internal indices)
550  if ( i >= fDim || i >= fDim) return 0;
551  if ( !fState.HasCovariance() ) return 0; // no info available when minimization has failed
552  if (fState.Parameter(i).IsFixed() || fState.Parameter(i).IsConst() ) return 0;
553  if (fState.Parameter(j).IsFixed() || fState.Parameter(j).IsConst() ) return 0;
554  unsigned int k = fState.IntOfExt(i);
555  unsigned int l = fState.IntOfExt(j);
556  return fState.Covariance()(k,l);
557 }
558 
559 bool HybridMinimizer::GetCovMatrix(double * cov) const {
560  // get value of covariance matrices
561  if ( !fState.HasCovariance() ) return false; // no info available when minimization has failed
562  for (unsigned int i = 0; i < fDim; ++i) {
563  if (fState.Parameter(i).IsFixed() || fState.Parameter(i).IsConst() ) {
564  for (unsigned int j = 0; j < fDim; ++j) { cov[i*fDim + j] = 0; }
565  }
566  else
567  {
568  unsigned int l = fState.IntOfExt(i);
569  for (unsigned int j = 0; j < fDim; ++j) {
570  // could probably speed up this loop (if needed)
571  int k = i*fDim + j;
572  if (fState.Parameter(j).IsFixed() || fState.Parameter(j).IsConst() )
573  cov[k] = 0;
574  else {
575  // need to transform from external to internal indices)
576  // for taking care of the removed fixed row/columns in the Minuit2 representation
577  unsigned int m = fState.IntOfExt(j);
578  cov[k] = fState.Covariance()(l,m);
579  }
580  }
581  }
582  }
583  return true;
584 }
585 
586 bool HybridMinimizer::GetHessianMatrix(double * hess) const {
587  // get value of Hessian matrix
588  // this is the second derivative matrices
589  if ( !fState.HasCovariance() ) return false; // no info available when minimization has failed
590  for (unsigned int i = 0; i < fDim; ++i) {
591  if (fState.Parameter(i).IsFixed() || fState.Parameter(i).IsConst() ) {
592  for (unsigned int j = 0; j < fDim; ++j) { hess[i*fDim + j] = 0; }
593  }
594  else {
595  unsigned int l = fState.IntOfExt(i);
596  for (unsigned int j = 0; j < fDim; ++j) {
597  // could probably speed up this loop (if needed)
598  int k = i*fDim + j;
599  if (fState.Parameter(j).IsFixed() || fState.Parameter(j).IsConst() )
600  hess[k] = 0;
601  else {
602  // need to transform from external to internal indices)
603  // for taking care of the removed fixed row/columns in the Minuit2 representation
604  unsigned int m = fState.IntOfExt(j);
605  hess[k] = fState.Hessian()(l,m);
606  }
607  }
608  }
609  }
610 
611  return true;
612 }
613 
614 
615 double HybridMinimizer::Correlation(unsigned int i, unsigned int j) const {
616  // get correlation between parameter i and j
617  if ( i >= fDim || i >= fDim) return 0;
618  if ( !fState.HasCovariance() ) return 0; // no info available when minimization has failed
619  if (fState.Parameter(i).IsFixed() || fState.Parameter(i).IsConst() ) return 0;
620  if (fState.Parameter(j).IsFixed() || fState.Parameter(j).IsConst() ) return 0;
621  unsigned int k = fState.IntOfExt(i);
622  unsigned int l = fState.IntOfExt(j);
623  double cij = fState.IntCovariance()(k,l);
624  double tmp = std::sqrt( std::abs ( fState.IntCovariance()(k,k) * fState.IntCovariance()(l,l) ) );
625  if (tmp > 0 ) return cij/tmp;
626  return 0;
627 }
628 
629 double HybridMinimizer::GlobalCC(unsigned int i) const {
630  // get global correlation coefficient for the parameter i. This is a number between zero and one which gives
631  // the correlation between the i-th parameter and that linear combination of all other parameters which
632  // is most strongly correlated with i.
633 
634  if ( i >= fDim || i >= fDim) return 0;
635  // no info available when minimization has failed or has some problems
636  if ( !fState.HasGlobalCC() ) return 0;
637  if (fState.Parameter(i).IsFixed() || fState.Parameter(i).IsConst() ) return 0;
638  unsigned int k = fState.IntOfExt(i);
639  return fState.GlobalCC().GlobalCC()[k];
640 }
641 
642 
643 bool HybridMinimizer::GetMinosError(unsigned int i, double & errLow, double & errUp, int runopt) {
644  // return the minos error for parameter i
645  // if a minimum does not exist an error is returned
646  // runopt is a flag which specifies if only lower or upper error needs to be run
647  // if runopt = 0 both, = 1 only lower, + 2 only upper errors
648  errLow = 0; errUp = 0;
649  bool runLower = runopt != 2;
650  bool runUpper = runopt != 1;
651 
652  assert( fMinuitFCN );
653 
654  // need to know if parameter is const or fixed
655  if ( fState.Parameter(i).IsConst() || fState.Parameter(i).IsFixed() ) {
656  return false;
657  }
658 
659  int debugLevel = PrintLevel();
660  // internal minuit messages
661  MnPrint::SetLevel( debugLevel );
662 
663  // to run minos I need function minimum class
664  // redo minimization from current state
665 // ROOT::Minuit2::FunctionMinimum min =
666 // GetMinimizer()->Minimize(*GetFCN(),fState, ROOT::Minuit2::MnStrategy(strategy), MaxFunctionCalls(), Tolerance());
667 // fState = min.UserState();
668  if (fMinimum == nullptr) {
669  MN_ERROR_MSG("HybridMinimizer::GetMinosErrors: failed - no function minimum existing");
670  return false;
671  }
672 
673  if (!fMinimum->IsValid() ) {
674  MN_ERROR_MSG("HybridMinimizer::MINOS failed due to invalid function minimum");
675  return false;
676  }
677 
678  fMinuitFCN->SetErrorDef(ErrorDef() );
679  // if error def has been changed update it in FunctionMinimum
680  if (ErrorDef() != fMinimum->Up() )
681  fMinimum->SetErrorDef(ErrorDef() );
682 
683  // switch off Minuit2 printing
684  int prev_level = (PrintLevel() <= 0 ) ? TurnOffPrintInfoLevel() : -2;
685 
686  // set the precision if needed
687  if (Precision() > 0) fState.SetPrecision(Precision());
688 
689 
690  ROOT::Minuit2::MnMinos minos( *fMinuitFCN, *fMinimum);
691 
692  // run MnCross
693  MnCross low;
694  MnCross up;
695  int maxfcn = MaxFunctionCalls();
696  double tol = Tolerance();
697 
698 // const char * par_name = fState.Name(i);
699 
700  // now input tolerance for migrad calls inside Minos (MnFunctionCross)
701  // before it was fixed to 0.05
702  // cut off too small tolerance (they are not needed)
703  tol = std::max(tol, 0.01);
704 
705  /*
706  if (PrintLevel() >=1) {
707  // print the real number of maxfcn used (defined in MnMinos)
708  int maxfcn_used = maxfcn;
709  if (maxfcn_used == 0) {
710  int nvar = fState.VariableParameters();
711  maxfcn_used = 2*(nvar+1)*(200 + 100*nvar + 5*nvar*nvar);
712  }
713 // std::cout << "HybridMinimizer::GetMinosError for parameter " << i << " " << par_name
714 // << " using max-calls " << maxfcn_used << ", tolerance " << tol << std::endl;
715  }
716  */
717 
718  if (runLower) low = minos.Loval(i,maxfcn,tol);
719  if (runUpper) up = minos.Upval(i,maxfcn,tol);
720 
721  ROOT::Minuit2::MinosError me(i, fMinimum->UserState().Value(i),low, up);
722 
723  if (prev_level > -2) RestoreGlobalPrintLevel(prev_level);
724 
725  // debug result of Minos
726  // print error message in Minos
727 
728 
729  if (debugLevel >= 1) {
730 /*
731  if (runLower) {
732  if (!me.LowerValid() )
733  std::cout << "Minos: Invalid lower error for parameter " << par_name << std::endl;
734  if(me.AtLowerLimit())
735  std::cout << "Minos: Parameter : " << par_name << " is at Lower limit."<<std::endl;
736  if(me.AtLowerMaxFcn())
737  std::cout << "Minos: Maximum number of function calls exceeded when running for lower error" <<std::endl;
738  if(me.LowerNewMin() )
739  std::cout << "Minos: New Minimum found while running Minos for lower error" <<std::endl;
740 
741  if (debugLevel > 1) std::cout << "Minos: Lower error for parameter " << par_name << " : " << me.Lower() << std::endl;
742 
743  }
744  if (runUpper) {
745  if (!me.UpperValid() )
746  std::cout << "Minos: Invalid upper error for parameter " << par_name << std::endl;
747  if(me.AtUpperLimit())
748  std::cout << "Minos: Parameter " << par_name << " is at Upper limit."<<std::endl;
749  if(me.AtUpperMaxFcn())
750  std::cout << "Minos: Maximum number of function calls exceeded when running for upper error" <<std::endl;
751  if(me.UpperNewMin() )
752  std::cout << "Minos: New Minimum found while running Minos for upper error" <<std::endl;
753 
754  if (debugLevel > 1) std::cout << "Minos: Upper error for parameter " << par_name << " : " << me.Upper() << std::endl;
755  }
756 */
757  }
758 
759  bool lowerInvalid = (runLower && !me.LowerValid() );
760  bool upperInvalid = (runUpper && !me.UpperValid() );
761  int mstatus = 0;
762  if (lowerInvalid || upperInvalid ) {
763  // set status accroding to bit
764  // bit 1: lower invalid Minos errors
765  // bit 2: uper invalid Minos error
766  // bit 3: invalid because max FCN
767  // bit 4 : invalid because a new minimum has been found
768  if (lowerInvalid) {
769  mstatus |= 1;
770  if (me.AtLowerMaxFcn() ) mstatus |= 4;
771  if (me.LowerNewMin() ) mstatus |= 8;
772  }
773  if(upperInvalid) {
774  mstatus |= 3;
775  if (me.AtUpperMaxFcn() ) mstatus |= 4;
776  if (me.UpperNewMin() ) mstatus |= 8;
777  }
778  //std::cout << "Error running Minos for parameter " << i << std::endl;
779  fStatus += 10*mstatus;
780  }
781 
782  errLow = me.Lower();
783  errUp = me.Upper();
784 
785  bool isValid = (runLower && me.LowerValid() ) || (runUpper && me.UpperValid() );
786  return isValid;
787 }
788 
789 bool HybridMinimizer::Scan(unsigned int ipar, unsigned int & nstep, double * x, double * y, double xmin, double xmax) {
790  // scan a parameter (variable) around the minimum value
791  // the parameters must have been set before
792  // if xmin=0 && xmax == 0 by default scan around 2 sigma of the error
793  // if the errors are also zero then scan from min and max of parameter range
794 
795  if (!fMinuitFCN) {
796  MN_ERROR_MSG2("HybridMinimizer::Scan"," Function must be set before using Scan");
797  return false;
798  }
799 
800  if ( ipar > fState.MinuitParameters().size() ) {
801  MN_ERROR_MSG2("HybridMinimizer::Scan"," Invalid number. Minimizer variables must be set before using Scan");
802  return false;
803  }
804 
805  // switch off Minuit2 printing
806  int prev_level = (PrintLevel() <= 0 ) ? TurnOffPrintInfoLevel() : -2;
807 
808  MnPrint::SetLevel( PrintLevel() );
809 
810 
811  // set the precision if needed
812  if (Precision() > 0) fState.SetPrecision(Precision());
813 
814  MnParameterScan scan( *fMinuitFCN, fState.Parameters() );
815  double amin = scan.Fval(); // fcn value of the function before scan
816 
817  // first value is param value
818  std::vector<std::pair<double, double> > result = scan(ipar, nstep-1, xmin, xmax);
819 
820  if (prev_level > -2) RestoreGlobalPrintLevel(prev_level);
821 
822  if (result.size() != nstep) {
823  MN_ERROR_MSG2("HybridMinimizer::Scan"," Invalid result from MnParameterScan");
824  return false;
825  }
826  // sort also the returned points in x
827  std::sort(result.begin(), result.end() );
828 
829 
830  for (unsigned int i = 0; i < nstep; ++i ) {
831  x[i] = result[i].first;
832  y[i] = result[i].second;
833  }
834 
835  // what to do if a new minimum has been found ?
836  // use that as new minimum
837  if (scan.Fval() < amin ) {
838  if (PrintLevel() > 0) MN_INFO_MSG2("HybridMinimizer::Scan","A new minimum has been found");
839  fState.SetValue(ipar, scan.Parameters().Value(ipar) );
840 
841  }
842 
843 
844  return true;
845 }
846 
847 bool HybridMinimizer::Contour(unsigned int ipar, unsigned int jpar, unsigned int & npoints, double * x, double * y) {
848  // contour plot for parameter i and j
849  // need a valid FunctionMinimum otherwise exits
850  if (fMinimum == nullptr) {
851  MN_ERROR_MSG2("HybridMinimizer::Contour"," no function minimum existing. Must minimize function before");
852  return false;
853  }
854 
855  if (!fMinimum->IsValid() ) {
856  MN_ERROR_MSG2("HybridMinimizer::Contour","Invalid function minimum");
857  return false;
858  }
859  assert(fMinuitFCN);
860 
861  fMinuitFCN->SetErrorDef(ErrorDef() );
862  // if error def has been changed update it in FunctionMinimum
863  if (ErrorDef() != fMinimum->Up() )
864  fMinimum->SetErrorDef(ErrorDef() );
865 
866  // switch off Minuit2 printing (for level of 0,1)
867  int prev_level = (PrintLevel() <= 1 ) ? TurnOffPrintInfoLevel() : -2;
868 
869  MnPrint::SetLevel( PrintLevel() );
870 
871  // set the precision if needed
872  if (Precision() > 0) fState.SetPrecision(Precision());
873 
874  // eventually one should specify tolerance in contours
875  MnContours contour(*fMinuitFCN, *fMinimum, Strategy() );
876 
877  if (prev_level > -2) RestoreGlobalPrintLevel(prev_level);
878 
879  std::vector<std::pair<double,double> > result = contour(ipar,jpar, npoints);
880  if (result.size() != npoints) {
881  MN_ERROR_MSG2("HybridMinimizer::Contour"," Invalid result from MnContours");
882  return false;
883  }
884  for (unsigned int i = 0; i < npoints; ++i ) {
885  x[i] = result[i].first;
886  y[i] = result[i].second;
887  }
888 
889 
890  return true;
891 
892 
893 }
894 
896  // find Hessian (full second derivative calculations)
897  // the contained state will be updated with the Hessian result
898  // in case a function minimum exists and is valid the result will be
899  // appended in the function minimum
900 
901  if (!fMinuitFCN) {
902  MN_ERROR_MSG2("HybridMinimizer::Hesse","FCN function has not been set");
903  return false;
904  }
905 
906  int strategy = Strategy();
907  int maxfcn = MaxFunctionCalls();
908 
909  // switch off Minuit2 printing
910  int prev_level = (PrintLevel() <= 0 ) ? TurnOffPrintInfoLevel() : -2;
911 
912  MnPrint::SetLevel( PrintLevel() );
913 
914  // set the precision if needed
915  if (Precision() > 0) fState.SetPrecision(Precision());
916 
917  ROOT::Minuit2::MnHesse hesse( strategy );
918 
919  // case when function minimum exists
920  if (fMinimum ) {
921  // run hesse and function minimum will be updated with Hesse result
922  hesse( *fMinuitFCN, *fMinimum, maxfcn );
923  fState = fMinimum->UserState();
924  }
925 
926  else {
927  // run Hesse on point stored in current state (independent of function minimum validity)
928  // (x == 0)
929  fState = hesse( *fMinuitFCN, fState, maxfcn);
930  }
931 
932  if (prev_level > -2) RestoreGlobalPrintLevel(prev_level);
933 
934  if (PrintLevel() >= 3) {
935 // std::cout << "State returned from Hesse " << std::endl;
936 // std::cout << fState << std::endl;
937  }
938 
939  if (!fState.HasCovariance() ) {
940  // if false means error is not valid and this is due to a failure in Hesse
941  if (PrintLevel() > 0) MN_INFO_MSG2("HybridMinimizer::Hesse","Hesse failed ");
942  // update minimizer error status
943  int hstatus = 4;
944  // information on error state can be retrieved only if fMinimum is available
945  if (fMinimum) {
946  if (fMinimum->Error().HesseFailed() ) hstatus = 1;
947  if (fMinimum->Error().InvertFailed() ) hstatus = 2;
948  else if (!(fMinimum->Error().IsPosDef()) ) hstatus = 3;
949  }
950  fStatus += 100*hstatus;
951  return false;
952  }
953 
954  return true;
955 }
956 
958  // return status of covariance matrix
959  //-1 - not available (inversion failed or Hesse failed)
960  // 0 - available but not positive defined
961  // 1 - covariance only approximate
962  // 2 full matrix but forced pos def
963  // 3 full accurate matrix
964 
965  if (fMinimum) {
966  // case a function minimum is available
967  if (fMinimum->HasAccurateCovar() ) return 3;
968  else if (fMinimum->HasMadePosDefCovar() ) return 2;
969  else if (fMinimum->HasValidCovariance() ) return 1;
970  else if (fMinimum->HasCovariance() ) return 0;
971  return -1;
972  }
973  else {
974  // case fMinimum is not available - use state information
975  return fState.CovarianceStatus();
976  }
977  return 0;
978 }
979 
980 }
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 )