19 #include "Math/IFunction.h"
20 #include "Math/IOptions.h"
22 #include "Minuit2/FCNAdapter.h"
23 #include "Minuit2/FumiliFCNAdapter.h"
24 #include "Minuit2/FCNGradAdapter.h"
25 #include "Minuit2/FunctionMinimum.h"
26 #include "Minuit2/MnMigrad.h"
27 #include "Minuit2/MnMinos.h"
28 #include "Minuit2/MinosError.h"
29 #include "Minuit2/MnHesse.h"
30 #include "Minuit2/MinuitParameter.h"
31 #include "Minuit2/MnUserFcn.h"
32 #include "Minuit2/MnPrint.h"
33 #include "Minuit2/FunctionMinimum.h"
34 #include "Minuit2/VariableMetricMinimizer.h"
35 #include "Minuit2/SimplexMinimizer.h"
36 #include "Minuit2/CombinedMinimizer.h"
37 #include "Minuit2/ScanMinimizer.h"
38 #include "Minuit2/FumiliMinimizer.h"
39 #include "Minuit2/MnParameterScan.h"
40 #include "Minuit2/MnContours.h"
56 if (prevErrorIgnoreLevel < 1001) {
58 return prevErrorIgnoreLevel;
72 : Minimizer(), fDim(0), fMinimizer(nullptr), fMinuitFCN(nullptr), fMinimum(nullptr) {
77 HybridMinimizer::HybridMinimizer(
const char *
type)
78 : Minimizer(), fDim(0), fMinimizer(nullptr), fMinuitFCN(nullptr), fMinimum(nullptr) {
86 if (algoname ==
"simplex")
88 if (algoname ==
"minimize")
90 if (algoname ==
"scan")
92 if (algoname ==
"fumili")
108 SetMinimizer(
new ROOT::Minuit2::VariableMetricMinimizer());
126 SetMinimizer(
new ROOT::Minuit2::VariableMetricMinimizer());
153 fState = MnUserParameterState();
173 .format(
"Parameter {} has zero or invalid step size - consider it as constant",
name);
178 unsigned int minuit2Index =
fState.Index(
name);
179 if (minuit2Index != ivar) {
180 edm::LogInfo(
"HybridMinimizer::SetVariable").format(
"Wrong index used for the variable {} {}",
name, minuit2Index);
183 fState.RemoveLimits(ivar);
193 fState.SetLowerLimit(ivar, lower);
229 if (ivar >=
fState.MinuitParameters().size())
231 return fState.GetName(ivar);
242 if (ivar >=
fState.MinuitParameters().size())
250 unsigned int n =
fState.MinuitParameters().size();
253 for (
unsigned int ivar = 0; ivar <
n; ++ivar)
254 fState.SetValue(ivar, x[ivar]);
264 fMinuitFCN =
new ROOT::Minuit2::FCNAdapter<ROOT::Math::IMultiGenFunction>(
func, ErrorDef());
267 const ROOT::Math::FitMethodFunction *fcnfunc = dynamic_cast<const ROOT::Math::FitMethodFunction *>(&
func);
269 edm::LogError(
"HybridMinimizer::SetFunction") <<
"HybridMinimizer: Wrong Fit method function for Fumili";
272 fMinuitFCN =
new ROOT::Minuit2::FumiliFCNAdapter<ROOT::Math::FitMethodFunction>(*fcnfunc,
fDim, ErrorDef());
282 fMinuitFCN =
new ROOT::Minuit2::FCNGradAdapter<ROOT::Math::IMultiGradFunction>(
func, ErrorDef());
285 const ROOT::Math::FitMethodGradFunction *fcnfunc = dynamic_cast<const ROOT::Math::FitMethodGradFunction *>(&
func);
287 edm::LogError(
"HybridMinimizer::SetFunction") <<
"HybridMinimizer: Wrong Fit method function for Fumili";
290 fMinuitFCN =
new ROOT::Minuit2::FumiliFCNAdapter<ROOT::Math::FitMethodGradFunction>(*fcnfunc,
fDim, ErrorDef());
298 edm::LogError(
"HybridMinimizer::Minimize") <<
"FCN function has not been set";
309 int maxfcn = MaxFunctionCalls();
311 int strategyLevel = Strategy();
336 fState.SetPrecision(Precision());
339 ROOT::Minuit2::MnStrategy strategy(strategyLevel);
340 ROOT::Math::IOptions *minuit2Opt = ROOT::Math::MinimizerOptions::FindDefault(
"Minuit2");
343 int nGradCycles = strategy.GradientNCycles();
344 int nHessCycles = strategy.HessianNCycles();
345 int nHessGradCycles = strategy.HessianGradientNCycles();
347 double gradTol = strategy.GradientTolerance();
348 double gradStepTol = strategy.GradientStepTolerance();
349 double hessStepTol = strategy.HessianStepTolerance();
350 double hessG2Tol = strategy.HessianG2Tolerance();
352 minuit2Opt->GetValue(
"GradientNCycles", nGradCycles);
353 minuit2Opt->GetValue(
"HessianNCycles", nHessCycles);
354 minuit2Opt->GetValue(
"HessianGradientNCycles", nHessGradCycles);
356 minuit2Opt->GetValue(
"GradientTolerance", gradTol);
357 minuit2Opt->GetValue(
"GradientStepTolerance", gradStepTol);
358 minuit2Opt->GetValue(
"HessianStepTolerance", hessStepTol);
359 minuit2Opt->GetValue(
"HessianG2Tolerance", hessG2Tol);
361 strategy.SetGradientNCycles(nGradCycles);
362 strategy.SetHessianNCycles(nHessCycles);
363 strategy.SetHessianGradientNCycles(nHessGradCycles);
365 strategy.SetGradientTolerance(gradTol);
366 strategy.SetGradientStepTolerance(gradStepTol);
367 strategy.SetHessianStepTolerance(hessStepTol);
368 strategy.SetHessianG2Tolerance(hessStepTol);
370 if (PrintLevel() > 0) {
376 const ROOT::Minuit2::FCNGradientBase *gradFCN = dynamic_cast<const ROOT::Minuit2::FCNGradientBase *>(
fMinuitFCN);
377 if (gradFCN !=
nullptr) {
380 ROOT::Minuit2::FunctionMinimum
min =
GetMinimizer()->Minimize(*gradFCN,
fState, strategy, maxfcn, tol);
381 fMinimum =
new ROOT::Minuit2::FunctionMinimum(
min);
384 fMinimum =
new ROOT::Minuit2::FunctionMinimum(
min);
388 if (
fMinimum->IsValid() && IsValidError() &&
fMinimum->State().Error().Dcovar() != 0) {
390 ROOT::Minuit2::MnHesse hesse(strategy);
431 if (
min.HasMadePosDefCovar()) {
432 txt =
"Covar was made pos def";
435 if (
min.HesseFailed()) {
436 txt =
"Hesse is not valid";
439 if (
min.IsAboveMaxEdm()) {
440 txt =
"Edm is above max";
443 if (
min.HasReachedCallLimit()) {
444 txt =
"Reached call limit";
448 bool validMinimum =
min.IsValid();
457 txt =
"unknown failure";
460 edm::LogInfo(
"HybridMinimizer::Minimize").format(
"Minimization did NOT converge, {}", txt);
504 const std::vector<MinuitParameter> ¶msObj =
fState.MinuitParameters();
505 if (paramsObj.empty())
512 for (
unsigned int i = 0;
i <
fDim; ++
i) {
521 const std::vector<MinuitParameter> ¶msObj =
fState.MinuitParameters();
522 if (paramsObj.empty())
529 for (
unsigned int i = 0;
i <
fDim; ++
i) {
530 const MinuitParameter &par = paramsObj[
i];
531 if (par.IsFixed() || par.IsConst())
544 if (!
fState.HasCovariance())
546 if (
fState.Parameter(
i).IsFixed() ||
fState.Parameter(
i).IsConst())
548 if (
fState.Parameter(
j).IsFixed() ||
fState.Parameter(
j).IsConst())
550 unsigned int k =
fState.IntOfExt(
i);
551 unsigned int l =
fState.IntOfExt(
j);
557 if (!
fState.HasCovariance())
559 for (
unsigned int i = 0;
i <
fDim; ++
i) {
560 if (
fState.Parameter(
i).IsFixed() ||
fState.Parameter(
i).IsConst()) {
561 for (
unsigned int j = 0;
j <
fDim; ++
j) {
565 unsigned int l =
fState.IntOfExt(
i);
566 for (
unsigned int j = 0;
j <
fDim; ++
j) {
569 if (
fState.Parameter(
j).IsFixed() ||
fState.Parameter(
j).IsConst())
574 unsigned int m =
fState.IntOfExt(
j);
588 for (
unsigned int i = 0;
i <
fDim; ++
i) {
589 if (
fState.Parameter(
i).IsFixed() ||
fState.Parameter(
i).IsConst()) {
590 for (
unsigned int j = 0;
j <
fDim; ++
j) {
594 unsigned int l =
fState.IntOfExt(
i);
595 for (
unsigned int j = 0;
j <
fDim; ++
j) {
598 if (
fState.Parameter(
j).IsFixed() ||
fState.Parameter(
j).IsConst())
603 unsigned int m =
fState.IntOfExt(
j);
617 if (!
fState.HasCovariance())
619 if (
fState.Parameter(
i).IsFixed() ||
fState.Parameter(
i).IsConst())
621 if (
fState.Parameter(
j).IsFixed() ||
fState.Parameter(
j).IsConst())
623 unsigned int k =
fState.IntOfExt(
i);
624 unsigned int l =
fState.IntOfExt(
j);
625 double cij =
fState.IntCovariance()(
k,
l);
640 if (!
fState.HasGlobalCC())
642 if (
fState.Parameter(
i).IsFixed() ||
fState.Parameter(
i).IsConst())
644 unsigned int k =
fState.IntOfExt(
i);
645 return fState.GlobalCC().GlobalCC()[
k];
655 bool runLower = runopt != 2;
656 bool runUpper = runopt != 1;
661 if (
fState.Parameter(
i).IsConst() ||
fState.Parameter(
i).IsFixed()) {
675 edm::LogError(
"HybridMinimizer::GetMinosErrors") <<
" failed - no function minimum existing";
680 edm::LogError(
"HybridMinimizer::MINOS") <<
" failed due to invalid function minimum";
694 fState.SetPrecision(Precision());
701 int maxfcn = MaxFunctionCalls();
725 low = minos.Loval(
i, maxfcn, tol);
727 up = minos.Upval(
i, maxfcn, tol);
767 bool lowerInvalid = (runLower && !
me.LowerValid());
768 bool upperInvalid = (runUpper && !
me.UpperValid());
770 if (lowerInvalid || upperInvalid) {
778 if (
me.AtLowerMaxFcn())
780 if (
me.LowerNewMin())
785 if (
me.AtUpperMaxFcn())
787 if (
me.UpperNewMin())
791 fStatus += 10 * mstatus;
797 bool isValid = (runLower &&
me.LowerValid()) || (runUpper &&
me.UpperValid());
808 edm::LogError(
"HybridMinimizer::Scan") <<
" Function must be set before using Scan";
812 if (ipar >
fState.MinuitParameters().size()) {
813 edm::LogError(
"HybridMinimizer::Scan") <<
" Invalid number. Minimizer variables must be set before using Scan";
824 fState.SetPrecision(Precision());
827 double amin = scan.Fval();
830 std::vector<std::pair<double, double> >
result = scan(ipar, nstep - 1,
xmin,
xmax);
835 if (
result.size() != nstep) {
836 edm::LogError(
"HybridMinimizer::Scan") <<
" Invalid result from MnParameterScan";
842 for (
unsigned int i = 0;
i < nstep; ++
i) {
849 if (scan.Fval() < amin) {
850 if (PrintLevel() > 0)
851 edm::LogInfo(
"HybridMinimizer::Scan") <<
"A new minimum has been found";
852 fState.SetValue(ipar, scan.Parameters().Value(ipar));
862 edm::LogError(
"HybridMinimizer::Contour") <<
" no function minimum existing. Must minimize function before";
867 edm::LogError(
"HybridMinimizer::Contour") <<
"Invalid function minimum";
884 fState.SetPrecision(Precision());
894 edm::LogError(
"HybridMinimizer::Contour") <<
" Invalid result from MnContours";
912 edm::LogError(
"HybridMinimizer::Hesse") <<
"FCN function has not been set";
916 int strategy = Strategy();
917 int maxfcn = MaxFunctionCalls();
926 fState.SetPrecision(Precision());
928 ROOT::Minuit2::MnHesse hesse(strategy);
946 if (PrintLevel() >= 3) {
951 if (!
fState.HasCovariance()) {
953 if (PrintLevel() > 0)
954 edm::LogInfo(
"HybridMinimizer::Hesse") <<
"Hesse failed ";
959 if (
fMinimum->Error().HesseFailed())
961 if (
fMinimum->Error().InvertFailed())
963 else if (!(
fMinimum->Error().IsPosDef()))
966 fStatus += 100 * hstatus;
985 else if (
fMinimum->HasMadePosDefCovar())
987 else if (
fMinimum->HasValidCovariance())
994 return fState.CovarianceStatus();