mirror of
https://github.com/aportelli/LatAnalyze.git
synced 2024-11-10 00:45:36 +00:00
simplification of the Minuit minimiser interface, (successful) test of the new fit interface
This commit is contained in:
parent
ee8ed05b81
commit
9b9c86cf72
@ -1,6 +1,7 @@
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
#include <LatAnalyze/CompiledModel.hpp>
|
||||
#include <LatAnalyze/Io.hpp>
|
||||
#include <LatAnalyze/MinuitMinimizer.hpp>
|
||||
#include <LatAnalyze/RandGen.hpp>
|
||||
#include <LatAnalyze/XYStatData.hpp>
|
||||
@ -8,39 +9,50 @@
|
||||
using namespace std;
|
||||
using namespace Latan;
|
||||
|
||||
const Index nPoint = 30;
|
||||
const double xErr = .2, yErr = .1;
|
||||
const double exactPar[2] = {0.5,5.0}, dx = 10.0/static_cast<double>(nPoint);
|
||||
const Index nPoint1 = 5, nPoint2 = 5;
|
||||
const double xErr = .1, yErr = .1;
|
||||
const double exactPar[2] = {0.5,5.};
|
||||
const double dx1 = 10.0/static_cast<double>(nPoint1);
|
||||
const double dx2 = 5.0/static_cast<double>(nPoint2);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// generate fake data
|
||||
XYStatData data;
|
||||
RandGen rg;
|
||||
double x1_k, x2_k;
|
||||
double xBuf[2];
|
||||
DoubleModel f([](const double *x, const double *p)
|
||||
{return p[1]*exp(-x[0]*p[0]);}, 1, 2);
|
||||
{return p[1]*exp(-x[0]*p[0])+x[1];}, 2, 2);
|
||||
|
||||
data.addXDim("x", nPoint);
|
||||
data.addXDim("x", nPoint1);
|
||||
data.addXDim("off", nPoint2);
|
||||
data.addYDim("y");
|
||||
for (Index k = 0; k < nPoint; ++k)
|
||||
for (Index i1 = 0; i1 < nPoint1; ++i1)
|
||||
{
|
||||
x1_k = rg.gaussian(k*dx, xErr);
|
||||
x2_k = rg.gaussian(k*dx, xErr);
|
||||
data.x(k) = x1_k;
|
||||
data.y(k) = rg.gaussian(f(&x2_k, exactPar), yErr);
|
||||
printf("% 8e % 8e % 8e % 8e\n", data.x(k), data.y(k), xErr, yErr);
|
||||
xBuf[0] = i1*dx1;
|
||||
data.x(i1, 0) = rg.gaussian(xBuf[0], xErr);
|
||||
for (Index i2 = 0; i2 < nPoint2; ++i2)
|
||||
{
|
||||
xBuf[1] = i2*dx2;
|
||||
data.x(i2, 1) = xBuf[1];
|
||||
data.y(data.dataIndex(i1, i2)) = rg.gaussian(f(xBuf, exactPar),
|
||||
yErr);
|
||||
printf("% 8e % 8e % 8e % 8e % 8e\n", data.x(i1, 0), xErr,
|
||||
data.x(i2, 1), data.y(i1), yErr);
|
||||
}
|
||||
}
|
||||
cout << endl;
|
||||
data.setXError(0, DVec::Constant(nPoint, xErr));
|
||||
data.setYError(0, DVec::Constant(nPoint, yErr));
|
||||
data.setXError(0, DVec::Constant(data.getXSize(0), xErr));
|
||||
data.assumeXExact(true, 1);
|
||||
data.setYError(0, DVec::Constant(data.getYSize(), yErr));
|
||||
cout << data << endl;
|
||||
|
||||
// fit
|
||||
DVec init = DVec::Constant(2, 0.5);
|
||||
DVec init = DVec::Constant(2, 0.1);
|
||||
FitResult p;
|
||||
MinuitMinimizer minimizer;
|
||||
|
||||
minimizer.setVerbosity(Minimizer::Verbosity::Normal);
|
||||
p = data.fit(minimizer, init, f);
|
||||
cout << "a= " << p(0) << " b= " << p(1) << endl;
|
||||
cout << "chi^2/ndof= " << p.getChi2PerDof() << endl;
|
||||
|
@ -8,41 +8,49 @@
|
||||
using namespace std;
|
||||
using namespace Latan;
|
||||
|
||||
const Index nPoint = 30;
|
||||
const Index nPoint1 = 10, nPoint2 = 10;
|
||||
const Index nSample = 1000;
|
||||
const double xErr = .2, yErr = .1;
|
||||
const double exactPar[2] = {0.5,5.0}, dx = 10.0/static_cast<double>(nPoint);
|
||||
const double xErr = .1, yErr = .1;
|
||||
const double exactPar[2] = {0.5,5.};
|
||||
const double dx1 = 10.0/static_cast<double>(nPoint1);
|
||||
const double dx2 = 5.0/static_cast<double>(nPoint2);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// generate fake data
|
||||
DMatSample x(nSample, nPoint, 1), y(nSample, nPoint, 1);
|
||||
XYSampleData data(nSample);
|
||||
RandGen rg;
|
||||
double x1_k, x2_k;
|
||||
DoubleModel f([](const double *t, const double *p)
|
||||
{return p[1]*exp(-t[0]*p[0]);}, 1, 2);
|
||||
RandGen rg;
|
||||
double xBuf[2];
|
||||
DoubleModel f([](const double *x, const double *p)
|
||||
{return p[1]*exp(-x[0]*p[0])+x[1];}, 2, 2);
|
||||
|
||||
data.addXDim("x", nPoint);
|
||||
data.addXDim("x", nPoint1);
|
||||
data.addXDim("off", nPoint2);
|
||||
data.addYDim("y");
|
||||
FOR_STAT_ARRAY(x, s)
|
||||
for (Index s = central; s < nSample; ++s)
|
||||
{
|
||||
for (Index k = 0; k < nPoint; ++k)
|
||||
for (Index i1 = 0; i1 < nPoint1; ++i1)
|
||||
{
|
||||
x1_k = rg.gaussian(k*dx, xErr);
|
||||
x2_k = rg.gaussian(k*dx, xErr);
|
||||
data.x(k)[s] = x1_k;
|
||||
data.y(k)[s] = rg.gaussian(f(&x2_k, exactPar), yErr);
|
||||
xBuf[0] = i1*dx1;
|
||||
data.x(i1, 0)[s] = rg.gaussian(xBuf[0], xErr);
|
||||
for (Index i2 = 0; i2 < nPoint2; ++i2)
|
||||
{
|
||||
xBuf[1] = i2*dx2;
|
||||
data.x(i2, 1)[s] = xBuf[1];
|
||||
data.y(data.dataIndex(i1, i2))[s] =
|
||||
rg.gaussian(f(xBuf, exactPar), yErr);
|
||||
}
|
||||
}
|
||||
}
|
||||
data.assumeXExact(true, 1);
|
||||
cout << data << endl;
|
||||
|
||||
// fit
|
||||
DVec init = DVec::Constant(2, 0.5);
|
||||
DVec init = DVec::Constant(2, 0.1);
|
||||
DMat err;
|
||||
SampleFitResult p;
|
||||
MinuitMinimizer minimizer;
|
||||
|
||||
|
||||
p = data.fit(minimizer, init, f);
|
||||
err = p.variance().cwiseSqrt();
|
||||
cout << "a= " << p[central](0) << " +/- " << err(0) << endl;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MinuitMinimizer.cpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2015 Antonin Portelli
|
||||
* Copyright (C) 2013 - 2016 Antonin Portelli
|
||||
*
|
||||
* 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
|
||||
@ -19,48 +19,18 @@
|
||||
|
||||
#include <LatAnalyze/MinuitMinimizer.hpp>
|
||||
#include <LatAnalyze/includes.hpp>
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wconversion"
|
||||
|
||||
#include <Minuit2/FCNBase.h>
|
||||
#include <Minuit2/FunctionMinimum.h>
|
||||
#include <Minuit2/MnMigrad.h>
|
||||
#include <Minuit2/MnPrint.h>
|
||||
#include <Minuit2/MnPlot.h>
|
||||
#include <Minuit2/MnScan.h>
|
||||
#include <Minuit2/MnSimplex.h>
|
||||
#include <Minuit2/ScanMinimizer.h>
|
||||
#include <Minuit2/SimplexMinimizer.h>
|
||||
#include <Minuit2/VariableMetricMinimizer.h>
|
||||
#include <Minuit2/Minuit2Minimizer.h>
|
||||
#include <Math/Functor.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace ROOT;
|
||||
using namespace Minuit2;
|
||||
using namespace Latan;
|
||||
|
||||
static constexpr double initErr = 0.5;
|
||||
static constexpr double initErr = 0.1;
|
||||
static constexpr unsigned int maxTry = 10u;
|
||||
|
||||
/******************************************************************************
|
||||
* MinuitMinimizer implementation *
|
||||
* MinuitMinimizer implementation *
|
||||
******************************************************************************/
|
||||
// MinuitFunction constructor //////////////////////////////////////////////////
|
||||
MinuitMinimizer::MinuitFunction::MinuitFunction(const DoubleFunction &f)
|
||||
: f_(&f)
|
||||
{}
|
||||
|
||||
// MinuitFunction minuit members ///////////////////////////////////////////////
|
||||
double MinuitMinimizer::MinuitFunction::operator()
|
||||
(const vector<double> &x) const
|
||||
{
|
||||
return (*f_)(x);
|
||||
}
|
||||
|
||||
double MinuitMinimizer::MinuitFunction::Up(void) const
|
||||
{
|
||||
return 1.;
|
||||
}
|
||||
|
||||
// constructors ////////////////////////////////////////////////////////////////
|
||||
MinuitMinimizer::MinuitMinimizer(const Algorithm algorithm)
|
||||
{
|
||||
@ -79,126 +49,135 @@ MinuitMinimizer::Algorithm MinuitMinimizer::getAlgorithm(void) const
|
||||
return algorithm_;
|
||||
}
|
||||
|
||||
double MinuitMinimizer::getPrecision(void) const
|
||||
{
|
||||
LATAN_ERROR(Implementation,
|
||||
"Minuit minimizer precision cannot be accessed");
|
||||
|
||||
return 0.;
|
||||
}
|
||||
|
||||
void MinuitMinimizer::setAlgorithm(const Algorithm algorithm)
|
||||
{
|
||||
algorithm_ = algorithm;
|
||||
}
|
||||
|
||||
void MinuitMinimizer::setPrecision(const double precision __dumb)
|
||||
{
|
||||
LATAN_ERROR(Implementation,
|
||||
"Minuit minimizer precision cannot be accessed");
|
||||
}
|
||||
|
||||
// minimization ////////////////////////////////////////////////////////////////
|
||||
const DVec & MinuitMinimizer::operator()(const DoubleFunction &f)
|
||||
{
|
||||
DVec &x = getState();
|
||||
Verbosity verbosity = getVerbosity();
|
||||
using namespace ROOT;
|
||||
using namespace Minuit2;
|
||||
|
||||
DVec &x = getState();
|
||||
int printLevel;
|
||||
EMinimizerType minuitAlg;
|
||||
unique_ptr<Math::Minimizer> min;
|
||||
|
||||
// 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;
|
||||
}
|
||||
switch (getAlgorithm())
|
||||
{
|
||||
case Algorithm::Migrad:
|
||||
minuitAlg = kMigrad;
|
||||
break;
|
||||
case Algorithm::Simplex:
|
||||
minuitAlg = kSimplex;
|
||||
break;
|
||||
case Algorithm::Combined:
|
||||
minuitAlg = kCombined;
|
||||
break;
|
||||
}
|
||||
|
||||
// resize minimizer state to match function number of arguments
|
||||
if (f.getNArg() != x.size())
|
||||
{
|
||||
resize(f.getNArg());
|
||||
}
|
||||
|
||||
// set parameters
|
||||
MinuitFunction minuitF(f);
|
||||
MnUserParameters parameters;
|
||||
// create and set minimizer
|
||||
min.reset(new Minuit2Minimizer(minuitAlg));
|
||||
min->SetMaxFunctionCalls(getMaxIteration());
|
||||
min->SetTolerance(getPrecision());
|
||||
min->SetPrintLevel(printLevel);
|
||||
|
||||
// set function and variables
|
||||
Math::Functor minuitF(f, x.size());
|
||||
string name;
|
||||
double val, step;
|
||||
|
||||
min->SetFunction(minuitF);
|
||||
for (Index i = 0; i < x.size(); ++i)
|
||||
{
|
||||
parameters.Add("x_" + strFrom(i), x(i), initErr*fabs(x(i)));
|
||||
if (hasLowLimit(i)&&hasHighLimit(i))
|
||||
name = "x_" + strFrom(i);
|
||||
val = x(i);
|
||||
step = (fabs(x(i)) != 0.) ? initErr*fabs(x(i)) : 1.;
|
||||
if (hasHighLimit(i) and !hasLowLimit(i))
|
||||
{
|
||||
parameters.SetLimits(static_cast<unsigned int>(i),
|
||||
getLowLimit(i), getHighLimit(i));
|
||||
min->SetUpperLimitedVariable(i, name, val, step, getHighLimit(i));
|
||||
}
|
||||
else if (hasLowLimit(i))
|
||||
else if (!hasHighLimit(i) and hasLowLimit(i))
|
||||
{
|
||||
parameters.SetLowerLimit(static_cast<unsigned int>(i),
|
||||
getLowLimit(i));
|
||||
min->SetLowerLimitedVariable(i, name, val, step, getLowLimit(i));
|
||||
}
|
||||
else if (hasHighLimit(i))
|
||||
else if (hasHighLimit(i) and hasLowLimit(i))
|
||||
{
|
||||
parameters.SetUpperLimit(static_cast<unsigned int>(i),
|
||||
getHighLimit(i));
|
||||
min->SetLimitedVariable(i, name, val, step, getLowLimit(i),
|
||||
getHighLimit(i));
|
||||
}
|
||||
else
|
||||
{
|
||||
min->SetVariable(i, name, val, step);
|
||||
}
|
||||
}
|
||||
|
||||
// pre-minimization
|
||||
MnMigrad preMinimizer(minuitF, parameters, 1);
|
||||
FunctionMinimum preMin = preMinimizer();
|
||||
// minimize
|
||||
int status;
|
||||
unsigned int n = 0;
|
||||
|
||||
if (verbosity >= Verbosity::Debug)
|
||||
if (getVerbosity() >= Verbosity::Normal)
|
||||
{
|
||||
cout << "-- MINUIT pre-minimization -----------------------------";
|
||||
cout << preMin;
|
||||
cout << "--------------------------------------------------------";
|
||||
cout << endl;
|
||||
cout << "========== Minuit pre-minimization " << endl;
|
||||
}
|
||||
for (unsigned int i = 0; i < x.size(); ++i)
|
||||
min->SetStrategy(0);
|
||||
min->Minimize();
|
||||
do
|
||||
{
|
||||
parameters.SetValue(i, preMin.UserParameters().Value(i));
|
||||
parameters.SetError(i, 2.*preMin.UserParameters().Error(i));
|
||||
}
|
||||
|
||||
// minimization and output
|
||||
unique_ptr<MnApplication> minimizer(nullptr);
|
||||
if (algorithm_ == Algorithm::Migrad)
|
||||
{
|
||||
minimizer.reset(new MnMigrad(minuitF, parameters, 2));
|
||||
}
|
||||
else if (algorithm_ == Algorithm::Simplex)
|
||||
{
|
||||
minimizer.reset(new MnSimplex(minuitF, parameters, 2));
|
||||
}
|
||||
unsigned int iTry = 0;
|
||||
FunctionMinimum min = (*minimizer)();
|
||||
|
||||
while ((!min.IsValid())&&(iTry < maxTry))
|
||||
{
|
||||
min = (*minimizer)();
|
||||
iTry++;
|
||||
}
|
||||
if (!min.IsValid())
|
||||
{
|
||||
LATAN_WARNING("MINUIT library reported that minimization result is not valid");
|
||||
}
|
||||
for (unsigned int i = 0; i < x.size(); ++i)
|
||||
{
|
||||
x(i) = min.UserParameters().Value(i);
|
||||
}
|
||||
if (verbosity >= Verbosity::Normal)
|
||||
{
|
||||
cout << "-- MINUIT minimization ---------------------------------";
|
||||
cout << min;
|
||||
cout << "--------------------------------------------------------";
|
||||
cout << endl;
|
||||
}
|
||||
if (verbosity >= Verbosity::Debug)
|
||||
{
|
||||
vector<pair<double, double>> scanRes;
|
||||
MnPlot plot;
|
||||
MnScan scanner(minuitF, preMin.UserParameters(), 2);
|
||||
|
||||
cout << "-- MINUIT scan -----------------------------------------";
|
||||
cout << endl;
|
||||
for (unsigned int i = 0; i < x.size(); i++)
|
||||
n++;
|
||||
if (getVerbosity() >= Verbosity::Normal)
|
||||
{
|
||||
cout << "Parameter x_" << i << endl;
|
||||
scanRes = scanner.Scan(i);
|
||||
plot(scanRes);
|
||||
cout << "========== Minuit minimization, try #" << n << endl;
|
||||
}
|
||||
cout << "--------------------------------------------------------";
|
||||
cout << endl;
|
||||
min->SetStrategy(2);
|
||||
min->Minimize();
|
||||
status = min->Status();
|
||||
} while (status and (n < maxTry));
|
||||
if (getVerbosity() >= Verbosity::Normal)
|
||||
{
|
||||
cout << "==============================" << endl;
|
||||
}
|
||||
switch (status)
|
||||
{
|
||||
case 1:
|
||||
LATAN_WARNING("invalid minimum: covariance matrix was made positive");
|
||||
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;
|
||||
}
|
||||
|
||||
// save and return result
|
||||
for (Index i = 0; i < x.size(); ++i)
|
||||
{
|
||||
x(i) = min->X()[i];
|
||||
}
|
||||
|
||||
return x;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MinuitMinimizer.hpp, part of LatAnalyze 3
|
||||
*
|
||||
* Copyright (C) 2013 - 2015 Antonin Portelli
|
||||
* Copyright (C) 2013 - 2016 Antonin Portelli
|
||||
*
|
||||
* 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
|
||||
@ -23,52 +23,36 @@
|
||||
#include <LatAnalyze/Global.hpp>
|
||||
#include <LatAnalyze/Function.hpp>
|
||||
#include <LatAnalyze/Minimizer.hpp>
|
||||
#include <Minuit2/FCNBase.h>
|
||||
|
||||
BEGIN_LATAN_NAMESPACE
|
||||
|
||||
/******************************************************************************
|
||||
* Minuit minimizer *
|
||||
* MinuitMinimizer *
|
||||
******************************************************************************/
|
||||
|
||||
class MinuitMinimizer: public Minimizer
|
||||
{
|
||||
public:
|
||||
enum class Algorithm
|
||||
{
|
||||
Migrad = 1,
|
||||
Simplex = 2
|
||||
};
|
||||
private:
|
||||
class MinuitFunction: public ROOT::Minuit2::FCNBase
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
explicit MinuitFunction(const DoubleFunction &f);
|
||||
// destructor
|
||||
virtual ~MinuitFunction(void) = default;
|
||||
// minuit members
|
||||
virtual double operator()(const std::vector<double> &x) const;
|
||||
virtual double Up(void) const;
|
||||
private:
|
||||
const DoubleFunction *f_;
|
||||
Migrad = 1,
|
||||
Simplex = 2,
|
||||
Combined = 3
|
||||
};
|
||||
public:
|
||||
// constructors
|
||||
MinuitMinimizer(const Algorithm algorithm = Algorithm::Migrad);
|
||||
// constructor
|
||||
MinuitMinimizer(const Algorithm algorithm = defaultAlg_);
|
||||
explicit MinuitMinimizer(const Index dim,
|
||||
const Algorithm algorithm = Algorithm::Migrad);
|
||||
const Algorithm algorithm = defaultAlg_);
|
||||
// destructor
|
||||
virtual ~MinuitMinimizer(void) = default;
|
||||
// access
|
||||
virtual double getPrecision(void) const;
|
||||
Algorithm getAlgorithm(void) const;
|
||||
virtual void setPrecision(const double precision);
|
||||
void setAlgorithm(const Algorithm algorithm);
|
||||
Algorithm getAlgorithm(void) const;
|
||||
void setAlgorithm(const Algorithm algorithm);
|
||||
// minimization
|
||||
virtual const DVec & operator()(const DoubleFunction &f);
|
||||
private:
|
||||
Algorithm algorithm_;
|
||||
Algorithm algorithm_;
|
||||
static constexpr Algorithm defaultAlg_ = Algorithm::Combined;
|
||||
};
|
||||
|
||||
END_LATAN_NAMESPACE
|
||||
|
@ -31,7 +31,7 @@ BEGIN_LATAN_NAMESPACE
|
||||
class Solver
|
||||
{
|
||||
public:
|
||||
static const unsigned int defaultMaxIteration = 1000u;
|
||||
static const unsigned int defaultMaxIteration = 10000u;
|
||||
static constexpr double defaultPrec = 1.0e-7;
|
||||
public:
|
||||
enum class Verbosity
|
||||
|
Loading…
Reference in New Issue
Block a user