1
0
mirror of https://github.com/aportelli/LatAnalyze.git synced 2024-11-10 08:55:37 +00:00
LatAnalyze/lib/Numerical/MinuitMinimizer.cpp

185 lines
5.3 KiB
C++
Raw Normal View History

2014-02-20 20:21:45 +00:00
/*
* MinuitMinimizer.cpp, part of LatAnalyze 3
*
* Copyright (C) 2013 - 2016 Antonin Portelli
2014-02-20 20:21:45 +00:00
*
* LatAnalyze 3 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LatAnalyze 3 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LatAnalyze 3. If not, see <http://www.gnu.org/licenses/>.
*/
#include <LatAnalyze/Numerical/MinuitMinimizer.hpp>
2014-03-13 18:51:01 +00:00
#include <LatAnalyze/includes.hpp>
#include <Minuit2/Minuit2Minimizer.h>
#include <Math/Functor.h>
2014-02-20 20:21:45 +00:00
using namespace std;
using namespace Latan;
2016-04-01 21:39:49 +01:00
static constexpr double initErr = 0.1;
2014-09-18 17:18:51 +01:00
2014-02-20 20:21:45 +00:00
/******************************************************************************
2016-03-23 17:16:50 +00:00
* MinuitMinimizer implementation *
2014-02-20 20:21:45 +00:00
******************************************************************************/
// constructors ////////////////////////////////////////////////////////////////
MinuitMinimizer::MinuitMinimizer(const Algorithm algorithm)
{
setAlgorithm(algorithm);
}
2014-09-22 15:19:30 +01:00
// access //////////////////////////////////////////////////////////////////////
MinuitMinimizer::Algorithm MinuitMinimizer::getAlgorithm(void) const
{
return algorithm_;
}
void MinuitMinimizer::setAlgorithm(const Algorithm algorithm)
{
algorithm_ = algorithm;
}
2016-04-12 20:10:37 +01:00
bool MinuitMinimizer::supportLimits(void) const
{
return true;
}
2014-02-20 20:21:45 +00:00
// minimization ////////////////////////////////////////////////////////////////
const DVec & MinuitMinimizer::operator()(const DoubleFunction &f)
{
using namespace ROOT;
using namespace Minuit2;
2016-04-15 18:23:45 +01:00
DVec &x = getState();
int printLevel = 0;
EMinimizerType minuitAlg = kCombined;
double prec = getPrecision();
// convert Latan parameters to Minuit parameters
switch (getVerbosity())
{
case Verbosity::Silent:
printLevel = 0;
break;
case Verbosity::Normal:
printLevel = 2;
break;
case Verbosity::Debug:
printLevel = 3;
break;
}
2016-04-15 18:23:45 +01:00
// The factor of 0.002 here is to compensate the dirty hack in Minuit
// source used to match the C++ and F77 versions
// (cf. VariableMetricBuilder.cxx)
switch (getAlgorithm())
{
2016-04-12 20:10:37 +01:00
case Algorithm::migrad:
2016-04-15 18:23:45 +01:00
minuitAlg = kMigrad;
prec /= 0.002;
break;
2016-04-12 20:10:37 +01:00
case Algorithm::simplex:
minuitAlg = kSimplex;
break;
2016-04-12 20:10:37 +01:00
case Algorithm::combined:
2016-04-15 18:23:45 +01:00
minuitAlg = kCombined;
prec /= 0.002;
break;
}
2014-02-20 20:21:45 +00:00
// resize minimizer state to match function number of arguments
2014-02-20 20:21:45 +00:00
if (f.getNArg() != x.size())
{
resize(f.getNArg());
2014-02-20 20:21:45 +00:00
}
// create and set minimizer
Minuit2Minimizer min(minuitAlg);
min.SetStrategy(2);
min.SetMaxFunctionCalls(getMaxIteration());
2016-04-15 18:23:45 +01:00
min.SetTolerance(prec);
min.SetPrintLevel(printLevel);
// set function and variables
Math::Functor minuitF(f, x.size());
string name;
double val, step;
2014-02-20 20:21:45 +00:00
min.SetFunction(minuitF);
for (Index i = 0; i < x.size(); ++i)
2014-02-20 20:21:45 +00:00
{
name = f.varName().getName(i);
val = x(i);
step = (fabs(x(i)) != 0.) ? initErr*fabs(x(i)) : 1.;
if (hasHighLimit(i) and !hasLowLimit(i))
{
min.SetUpperLimitedVariable(i, name, val, step, getHighLimit(i));
}
else if (!hasHighLimit(i) and hasLowLimit(i))
{
min.SetLowerLimitedVariable(i, name, val, step, getLowLimit(i));
}
else if (hasHighLimit(i) and hasLowLimit(i))
2014-10-14 16:34:27 +01:00
{
min.SetLimitedVariable(i, name, val, step, getLowLimit(i),
getHighLimit(i));
2014-10-14 16:34:27 +01:00
}
else
2014-10-14 16:34:27 +01:00
{
min.SetVariable(i, name, val, step);
2014-10-14 16:34:27 +01:00
}
2014-02-20 20:21:45 +00:00
}
// minimize
int status;
unsigned int n = 0;
2014-02-20 20:21:45 +00:00
do
{
if (getVerbosity() >= Verbosity::Normal)
{
cout << "========== Minuit minimization, pass #" << n + 1;
2016-04-01 21:39:49 +01:00
cout << " =========" << endl;
}
min.Minimize();
status = min.Status();
2016-04-01 21:39:49 +01:00
n++;
2016-04-15 18:23:45 +01:00
} while ((status >= 2) and (n < getMaxPass()));
if (getVerbosity() >= Verbosity::Normal)
2014-02-20 20:21:45 +00:00
{
2016-04-01 21:39:49 +01:00
cout << "=================================================" << endl;
2014-02-20 20:21:45 +00:00
}
switch (status)
2014-02-20 20:21:45 +00:00
{
case 1:
2016-04-15 18:23:45 +01:00
// covariance matrix was made positive, the minimum is still good
// it just means that Minuit error analysis is inaccurate
break;
case 2:
LATAN_WARNING("invalid minimum: Hesse analysis is not valid");
break;
case 3:
LATAN_WARNING("invalid minimum: requested precision not reached");
break;
case 4:
LATAN_WARNING("invalid minimum: iteration limit reached");
break;
2014-02-20 20:21:45 +00:00
}
// save and return result
for (Index i = 0; i < x.size(); ++i)
2014-02-20 20:21:45 +00:00
{
x(i) = min.X()[i];
2014-02-20 20:21:45 +00:00
}
return x;
}