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