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"
49 using namespace ROOT::Minuit2;
55 int prevErrorIgnoreLevel = gErrorIgnoreLevel;
56 if (prevErrorIgnoreLevel < 1001) {
57 gErrorIgnoreLevel = 1001;
58 return prevErrorIgnoreLevel;
72 : Minimizer(), fDim(0), fMinimizer(nullptr), fMinuitFCN(nullptr), fMinimum(nullptr) {
78 : Minimizer(), fDim(0), fMinimizer(nullptr), fMinuitFCN(nullptr), fMinimum(nullptr) {
83 std::transform(algoname.begin(), algoname.end(), algoname.begin(), (int (*)(int))tolower);
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);
176 fState.Add(name, val, step);
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);
202 fState.SetUpperLimit(ivar, upper);
211 fState.SetLimits(ivar, lower, upper);
221 ivar =
fState.Index(name);
229 if (ivar >=
fState.MinuitParameters().size())
231 return fState.GetName(ivar);
237 return fState.Trafo().FindIndex(name);
242 if (ivar >=
fState.MinuitParameters().size())
244 fState.SetValue(ivar, val);
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);
409 if (debugLevel >= 3) {
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();
451 if (fStatus != 0 && debugLevel > 0)
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) {
562 cov[
i * fDim +
j] = 0;
565 unsigned int l =
fState.IntOfExt(
i);
566 for (
unsigned int j = 0;
j <
fDim; ++
j) {
568 int k =
i * fDim +
j;
569 if (
fState.Parameter(j).IsFixed() ||
fState.Parameter(j).IsConst())
574 unsigned int m =
fState.IntOfExt(j);
586 if (!
fState.HasCovariance())
588 for (
unsigned int i = 0;
i <
fDim; ++
i) {
589 if (
fState.Parameter(
i).IsFixed() ||
fState.Parameter(
i).IsConst()) {
590 for (
unsigned int j = 0;
j <
fDim; ++
j) {
591 hess[
i * fDim +
j] = 0;
594 unsigned int l =
fState.IntOfExt(
i);
595 for (
unsigned int j = 0;
j <
fDim; ++
j) {
597 int k =
i * 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);
729 ROOT::Minuit2::MinosError
me(i,
fMinimum->UserState().Value(i), low,
up);
737 if (debugLevel >= 1) {
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";
840 std::sort(result.begin(), result.end());
842 for (
unsigned int i = 0;
i < nstep; ++
i) {
843 x[
i] = result[
i].first;
844 y[
i] = result[
i].second;
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());
892 std::vector<std::pair<double, double> >
result = contour(ipar, jpar, npoints);
893 if (result.size() !=
npoints) {
894 edm::LogError(
"HybridMinimizer::Contour") <<
" Invalid result from MnContours";
898 x[
i] = result[
i].first;
899 y[
i] = result[
i].second;
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();
bool SetVariable(unsigned int ivar, const std::string &name, double val, double step) override
set free variable
const bool isValid(const Frame &aFrame, const FrameQuality &aQuality, const uint16_t aExpectedPos)
bool Contour(unsigned int i, unsigned int j, unsigned int &npoints, double *xi, double *xj) override
ROOT::Minuit2::MnUserParameterState fState
ROOT::Minuit2::FCNBase * fMinuitFCN
ROOT::Minuit2::FunctionMinimum * fMinimum
HybridMinimizer(EMinimizerType type=kMigrad)
uint32_t T const *__restrict__ uint32_t const *__restrict__ int32_t int Histo::index_type cudaStream_t Func __host__ __device__ V int Func func
Log< level::Error, false > LogError
void SetFunction(const ROOT::Math::IMultiGenFunction &func) override
set the function to minimize
bool SetVariableValue(unsigned int ivar, double val) override
set variable
bool SetLowerLimitedVariable(unsigned int ivar, const std::string &name, double val, double step, double lower) override
set lower limit variable (override if minimizer supports them )
void SetMinimizerType(EMinimizerType type)
bool GetMinosError(unsigned int i, double &errLow, double &errUp, int=0) override
std::vector< double > fErrors
const double * Errors() const override
return errors at the minimum
bool SetFixedVariable(unsigned int, const std::string &, double) override
set fixed variable (override if minimizer supports them )
bool ExamineMinimum(const ROOT::Minuit2::FunctionMinimum &min)
examine the minimum result
bool GetCovMatrix(double *cov) const override
~HybridMinimizer() override
virtual void SetMinimizer(ROOT::Minuit2::ModularFunctionMinimizer *m)
Abs< T >::type abs(const T &t)
double GlobalCC(unsigned int i) const override
bool GetHessianMatrix(double *h) const override
bool SetVariableValues(const double *val) override
double Correlation(unsigned int i, unsigned int j) const override
std::string VariableName(unsigned int ivar) const override
get name of variables (override if minimizer support storing of variable names)
HybridMinimizer & operator=(const HybridMinimizer &rhs)
int TurnOffPrintInfoLevel()
Log< level::Info, false > LogInfo
int CovMatrixStatus() const override
int VariableIndex(const std::string &name) const override
std::vector< double > fValues
void RestoreGlobalPrintLevel(int)
ROOT::Minuit2::ModularFunctionMinimizer * fMinimizer
bool SetLimitedVariable(unsigned int ivar, const std::string &name, double val, double step, double, double) override
set upper/lower limited variable (override if minimizer supports them )
virtual const ROOT::Minuit2::ModularFunctionMinimizer * GetMinimizer() const
double CovMatrix(unsigned int i, unsigned int j) const override
const double * X() const override
return pointer to X values at the minimum
void PrintResults() override
print result of minimization
virtual const ROOT::Minuit2::FCNBase * GetFCN() const
bool Scan(unsigned int i, unsigned int &nstep, double *x, double *y, double xmin=0, double xmax=0) override
bool SetUpperLimitedVariable(unsigned int ivar, const std::string &name, double val, double step, double upper) override
set upper limit variable (override if minimizer supports them )