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 // Implementation file for class Minuit2Minimizer
12 
13 #include "Minuit2/Minuit2Minimizer.h"
14 
15 #include "Math/IFunction.h"
16 #include "Math/IOptions.h"
17 
18 #include "Fit/ParameterSettings.h"
19 
20 #include "Minuit2/FCNAdapter.h"
21 #include "Minuit2/FumiliFCNAdapter.h"
22 #include "Minuit2/FCNGradAdapter.h"
23 #include "Minuit2/FunctionMinimum.h"
24 #include "Minuit2/MnMigrad.h"
25 #include "Minuit2/MnMinos.h"
26 #include "Minuit2/MinosError.h"
27 #include "Minuit2/MnHesse.h"
28 #include "Minuit2/MinuitParameter.h"
29 #include "Minuit2/MnUserFcn.h"
30 #include "Minuit2/MnPrint.h"
31 #include "Minuit2/VariableMetricMinimizer.h"
32 #include "Minuit2/SimplexMinimizer.h"
33 #include "Minuit2/CombinedMinimizer.h"
34 #include "Minuit2/ScanMinimizer.h"
35 #include "Minuit2/FumiliMinimizer.h"
36 #include "Minuit2/MnParameterScan.h"
37 #include "Minuit2/MnContours.h"
38 #include "Minuit2/MnTraceObject.h"
39 #include "Minuit2/MinimumBuilder.h"
40 
41 #include <cassert>
42 #include <iostream>
43 #include <algorithm>
44 #include <functional>
45 
46 #ifdef USE_ROOT_ERROR
47 #include "TROOT.h"
48 #include "TMinuit2TraceObject.h"
49 #endif
50 
51 namespace ROOT {
52 
53 namespace Minuit2 {
54 
55 // functions needed to control siwthc off of Minuit2 printing level
56 #ifdef USE_ROOT_ERROR
TurnOffPrintInfoLevel()57 int TurnOffPrintInfoLevel()
58 {
59    // switch off Minuit2 printing of INFO message (cut off is 1001)
60    int prevErrorIgnoreLevel = gErrorIgnoreLevel;
61    if (prevErrorIgnoreLevel < 1001) {
62       gErrorIgnoreLevel = 1001;
63       return prevErrorIgnoreLevel;
64    }
65    return -2; // no op in this case
66 }
67 
RestoreGlobalPrintLevel(int value)68 void RestoreGlobalPrintLevel(int value)
69 {
70    gErrorIgnoreLevel = value;
71 }
72 #else
73 // dummy functions
74 int TurnOffPrintInfoLevel()
75 {
76    return -1;
77 }
78 int ControlPrintLevel()
79 {
80    return -1;
81 }
82 void RestoreGlobalPrintLevel(int) {}
83 #endif
84 
Minuit2Minimizer(ROOT::Minuit2::EMinimizerType type)85 Minuit2Minimizer::Minuit2Minimizer(ROOT::Minuit2::EMinimizerType type)
86    : Minimizer(), fDim(0), fMinimizer(0), fMinuitFCN(0), fMinimum(0)
87 {
88    // Default constructor implementation depending on minimizer type
89    SetMinimizerType(type);
90 }
91 
Minuit2Minimizer(const char * type)92 Minuit2Minimizer::Minuit2Minimizer(const char *type) : Minimizer(), fDim(0), fMinimizer(0), fMinuitFCN(0), fMinimum(0)
93 {
94    // constructor from a string
95 
96    std::string algoname(type);
97    // tolower() is not an  std function (Windows)
98    std::transform(algoname.begin(), algoname.end(), algoname.begin(), (int (*)(int))tolower);
99 
100    EMinimizerType algoType = kMigrad;
101    if (algoname == "simplex")
102       algoType = kSimplex;
103    if (algoname == "minimize")
104       algoType = kCombined;
105    if (algoname == "scan")
106       algoType = kScan;
107    if (algoname == "fumili")
108       algoType = kFumili;
109    if (algoname == "bfgs")
110       algoType = kMigradBFGS;
111 
112    SetMinimizerType(algoType);
113 }
114 
SetMinimizerType(ROOT::Minuit2::EMinimizerType type)115 void Minuit2Minimizer::SetMinimizerType(ROOT::Minuit2::EMinimizerType type)
116 {
117    // Set  minimizer algorithm type
118    fUseFumili = false;
119    switch (type) {
120    case ROOT::Minuit2::kMigrad:
121       // std::cout << "Minuit2Minimizer: minimize using MIGRAD " << std::endl;
122       SetMinimizer(new ROOT::Minuit2::VariableMetricMinimizer());
123       return;
124    case ROOT::Minuit2::kMigradBFGS:
125       // std::cout << "Minuit2Minimizer: minimize using MIGRAD " << std::endl;
126       SetMinimizer(new ROOT::Minuit2::VariableMetricMinimizer(VariableMetricMinimizer::BFGSType()));
127       return;
128    case ROOT::Minuit2::kSimplex:
129       // std::cout << "Minuit2Minimizer: minimize using SIMPLEX " << std::endl;
130       SetMinimizer(new ROOT::Minuit2::SimplexMinimizer());
131       return;
132    case ROOT::Minuit2::kCombined: SetMinimizer(new ROOT::Minuit2::CombinedMinimizer()); return;
133    case ROOT::Minuit2::kScan: SetMinimizer(new ROOT::Minuit2::ScanMinimizer()); return;
134    case ROOT::Minuit2::kFumili:
135       SetMinimizer(new ROOT::Minuit2::FumiliMinimizer());
136       fUseFumili = true;
137       return;
138    default:
139       // migrad minimizer
140       SetMinimizer(new ROOT::Minuit2::VariableMetricMinimizer());
141    }
142 }
143 
~Minuit2Minimizer()144 Minuit2Minimizer::~Minuit2Minimizer()
145 {
146    // Destructor implementation.
147    if (fMinimizer)
148       delete fMinimizer;
149    if (fMinuitFCN)
150       delete fMinuitFCN;
151    if (fMinimum)
152       delete fMinimum;
153 }
154 
Minuit2Minimizer(const Minuit2Minimizer &)155 Minuit2Minimizer::Minuit2Minimizer(const Minuit2Minimizer &) : ROOT::Math::Minimizer()
156 {
157    // Implementation of copy constructor.
158 }
159 
operator =(const Minuit2Minimizer & rhs)160 Minuit2Minimizer &Minuit2Minimizer::operator=(const Minuit2Minimizer &rhs)
161 {
162    // Implementation of assignment operator.
163    if (this == &rhs)
164       return *this; // time saving self-test
165    return *this;
166 }
167 
Clear()168 void Minuit2Minimizer::Clear()
169 {
170    // delete the state in case of consecutive minimizations
171    fState = MnUserParameterState();
172    // clear also the function minimum
173    if (fMinimum)
174       delete fMinimum;
175    fMinimum = 0;
176 }
177 
178 // set variables
179 
SetVariable(unsigned int ivar,const std::string & name,double val,double step)180 bool Minuit2Minimizer::SetVariable(unsigned int ivar, const std::string &name, double val, double step)
181 {
182    // set a free variable.
183    // Add the variable if not existing otherwise  set value if exists already
184    // this is implemented in MnUserParameterState::Add
185    // if index is wrong (i.e. variable already exists but with a different index return false) but
186    // value is set for corresponding variable name
187 
188    //    std::cout << " add parameter " << name << "  " <<  val << " step " << step << std::endl;
189    MnPrint print("Minuit2Minimizer::SetVariable", PrintLevel());
190 
191    if (step <= 0) {
192       print.Info("Parameter", name, "has zero or invalid step size - consider it as constant");
193       fState.Add(name.c_str(), val);
194    } else
195       fState.Add(name.c_str(), val, step);
196 
197    unsigned int minuit2Index = fState.Index(name.c_str());
198    if (minuit2Index != ivar) {
199       print.Warn("Wrong index", minuit2Index, "used for the variable", name);
200       ivar = minuit2Index;
201       return false;
202    }
203    fState.RemoveLimits(ivar);
204 
205    return true;
206 }
207 
SetLowerLimitedVariable(unsigned int ivar,const std::string & name,double val,double step,double lower)208 bool Minuit2Minimizer::SetLowerLimitedVariable(unsigned int ivar, const std::string &name, double val, double step,
209                                                double lower)
210 {
211    // add a lower bounded variable
212    if (!SetVariable(ivar, name, val, step))
213       return false;
214    fState.SetLowerLimit(ivar, lower);
215    return true;
216 }
217 
SetUpperLimitedVariable(unsigned int ivar,const std::string & name,double val,double step,double upper)218 bool Minuit2Minimizer::SetUpperLimitedVariable(unsigned int ivar, const std::string &name, double val, double step,
219                                                double upper)
220 {
221    // add a upper bounded variable
222    if (!SetVariable(ivar, name, val, step))
223       return false;
224    fState.SetUpperLimit(ivar, upper);
225    return true;
226 }
227 
SetLimitedVariable(unsigned int ivar,const std::string & name,double val,double step,double lower,double upper)228 bool Minuit2Minimizer::SetLimitedVariable(unsigned int ivar, const std::string &name, double val, double step,
229                                           double lower, double upper)
230 {
231    // add a double bound variable
232    if (!SetVariable(ivar, name, val, step))
233       return false;
234    fState.SetLimits(ivar, lower, upper);
235    return true;
236 }
237 
SetFixedVariable(unsigned int ivar,const std::string & name,double val)238 bool Minuit2Minimizer::SetFixedVariable(unsigned int ivar, const std::string &name, double val)
239 {
240    // add a fixed variable
241    // need a step size otherwise treated as a constant
242    // use 10%
243    double step = (val != 0) ? 0.1 * std::abs(val) : 0.1;
244    if (!SetVariable(ivar, name, val, step)) {
245       ivar = fState.Index(name.c_str());
246    }
247    fState.Fix(ivar);
248    return true;
249 }
250 
VariableName(unsigned int ivar) const251 std::string Minuit2Minimizer::VariableName(unsigned int ivar) const
252 {
253    // return the variable name
254    if (ivar >= fState.MinuitParameters().size())
255       return std::string();
256    return fState.GetName(ivar);
257 }
258 
VariableIndex(const std::string & name) const259 int Minuit2Minimizer::VariableIndex(const std::string &name) const
260 {
261    // return the variable index
262    // check if variable exist
263    return fState.Trafo().FindIndex(name);
264 }
265 
SetVariableValue(unsigned int ivar,double val)266 bool Minuit2Minimizer::SetVariableValue(unsigned int ivar, double val)
267 {
268    // set value for variable ivar (only for existing parameters)
269    if (ivar >= fState.MinuitParameters().size())
270       return false;
271    fState.SetValue(ivar, val);
272    return true;
273 }
274 
SetVariableValues(const double * x)275 bool Minuit2Minimizer::SetVariableValues(const double *x)
276 {
277    // set value for variable ivar (only for existing parameters)
278    unsigned int n = fState.MinuitParameters().size();
279    if (n == 0)
280       return false;
281    for (unsigned int ivar = 0; ivar < n; ++ivar)
282       fState.SetValue(ivar, x[ivar]);
283    return true;
284 }
285 
SetVariableStepSize(unsigned int ivar,double step)286 bool Minuit2Minimizer::SetVariableStepSize(unsigned int ivar, double step)
287 {
288    // set the step-size of an existing variable
289    // parameter must exist or return false
290    if (ivar >= fState.MinuitParameters().size())
291       return false;
292    fState.SetError(ivar, step);
293    return true;
294 }
295 
SetVariableLowerLimit(unsigned int ivar,double lower)296 bool Minuit2Minimizer::SetVariableLowerLimit(unsigned int ivar, double lower)
297 {
298    // set the limits of an existing variable
299    // parameter must exist or return false
300    if (ivar >= fState.MinuitParameters().size())
301       return false;
302    fState.SetLowerLimit(ivar, lower);
303    return true;
304 }
SetVariableUpperLimit(unsigned int ivar,double upper)305 bool Minuit2Minimizer::SetVariableUpperLimit(unsigned int ivar, double upper)
306 {
307    // set the limits of an existing variable
308    // parameter must exist or return false
309    if (ivar >= fState.MinuitParameters().size())
310       return false;
311    fState.SetUpperLimit(ivar, upper);
312    return true;
313 }
314 
SetVariableLimits(unsigned int ivar,double lower,double upper)315 bool Minuit2Minimizer::SetVariableLimits(unsigned int ivar, double lower, double upper)
316 {
317    // set the limits of an existing variable
318    // parameter must exist or return false
319    if (ivar >= fState.MinuitParameters().size())
320       return false;
321    fState.SetLimits(ivar, lower, upper);
322    return true;
323 }
324 
FixVariable(unsigned int ivar)325 bool Minuit2Minimizer::FixVariable(unsigned int ivar)
326 {
327    // Fix an existing variable
328    if (ivar >= fState.MinuitParameters().size())
329       return false;
330    fState.Fix(ivar);
331    return true;
332 }
333 
ReleaseVariable(unsigned int ivar)334 bool Minuit2Minimizer::ReleaseVariable(unsigned int ivar)
335 {
336    // Release an existing variable
337    if (ivar >= fState.MinuitParameters().size())
338       return false;
339    fState.Release(ivar);
340    return true;
341 }
342 
IsFixedVariable(unsigned int ivar) const343 bool Minuit2Minimizer::IsFixedVariable(unsigned int ivar) const
344 {
345    // query if variable is fixed
346    if (ivar >= fState.MinuitParameters().size()) {
347       MnPrint print("Minuit2Minimizer", PrintLevel());
348       print.Error("Wrong variable index");
349       return false;
350    }
351    return (fState.Parameter(ivar).IsFixed() || fState.Parameter(ivar).IsConst());
352 }
353 
GetVariableSettings(unsigned int ivar,ROOT::Fit::ParameterSettings & varObj) const354 bool Minuit2Minimizer::GetVariableSettings(unsigned int ivar, ROOT::Fit::ParameterSettings &varObj) const
355 {
356    // retrieve variable settings (all set info on the variable)
357    if (ivar >= fState.MinuitParameters().size()) {
358       MnPrint print("Minuit2Minimizer", PrintLevel());
359       print.Error("Wrong variable index");
360       return false;
361    }
362    const MinuitParameter &par = fState.Parameter(ivar);
363    varObj.Set(par.Name(), par.Value(), par.Error());
364    if (par.HasLowerLimit()) {
365       if (par.HasUpperLimit()) {
366          varObj.SetLimits(par.LowerLimit(), par.UpperLimit());
367       } else {
368          varObj.SetLowerLimit(par.LowerLimit());
369       }
370    } else if (par.HasUpperLimit()) {
371       varObj.SetUpperLimit(par.UpperLimit());
372    }
373    if (par.IsConst() || par.IsFixed())
374       varObj.Fix();
375    return true;
376 }
377 
SetFunction(const ROOT::Math::IMultiGenFunction & func)378 void Minuit2Minimizer::SetFunction(const ROOT::Math::IMultiGenFunction &func)
379 {
380    // set function to be minimized
381    if (fMinuitFCN)
382       delete fMinuitFCN;
383    fDim = func.NDim();
384    if (!fUseFumili) {
385       fMinuitFCN = new ROOT::Minuit2::FCNAdapter<ROOT::Math::IMultiGenFunction>(func, ErrorDef());
386    } else {
387       // for Fumili the fit method function interface is required
388       const ROOT::Math::FitMethodFunction *fcnfunc = dynamic_cast<const ROOT::Math::FitMethodFunction *>(&func);
389       if (!fcnfunc) {
390          MnPrint print("Minuit2Minimizer", PrintLevel());
391          print.Error("Wrong Fit method function for Fumili");
392          return;
393       }
394       fMinuitFCN = new ROOT::Minuit2::FumiliFCNAdapter<ROOT::Math::FitMethodFunction>(*fcnfunc, fDim, ErrorDef());
395    }
396 }
397 
SetFunction(const ROOT::Math::IMultiGradFunction & func)398 void Minuit2Minimizer::SetFunction(const ROOT::Math::IMultiGradFunction &func)
399 {
400    // set function to be minimized
401    fDim = func.NDim();
402    if (fMinuitFCN)
403       delete fMinuitFCN;
404    if (!fUseFumili) {
405       fMinuitFCN = new ROOT::Minuit2::FCNGradAdapter<ROOT::Math::IMultiGradFunction>(func, ErrorDef());
406    } else {
407       // for Fumili the fit method function interface is required
408       const ROOT::Math::FitMethodGradFunction *fcnfunc = dynamic_cast<const ROOT::Math::FitMethodGradFunction *>(&func);
409       if (!fcnfunc) {
410          MnPrint print("Minuit2Minimizer", PrintLevel());
411          print.Error("Wrong Fit method function for Fumili");
412          return;
413       }
414       fMinuitFCN = new ROOT::Minuit2::FumiliFCNAdapter<ROOT::Math::FitMethodGradFunction>(*fcnfunc, fDim, ErrorDef());
415    }
416 }
417 
Minimize()418 bool Minuit2Minimizer::Minimize()
419 {
420    // perform the minimization
421    // store a copy of FunctionMinimum
422 
423    MnPrint print("Minuit2Minimizer::Minimize", PrintLevel());
424 
425    if (!fMinuitFCN) {
426       print.Error("FCN function has not been set");
427       return false;
428    }
429 
430    assert(GetMinimizer() != 0);
431 
432    // delete result of previous minimization
433    if (fMinimum)
434       delete fMinimum;
435    fMinimum = 0;
436 
437    const int maxfcn = MaxFunctionCalls();
438    const double tol = Tolerance();
439    const int strategyLevel = Strategy();
440    fMinuitFCN->SetErrorDef(ErrorDef());
441 
442    const int printLevel = PrintLevel();
443    if (PrintLevel() >= 1) {
444       // print the real number of maxfcn used (defined in ModularFuncitonMinimizer)
445       int maxfcn_used = maxfcn;
446       if (maxfcn_used == 0) {
447          int nvar = fState.VariableParameters();
448          maxfcn_used = 200 + 100 * nvar + 5 * nvar * nvar;
449       }
450       std::cout << "Minuit2Minimizer: Minimize with max-calls " << maxfcn_used << " convergence for edm < " << tol
451                 << " strategy " << strategyLevel << std::endl;
452    }
453 
454    // internal minuit messages
455    fMinimizer->Builder().SetPrintLevel(printLevel);
456 
457    // switch off Minuit2 printing
458    const int prev_level = (printLevel <= 0) ? TurnOffPrintInfoLevel() : -2;
459    const int prevGlobalLevel = MnPrint::SetGlobalLevel(printLevel);
460 
461    // set the precision if needed
462    if (Precision() > 0)
463       fState.SetPrecision(Precision());
464 
465    // set strategy and add extra options if needed
466    ROOT::Minuit2::MnStrategy strategy(strategyLevel);
467    ROOT::Math::IOptions *minuit2Opt = ROOT::Math::MinimizerOptions::FindDefault("Minuit2");
468    if (minuit2Opt) {
469       // set extra  options
470       int nGradCycles = strategy.GradientNCycles();
471       int nHessCycles = strategy.HessianNCycles();
472       int nHessGradCycles = strategy.HessianGradientNCycles();
473 
474       double gradTol = strategy.GradientTolerance();
475       double gradStepTol = strategy.GradientStepTolerance();
476       double hessStepTol = strategy.HessianStepTolerance();
477       double hessG2Tol = strategy.HessianG2Tolerance();
478 
479       minuit2Opt->GetValue("GradientNCycles", nGradCycles);
480       minuit2Opt->GetValue("HessianNCycles", nHessCycles);
481       minuit2Opt->GetValue("HessianGradientNCycles", nHessGradCycles);
482 
483       minuit2Opt->GetValue("GradientTolerance", gradTol);
484       minuit2Opt->GetValue("GradientStepTolerance", gradStepTol);
485       minuit2Opt->GetValue("HessianStepTolerance", hessStepTol);
486       minuit2Opt->GetValue("HessianG2Tolerance", hessG2Tol);
487 
488       strategy.SetGradientNCycles(nGradCycles);
489       strategy.SetHessianNCycles(nHessCycles);
490       strategy.SetHessianGradientNCycles(nHessGradCycles);
491 
492       strategy.SetGradientTolerance(gradTol);
493       strategy.SetGradientStepTolerance(gradStepTol);
494       strategy.SetHessianStepTolerance(hessStepTol);
495       strategy.SetHessianG2Tolerance(hessStepTol);
496 
497       int storageLevel = 1;
498       bool ret = minuit2Opt->GetValue("StorageLevel", storageLevel);
499       if (ret)
500          SetStorageLevel(storageLevel);
501 
502       if (printLevel > 0) {
503          std::cout << "Minuit2Minimizer::Minuit  - Changing default options" << std::endl;
504          minuit2Opt->Print();
505       }
506    }
507 
508    // set a minimizer tracer object (default for printlevel=10, from gROOT for printLevel=11)
509    // use some special print levels
510    MnTraceObject *traceObj = 0;
511 #ifdef USE_ROOT_ERROR
512    if (printLevel == 10 && gROOT) {
513       TObject *obj = gROOT->FindObject("Minuit2TraceObject");
514       traceObj = dynamic_cast<ROOT::Minuit2::MnTraceObject *>(obj);
515       if (traceObj) {
516          // need to remove from the list
517          gROOT->Remove(obj);
518       }
519    }
520    if (printLevel == 20 || printLevel == 30 || printLevel == 40 || (printLevel >= 20000 && printLevel < 30000)) {
521       int parNumber = printLevel - 20000;
522       if (printLevel == 20)
523          parNumber = -1;
524       if (printLevel == 30)
525          parNumber = -2;
526       if (printLevel == 40)
527          parNumber = 0;
528       traceObj = new TMinuit2TraceObject(parNumber);
529    }
530 #endif
531    if (printLevel == 100 || (printLevel >= 10000 && printLevel < 20000)) {
532       int parNumber = printLevel - 10000;
533       traceObj = new MnTraceObject(parNumber);
534    }
535    if (traceObj) {
536       traceObj->Init(fState);
537       SetTraceObject(*traceObj);
538    }
539 
540    const ROOT::Minuit2::FCNGradientBase *gradFCN = dynamic_cast<const ROOT::Minuit2::FCNGradientBase *>(fMinuitFCN);
541    if (gradFCN != 0) {
542       // use gradient
543       // SetPrintLevel(3);
544       ROOT::Minuit2::FunctionMinimum min = GetMinimizer()->Minimize(*gradFCN, fState, strategy, maxfcn, tol);
545       fMinimum = new ROOT::Minuit2::FunctionMinimum(min);
546    } else {
547       ROOT::Minuit2::FunctionMinimum min = GetMinimizer()->Minimize(*GetFCN(), fState, strategy, maxfcn, tol);
548       fMinimum = new ROOT::Minuit2::FunctionMinimum(min);
549    }
550 
551    // check if Hesse needs to be run
552    if (fMinimum->IsValid() && IsValidError() && fMinimum->State().Error().Dcovar() != 0) {
553       // run Hesse (Hesse will add results in the last state of fMinimum
554       ROOT::Minuit2::MnHesse hesse(strategy);
555       hesse(*fMinuitFCN, *fMinimum, maxfcn);
556    }
557 
558    // -2 is the highest low invalid value for gErrorIgnoreLevel
559    if (prev_level > -2)
560       RestoreGlobalPrintLevel(prev_level);
561    MnPrint::SetGlobalLevel(prevGlobalLevel);
562 
563    // copy minimum state (parameter values and errors)
564    fState = fMinimum->UserState();
565    bool ok = ExamineMinimum(*fMinimum);
566    // fMinimum = 0;
567 
568    // delete trace object if it was constructed
569    if (traceObj) {
570       delete traceObj;
571    }
572    return ok;
573 }
574 
ExamineMinimum(const ROOT::Minuit2::FunctionMinimum & min)575 bool Minuit2Minimizer::ExamineMinimum(const ROOT::Minuit2::FunctionMinimum &min)
576 {
577    /// study the function minimum
578 
579    // debug ( print all the states)
580    int debugLevel = PrintLevel();
581    if (debugLevel >= 3) {
582 
583       const std::vector<ROOT::Minuit2::MinimumState> &iterationStates = min.States();
584       std::cout << "Number of iterations " << iterationStates.size() << std::endl;
585       for (unsigned int i = 0; i < iterationStates.size(); ++i) {
586          // std::cout << iterationStates[i] << std::endl;
587          const ROOT::Minuit2::MinimumState &st = iterationStates[i];
588          std::cout << "----------> Iteration " << i << std::endl;
589          int pr = std::cout.precision(12);
590          std::cout << "            FVAL = " << st.Fval() << " Edm = " << st.Edm() << " Nfcn = " << st.NFcn()
591                    << std::endl;
592          std::cout.precision(pr);
593          if (st.HasCovariance())
594             std::cout << "            Error matrix change = " << st.Error().Dcovar() << std::endl;
595          if (st.HasParameters()) {
596             std::cout << "            Parameters : ";
597             // need to transform from internal to external
598             for (int j = 0; j < st.size(); ++j)
599                std::cout << " p" << j << " = " << fState.Int2ext(j, st.Vec()(j));
600             std::cout << std::endl;
601          }
602       }
603    }
604 
605    fStatus = 0;
606    std::string txt;
607    if (!min.HasPosDefCovar()) {
608       // this happens normally when Hesse failed
609       // it can happen in case MnSeed failed (see ROOT-9522)
610       txt = "Covar is not pos def";
611       fStatus = 5;
612    }
613    if (min.HasMadePosDefCovar()) {
614       txt = "Covar was made pos def";
615       fStatus = 1;
616    }
617    if (min.HesseFailed()) {
618       txt = "Hesse is not valid";
619       fStatus = 2;
620    }
621    if (min.IsAboveMaxEdm()) {
622       txt = "Edm is above max";
623       fStatus = 3;
624    }
625    if (min.HasReachedCallLimit()) {
626       txt = "Reached call limit";
627       fStatus = 4;
628    }
629 
630    MnPrint print("Minuit2Minimizer::Minimize", debugLevel);
631    bool validMinimum = min.IsValid();
632    if (validMinimum) {
633       // print a warning message in case something is not ok
634       if (fStatus != 0 && debugLevel > 0)
635          print.Warn(txt);
636    } else {
637       // minimum is not valid when state is not valid and edm is over max or has passed call limits
638       if (fStatus == 0) {
639          // this should not happen
640          txt = "unknown failure";
641          fStatus = 6;
642       }
643       print.Warn("Minimization did NOT converge,", txt);
644    }
645 
646    if (debugLevel >= 1)
647       PrintResults();
648 
649    // set the minimum values in the fValues vector
650    const std::vector<MinuitParameter> &paramsObj = fState.MinuitParameters();
651    if (paramsObj.size() == 0)
652       return 0;
653    assert(fDim == paramsObj.size());
654    // re-size vector if it has changed after a new minimization
655    if (fValues.size() != fDim)
656       fValues.resize(fDim);
657    for (unsigned int i = 0; i < fDim; ++i) {
658       fValues[i] = paramsObj[i].Value();
659    }
660 
661    return validMinimum;
662 }
663 
PrintResults()664 void Minuit2Minimizer::PrintResults()
665 {
666    // print results of minimization
667    if (!fMinimum)
668       return;
669    if (fMinimum->IsValid()) {
670       // valid minimum
671       std::cout << "Minuit2Minimizer : Valid minimum - status = " << fStatus << std::endl;
672       int pr = std::cout.precision(18);
673       std::cout << "FVAL  = " << fState.Fval() << std::endl;
674       std::cout << "Edm   = " << fState.Edm() << std::endl;
675       std::cout.precision(pr);
676       std::cout << "Nfcn  = " << fState.NFcn() << std::endl;
677       for (unsigned int i = 0; i < fState.MinuitParameters().size(); ++i) {
678          const MinuitParameter &par = fState.Parameter(i);
679          std::cout << par.Name() << "\t  = " << par.Value() << "\t ";
680          if (par.IsFixed())
681             std::cout << "(fixed)" << std::endl;
682          else if (par.IsConst())
683             std::cout << "(const)" << std::endl;
684          else if (par.HasLimits())
685             std::cout << "+/-  " << par.Error() << "\t(limited)" << std::endl;
686          else
687             std::cout << "+/-  " << par.Error() << std::endl;
688       }
689    } else {
690       std::cout << "Minuit2Minimizer : Invalid Minimum - status = " << fStatus << std::endl;
691       std::cout << "FVAL  = " << fState.Fval() << std::endl;
692       std::cout << "Edm   = " << fState.Edm() << std::endl;
693       std::cout << "Nfcn  = " << fState.NFcn() << std::endl;
694    }
695 }
696 
Errors() const697 const double *Minuit2Minimizer::Errors() const
698 {
699    // return error at minimum (set to zero for fixed and constant params)
700    const std::vector<MinuitParameter> &paramsObj = fState.MinuitParameters();
701    if (paramsObj.size() == 0)
702       return 0;
703    assert(fDim == paramsObj.size());
704    // be careful for multiple calls of this function. I will redo an allocation here
705    // only when size of vectors has changed (e.g. after a new minimization)
706    if (fErrors.size() != fDim)
707       fErrors.resize(fDim);
708    for (unsigned int i = 0; i < fDim; ++i) {
709       const MinuitParameter &par = paramsObj[i];
710       if (par.IsFixed() || par.IsConst())
711          fErrors[i] = 0;
712       else
713          fErrors[i] = par.Error();
714    }
715 
716    return &fErrors.front();
717 }
718 
CovMatrix(unsigned int i,unsigned int j) const719 double Minuit2Minimizer::CovMatrix(unsigned int i, unsigned int j) const
720 {
721    // get value of covariance matrices (transform from external to internal indices)
722    if (i >= fDim || j >= fDim)
723       return 0;
724    if (!fState.HasCovariance())
725       return 0; // no info available when minimization has failed
726    if (fState.Parameter(i).IsFixed() || fState.Parameter(i).IsConst())
727       return 0;
728    if (fState.Parameter(j).IsFixed() || fState.Parameter(j).IsConst())
729       return 0;
730    unsigned int k = fState.IntOfExt(i);
731    unsigned int l = fState.IntOfExt(j);
732    return fState.Covariance()(k, l);
733 }
734 
GetCovMatrix(double * cov) const735 bool Minuit2Minimizer::GetCovMatrix(double *cov) const
736 {
737    // get value of covariance matrices
738    if (!fState.HasCovariance())
739       return false; // no info available when minimization has failed
740    for (unsigned int i = 0; i < fDim; ++i) {
741       if (fState.Parameter(i).IsFixed() || fState.Parameter(i).IsConst()) {
742          for (unsigned int j = 0; j < fDim; ++j) {
743             cov[i * fDim + j] = 0;
744          }
745       } else {
746          unsigned int l = fState.IntOfExt(i);
747          for (unsigned int j = 0; j < fDim; ++j) {
748             // could probably speed up this loop (if needed)
749             int k = i * fDim + j;
750             if (fState.Parameter(j).IsFixed() || fState.Parameter(j).IsConst())
751                cov[k] = 0;
752             else {
753                // need to transform from external to internal indices)
754                // for taking care of the removed fixed row/columns in the Minuit2 representation
755                unsigned int m = fState.IntOfExt(j);
756                cov[k] = fState.Covariance()(l, m);
757             }
758          }
759       }
760    }
761    return true;
762 }
763 
GetHessianMatrix(double * hess) const764 bool Minuit2Minimizer::GetHessianMatrix(double *hess) const
765 {
766    // get value of Hessian matrix
767    // this is the second derivative matrices
768    if (!fState.HasCovariance())
769       return false; // no info available when minimization has failed
770    for (unsigned int i = 0; i < fDim; ++i) {
771       if (fState.Parameter(i).IsFixed() || fState.Parameter(i).IsConst()) {
772          for (unsigned int j = 0; j < fDim; ++j) {
773             hess[i * fDim + j] = 0;
774          }
775       } else {
776          unsigned int l = fState.IntOfExt(i);
777          for (unsigned int j = 0; j < fDim; ++j) {
778             // could probably speed up this loop (if needed)
779             int k = i * fDim + j;
780             if (fState.Parameter(j).IsFixed() || fState.Parameter(j).IsConst())
781                hess[k] = 0;
782             else {
783                // need to transform from external to internal indices)
784                // for taking care of the removed fixed row/columns in the Minuit2 representation
785                unsigned int m = fState.IntOfExt(j);
786                hess[k] = fState.Hessian()(l, m);
787             }
788          }
789       }
790    }
791 
792    return true;
793 }
794 
Correlation(unsigned int i,unsigned int j) const795 double Minuit2Minimizer::Correlation(unsigned int i, unsigned int j) const
796 {
797    // get correlation between parameter i and j
798    if (i >= fDim || j >= fDim)
799       return 0;
800    if (!fState.HasCovariance())
801       return 0; // no info available when minimization has failed
802    if (fState.Parameter(i).IsFixed() || fState.Parameter(i).IsConst())
803       return 0;
804    if (fState.Parameter(j).IsFixed() || fState.Parameter(j).IsConst())
805       return 0;
806    unsigned int k = fState.IntOfExt(i);
807    unsigned int l = fState.IntOfExt(j);
808    double cij = fState.IntCovariance()(k, l);
809    double tmp = std::sqrt(std::abs(fState.IntCovariance()(k, k) * fState.IntCovariance()(l, l)));
810    if (tmp > 0)
811       return cij / tmp;
812    return 0;
813 }
814 
GlobalCC(unsigned int i) const815 double Minuit2Minimizer::GlobalCC(unsigned int i) const
816 {
817    // get global correlation coefficient for the parameter i. This is a number between zero and one which gives
818    // the correlation between the i-th parameter  and that linear combination of all other parameters which
819    // is most strongly correlated with i.
820 
821    if (i >= fDim)
822       return 0;
823    // no info available when minimization has failed or has some problems
824    if (!fState.HasGlobalCC())
825       return 0;
826    if (fState.Parameter(i).IsFixed() || fState.Parameter(i).IsConst())
827       return 0;
828    unsigned int k = fState.IntOfExt(i);
829    return fState.GlobalCC().GlobalCC()[k];
830 }
831 
GetMinosError(unsigned int i,double & errLow,double & errUp,int runopt)832 bool Minuit2Minimizer::GetMinosError(unsigned int i, double &errLow, double &errUp, int runopt)
833 {
834    // return the minos error for parameter i
835    // if a minimum does not exist an error is returned
836    // runopt is a flag which specifies if only lower or upper error needs to be run
837    // if runopt = 0 both, = 1 only lower, + 2 only upper errors
838    errLow = 0;
839    errUp = 0;
840 
841    assert(fMinuitFCN);
842 
843    // need to know if parameter is const or fixed
844    if (fState.Parameter(i).IsConst() || fState.Parameter(i).IsFixed()) {
845       return false;
846    }
847 
848    MnPrint print("Minuit2Minimizer::GetMinosError", PrintLevel());
849 
850    // to run minos I need function minimum class
851    // redo minimization from current state
852    //    ROOT::Minuit2::FunctionMinimum min =
853    //       GetMinimizer()->Minimize(*GetFCN(),fState, ROOT::Minuit2::MnStrategy(strategy), MaxFunctionCalls(),
854    //       Tolerance());
855    //    fState = min.UserState();
856    if (fMinimum == 0) {
857       print.Error("Failed - no function minimum existing");
858       return false;
859    }
860 
861    if (!fMinimum->IsValid()) {
862       print.Error("Failed - invalid function minimum");
863       return false;
864    }
865 
866    fMinuitFCN->SetErrorDef(ErrorDef());
867    // if error def has been changed update it in FunctionMinimum
868    if (ErrorDef() != fMinimum->Up())
869       fMinimum->SetErrorDef(ErrorDef());
870 
871    int mstatus = RunMinosError(i, errLow, errUp, runopt);
872 
873    // run again the Minimization in case of a new minimum
874    // bit 8 is set
875    if ((mstatus & 8) != 0) {
876       print.Info([&](std::ostream &os) {
877          os << "Found a new minimum: run again the Minimization starting from the new point";
878          os << "\nFVAL  = " << fState.Fval();
879          for (auto &par : fState.MinuitParameters()) {
880             os << '\n' << par.Name() << "\t  = " << par.Value();
881          }
882       });
883       // release parameter that was fixed in the returned state from Minos
884       ReleaseVariable(i);
885       bool ok = Minimize();
886       if (!ok)
887          return false;
888       // run again Minos from new Minimum (also lower error needs to be re-computed)
889       print.Info("Run now again Minos from the new found Minimum");
890       mstatus = RunMinosError(i, errLow, errUp, runopt);
891 
892       // do not reset new minimum bit to flag for other parameters
893       mstatus |= 8;
894    }
895 
896    fStatus += 10 * mstatus;
897    fMinosStatus = mstatus;
898 
899    bool isValid = ((mstatus & 1) == 0) && ((mstatus & 2) == 0);
900    return isValid;
901 }
902 
RunMinosError(unsigned int i,double & errLow,double & errUp,int runopt)903 int Minuit2Minimizer::RunMinosError(unsigned int i, double &errLow, double &errUp, int runopt)
904 {
905 
906    bool runLower = runopt != 2;
907    bool runUpper = runopt != 1;
908 
909    const int debugLevel = PrintLevel();
910    // switch off Minuit2 printing
911    const int prev_level = (debugLevel <= 0) ? TurnOffPrintInfoLevel() : -2;
912    const int prevGlobalLevel = MnPrint::SetGlobalLevel(debugLevel);
913 
914    // set the precision if needed
915    if (Precision() > 0)
916       fState.SetPrecision(Precision());
917 
918    ROOT::Minuit2::MnMinos minos(*fMinuitFCN, *fMinimum);
919 
920    // run MnCross
921    MnCross low;
922    MnCross up;
923    int maxfcn = MaxFunctionCalls();
924    double tol = Tolerance();
925 
926    const char *par_name = fState.Name(i);
927 
928    // now input tolerance for migrad calls inside Minos (MnFunctionCross)
929    // before it was fixed to 0.05
930    // cut off too small tolerance (they are not needed)
931    tol = std::max(tol, 0.01);
932 
933    // get the real number of maxfcn used (defined in MnMinos) to be printed
934    int maxfcn_used = maxfcn;
935    if (maxfcn_used == 0) {
936       int nvar = fState.VariableParameters();
937       maxfcn_used = 2 * (nvar + 1) * (200 + 100 * nvar + 5 * nvar * nvar);
938    }
939 
940    if (runLower) {
941       if (debugLevel >= 1) {
942          std::cout << "************************************************************************************************"
943                       "******\n";
944          std::cout << "Minuit2Minimizer::GetMinosError - Run MINOS LOWER error for parameter #" << i << " : "
945                    << par_name << " using max-calls " << maxfcn_used << ", tolerance " << tol << std::endl;
946       }
947       low = minos.Loval(i, maxfcn, tol);
948    }
949    if (runUpper) {
950       if (debugLevel >= 1) {
951          std::cout << "************************************************************************************************"
952                       "******\n";
953          std::cout << "Minuit2Minimizer::GetMinosError - Run MINOS UPPER error for parameter #" << i << " : "
954                    << par_name << " using max-calls " << maxfcn_used << ", tolerance " << tol << std::endl;
955       }
956       up = minos.Upval(i, maxfcn, tol);
957    }
958 
959    ROOT::Minuit2::MinosError me(i, fMinimum->UserState().Value(i), low, up);
960 
961    // restore global print level
962    if (prev_level > -2)
963       RestoreGlobalPrintLevel(prev_level);
964    MnPrint::SetGlobalLevel(prevGlobalLevel);
965 
966    // debug result of Minos
967    // print error message in Minos
968    // Note that the only invalid condition can happen when the (npar-1) minimization fails
969    // The error is also invalid when the maximum number of calls is reached or a new function minimum is found
970    // in case of the parameter at the limit the error is not invalid.
971    // When the error is invalid the returned error is the Hessian error.
972 
973    if (debugLevel > 0) {
974       if (runLower) {
975          if (!me.LowerValid())
976             std::cout << "Minos:  Invalid lower error for parameter " << par_name << std::endl;
977          if (me.AtLowerLimit())
978             std::cout << "Minos:  Parameter : " << par_name << "  is at Lower limit; error is " << me.Lower()
979                       << std::endl;
980          if (me.AtLowerMaxFcn())
981             std::cout << "Minos:  Maximum number of function calls exceeded when running for lower error for parameter "
982                       << par_name << std::endl;
983          if (me.LowerNewMin())
984             std::cout << "Minos:  New Minimum found while running Minos for lower error for parameter " << par_name
985                       << std::endl;
986 
987          if (debugLevel >= 1 && me.LowerValid())
988             std::cout << "Minos: Lower error for parameter " << par_name << "  :  " << me.Lower() << std::endl;
989       }
990       if (runUpper) {
991          if (!me.UpperValid())
992             std::cout << "Minos:  Invalid upper error for parameter " << par_name << std::endl;
993          if (me.AtUpperLimit())
994             std::cout << "Minos:  Parameter " << par_name << " is at Upper limit; error is " << me.Upper() << std::endl;
995          if (me.AtUpperMaxFcn())
996             std::cout << "Minos:  Maximum number of function calls exceeded when running for upper error for parameter "
997                       << par_name << std::endl;
998          if (me.UpperNewMin())
999             std::cout << "Minos:  New Minimum found while running Minos for upper error for parameter " << par_name
1000                       << std::endl;
1001 
1002          if (debugLevel >= 1 && me.UpperValid())
1003             std::cout << "Minos: Upper error for parameter " << par_name << "  :  " << me.Upper() << std::endl;
1004       }
1005    }
1006 
1007    MnPrint print("RunMinosError", PrintLevel());
1008    bool lowerInvalid = (runLower && !me.LowerValid());
1009    bool upperInvalid = (runUpper && !me.UpperValid());
1010    // print message in case of invalid error also in printLevel0
1011    if (lowerInvalid) {
1012       print.Warn("Invalid lower error for parameter", fMinimum->UserState().Name(i));
1013    }
1014    if (upperInvalid) {
1015       print.Warn("Invalid upper error for parameter", fMinimum->UserState().Name(i));
1016    }
1017    // print also case it is lower/upper limit
1018    if (me.AtLowerLimit()) {
1019       print.Warn("Lower error for parameter", fMinimum->UserState().Name(i), "is at the Lower limit!");
1020    }
1021    if (me.AtUpperLimit()) {
1022       print.Warn("Upper error for parameter", fMinimum->UserState().Name(i), "is at the Upper limit!");
1023    }
1024 
1025    int mstatus = 0;
1026    if (lowerInvalid || upperInvalid) {
1027       // set status accroding to bit
1028       // bit 1:  lower invalid Minos errors
1029       // bit 2:  upper invalid Minos error
1030       // bit 3:   invalid because max FCN
1031       // bit 4 : invalid because a new minimum has been found
1032       if (lowerInvalid) {
1033          mstatus |= 1;
1034          if (me.AtLowerMaxFcn())
1035             mstatus |= 4;
1036          if (me.LowerNewMin())
1037             mstatus |= 8;
1038       }
1039       if (upperInvalid) {
1040          mstatus |= 2;
1041          if (me.AtUpperMaxFcn())
1042             mstatus |= 4;
1043          if (me.UpperNewMin())
1044             mstatus |= 8;
1045       }
1046    }
1047    // case upper/lower limit
1048    if (me.AtUpperLimit() || me.AtLowerLimit())
1049       mstatus |= 16;
1050 
1051    if (runLower)
1052       errLow = me.Lower();
1053    if (runUpper)
1054       errUp = me.Upper();
1055 
1056    // in case of new minimum found update also the  minimum state
1057    if ((runLower && me.LowerNewMin()) && (runUpper && me.UpperNewMin())) {
1058       // take state with lower function value
1059       fState = (low.State().Fval() < up.State().Fval()) ? low.State() : up.State();
1060    } else if (runLower && me.LowerNewMin()) {
1061       fState = low.State();
1062    } else if (runUpper && me.UpperNewMin()) {
1063       fState = up.State();
1064    }
1065 
1066    return mstatus;
1067 }
1068 
Scan(unsigned int ipar,unsigned int & nstep,double * x,double * y,double xmin,double xmax)1069 bool Minuit2Minimizer::Scan(unsigned int ipar, unsigned int &nstep, double *x, double *y, double xmin, double xmax)
1070 {
1071    // scan a parameter (variable) around the minimum value
1072    // the parameters must have been set before
1073    // if xmin=0 && xmax == 0  by default scan around 2 sigma of the error
1074    // if the errors  are also zero then scan from min and max of parameter range
1075 
1076    MnPrint print("Minuit2Minimizer::Scan", PrintLevel());
1077    if (!fMinuitFCN) {
1078       print.Error("Function must be set before using Scan");
1079       return false;
1080    }
1081 
1082    if (ipar > fState.MinuitParameters().size()) {
1083       print.Error("Invalid number; minimizer variables must be set before using Scan");
1084       return false;
1085    }
1086 
1087    // switch off Minuit2 printing
1088    const int prev_level = (PrintLevel() <= 0) ? TurnOffPrintInfoLevel() : -2;
1089    const int prevGlobalLevel = MnPrint::SetGlobalLevel(PrintLevel());
1090 
1091    // set the precision if needed
1092    if (Precision() > 0)
1093       fState.SetPrecision(Precision());
1094 
1095    MnParameterScan scan(*fMinuitFCN, fState.Parameters());
1096    double amin = scan.Fval(); // fcn value of the function before scan
1097 
1098    // first value is param value
1099    std::vector<std::pair<double, double>> result = scan(ipar, nstep - 1, xmin, xmax);
1100 
1101    // restore global print level
1102    if (prev_level > -2)
1103       RestoreGlobalPrintLevel(prev_level);
1104    MnPrint::SetGlobalLevel(prevGlobalLevel);
1105 
1106    if (result.size() != nstep) {
1107       print.Error("Invalid result from MnParameterScan");
1108       return false;
1109    }
1110    // sort also the returned points in x
1111    std::sort(result.begin(), result.end());
1112 
1113    for (unsigned int i = 0; i < nstep; ++i) {
1114       x[i] = result[i].first;
1115       y[i] = result[i].second;
1116    }
1117 
1118    // what to do if a new minimum has been found ?
1119    // use that as new minimum
1120    if (scan.Fval() < amin) {
1121       print.Info("A new minimum has been found");
1122       fState.SetValue(ipar, scan.Parameters().Value(ipar));
1123    }
1124 
1125    return true;
1126 }
1127 
Contour(unsigned int ipar,unsigned int jpar,unsigned int & npoints,double * x,double * y)1128 bool Minuit2Minimizer::Contour(unsigned int ipar, unsigned int jpar, unsigned int &npoints, double *x, double *y)
1129 {
1130    // contour plot for parameter i and j
1131    // need a valid FunctionMinimum otherwise exits
1132 
1133    MnPrint print("Minuit2Minimizer::Contour", PrintLevel());
1134 
1135    if (fMinimum == 0) {
1136       print.Error("No function minimum existing; must minimize function before");
1137       return false;
1138    }
1139 
1140    if (!fMinimum->IsValid()) {
1141       print.Error("Invalid function minimum");
1142       return false;
1143    }
1144    assert(fMinuitFCN);
1145 
1146    fMinuitFCN->SetErrorDef(ErrorDef());
1147    // if error def has been changed update it in FunctionMinimum
1148    if (ErrorDef() != fMinimum->Up()) {
1149       fMinimum->SetErrorDef(ErrorDef());
1150    }
1151 
1152    print.Info("Computing contours -", ErrorDef());
1153 
1154    // switch off Minuit2 printing (for level of  0,1)
1155    const int prev_level = (PrintLevel() <= 1) ? TurnOffPrintInfoLevel() : -2;
1156    const int prevGlobalLevel = MnPrint::SetGlobalLevel(PrintLevel() - 1);
1157 
1158    // set the precision if needed
1159    if (Precision() > 0)
1160       fState.SetPrecision(Precision());
1161 
1162    // eventually one should specify tolerance in contours
1163    MnContours contour(*fMinuitFCN, *fMinimum, Strategy());
1164 
1165    // restore global print level
1166    if (prev_level > -2)
1167       RestoreGlobalPrintLevel(prev_level);
1168    MnPrint::SetGlobalLevel(prevGlobalLevel);
1169 
1170    // compute the contour
1171    std::vector<std::pair<double, double>> result = contour(ipar, jpar, npoints);
1172    if (result.size() != npoints) {
1173       print.Error("Invalid result from MnContours");
1174       return false;
1175    }
1176    for (unsigned int i = 0; i < npoints; ++i) {
1177       x[i] = result[i].first;
1178       y[i] = result[i].second;
1179    }
1180 
1181    return true;
1182 }
1183 
Hesse()1184 bool Minuit2Minimizer::Hesse()
1185 {
1186    // find Hessian (full second derivative calculations)
1187    // the contained state will be updated with the Hessian result
1188    // in case a function minimum exists and is valid the result will be
1189    // appended in the function minimum
1190 
1191    MnPrint print("Minuit2Minimizer::Hesse", PrintLevel());
1192 
1193    if (!fMinuitFCN) {
1194       print.Error("FCN function has not been set");
1195       return false;
1196    }
1197 
1198    const int strategy = Strategy();
1199    const int maxfcn = MaxFunctionCalls();
1200    print.Info("Using max-calls", maxfcn);
1201 
1202    // switch off Minuit2 printing
1203    const int prev_level = (PrintLevel() <= 0) ? TurnOffPrintInfoLevel() : -2;
1204    const int prevGlobalLevel = MnPrint::SetGlobalLevel(PrintLevel());
1205 
1206    // set the precision if needed
1207    if (Precision() > 0)
1208       fState.SetPrecision(Precision());
1209 
1210    ROOT::Minuit2::MnHesse hesse(strategy);
1211 
1212    // case when function minimum exists
1213    if (fMinimum) {
1214 
1215       // if (PrintLevel() >= 3) {
1216       //    std::cout << "Minuit2Minimizer::Hesse  - State before running Hesse " << std::endl;
1217       //    std::cout << fState << std::endl;
1218       // }
1219 
1220       // run hesse and function minimum will be updated with Hesse result
1221       hesse(*fMinuitFCN, *fMinimum, maxfcn);
1222       // update user state
1223       fState = fMinimum->UserState();
1224    }
1225 
1226    else {
1227       // run Hesse on point stored in current state (independent of function minimum validity)
1228       // (x == 0)
1229       fState = hesse(*fMinuitFCN, fState, maxfcn);
1230    }
1231 
1232    // restore global print level
1233    if (prev_level > -2)
1234       RestoreGlobalPrintLevel(prev_level);
1235    MnPrint::SetGlobalLevel(prevGlobalLevel);
1236 
1237    if (PrintLevel() >= 3) {
1238       std::cout << "Minuit2Minimizer::Hesse  - State returned from Hesse " << std::endl;
1239       std::cout << fState << std::endl;
1240    }
1241 
1242    int covStatus = fState.CovarianceStatus();
1243    std::string covStatusType = "not valid";
1244    if (covStatus == 1)
1245       covStatusType = "approximate";
1246    if (covStatus == 2)
1247       covStatusType = "full but made positive defined";
1248    if (covStatus == 3)
1249       covStatusType = "accurate";
1250 
1251    if (!fState.HasCovariance()) {
1252       // if false means error is not valid and this is due to a failure in Hesse
1253       // update minimizer error status
1254       int hstatus = 4;
1255       // information on error state can be retrieved only if fMinimum is available
1256       if (fMinimum) {
1257          if (fMinimum->Error().HesseFailed())
1258             hstatus = 1;
1259          if (fMinimum->Error().InvertFailed())
1260             hstatus = 2;
1261          else if (!(fMinimum->Error().IsPosDef()))
1262             hstatus = 3;
1263       }
1264 
1265       print.Warn("Hesse failed - matrix is", covStatusType);
1266       print.Warn(hstatus);
1267 
1268       fStatus += 100 * hstatus;
1269       return false;
1270    }
1271 
1272    print.Info("Hesse is valid - matrix is", covStatusType);
1273 
1274    return true;
1275 }
1276 
CovMatrixStatus() const1277 int Minuit2Minimizer::CovMatrixStatus() const
1278 {
1279    // return status of covariance matrix
1280    //-1 - not available (inversion failed or Hesse failed)
1281    // 0 - available but not positive defined
1282    // 1 - covariance only approximate
1283    // 2 full matrix but forced pos def
1284    // 3 full accurate matrix
1285 
1286    if (fMinimum) {
1287       // case a function minimum  is available
1288       if (fMinimum->HasAccurateCovar())
1289          return 3;
1290       else if (fMinimum->HasMadePosDefCovar())
1291          return 2;
1292       else if (fMinimum->HasValidCovariance())
1293          return 1;
1294       else if (fMinimum->HasCovariance())
1295          return 0;
1296       return -1;
1297    } else {
1298       // case fMinimum is not available - use state information
1299       return fState.CovarianceStatus();
1300    }
1301    return 0;
1302 }
1303 
SetTraceObject(MnTraceObject & obj)1304 void Minuit2Minimizer::SetTraceObject(MnTraceObject &obj)
1305 {
1306    // set trace object
1307    if (!fMinimizer)
1308       return;
1309    fMinimizer->Builder().SetTraceObject(obj);
1310 }
1311 
SetStorageLevel(int level)1312 void Minuit2Minimizer::SetStorageLevel(int level)
1313 {
1314    // set storage level
1315    if (!fMinimizer)
1316       return;
1317    fMinimizer->Builder().SetStorageLevel(level);
1318 }
1319 
1320 } // end namespace Minuit2
1321 
1322 } // end namespace ROOT
1323