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> ¶msObj = 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> ¶msObj = 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