1
0
mirror of https://github.com/aportelli/LatAnalyze.git synced 2025-06-17 06:47:06 +01:00

reintegration of LatCore & folder restructuration

This commit is contained in:
2019-02-10 00:23:36 +00:00
parent 6addec5e14
commit 83d5428c3a
111 changed files with 6974 additions and 315 deletions

View File

@ -0,0 +1,234 @@
/*
* Derivative.cpp, part of LatAnalyze 3
*
* 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
* 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/Derivative.hpp>
#include <LatAnalyze/includes.hpp>
#include <LatAnalyze/Core/Math.hpp>
using namespace std;
using namespace Latan;
using namespace Math;
/******************************************************************************
* Derivative implementation *
******************************************************************************/
// constructor /////////////////////////////////////////////////////////////////
Derivative::Derivative(const DoubleFunction &f, const Index dir,
const double step)
: buffer_(new DVec(f.getNArg()))
{
setFunction(f);
setDir(dir);
setStep(step);
}
Derivative::Derivative(const DoubleFunction &f, const Index dir,
const Index order, const DVec &point, const double step)
: Derivative(f, dir, step)
{
setOrderAndPoint(order, point);
}
// access //////////////////////////////////////////////////////////////////////
Index Derivative::getDir(void) const
{
return dir_;
}
Index Derivative::getOrder(void) const
{
return order_;
}
Index Derivative::getNPoint(void) const
{
return point_.size();
}
double Derivative::getStep(void) const
{
return step_;
}
void Derivative::setDir(const Index dir)
{
dir_ = dir;
}
void Derivative::setFunction(const DoubleFunction &f)
{
f_ = f;
}
void Derivative::setOrderAndPoint(const Index order, const DVec &point)
{
if (order >= point.size())
{
LATAN_ERROR(Size, "derivative order is superior or equal to the number of point");
}
order_ = order;
point_ = point;
coefficient_.resize(point.size());
makeCoefficients();
}
void Derivative::setStep(const double step)
{
step_ = step;
}
// coefficient generation //////////////////////////////////////////////////////
// from B. Fornberg, “Generation of finite difference formulas on arbitrarily
// spaced grids,” Math. Comp., vol. 51, no. 184, pp. 699706, 1988.
// http://dx.doi.org/10.1090/S0025-5718-1988-0935077-0
void Derivative::makeCoefficients(void)
{
double c[3];
const Index N = point_.size() - 1, M = order_;
DMat curr(M + 1, N + 1), prev(M + 1, N + 1);
curr.fill(0.);
prev.fill(0.);
prev(0, 0) = 1.;
c[0] = 1.;
for (Index n = 1; n <= N; ++n)
{
c[1] = 1.;
for (Index nu = 0; nu <= n - 1; ++nu)
{
c[2] = point_(n) - point_(nu);
c[1] *= c[2];
for (Index m = 0; m <= min(n, M); ++m)
{
curr(m, nu) = point_(n)*prev(m, nu);
if (m)
{
curr(m, nu) -= m*prev(m-1, nu);
}
curr(m, nu) /= c[2];
}
}
for (Index m = 0; m <= min(n, M); ++m)
{
curr(m, n) = -point_(n-1)*prev(m, n-1);
if (m)
{
curr(m, n) += m*prev(m-1, n-1);
}
curr(m, n) *= c[0]/c[1];
}
c[0] = c[1];
prev = curr;
}
coefficient_ = curr.row(M);
}
// function call ///////////////////////////////////////////////////////////////
double Derivative::operator()(const double *x) const
{
ConstMap<DVec> xMap(x, f_.getNArg());
double res = 0.;
*buffer_ = xMap;
FOR_VEC(point_, i)
{
(*buffer_)(dir_) = x[dir_] + point_(i)*step_;
res += coefficient_[i]*f_(*buffer_);
}
res /= pow(step_, order_);
return res;
}
// function factory ////////////////////////////////////////////////////////////
DoubleFunction Derivative::makeFunction(const bool makeHardCopy) const
{
DoubleFunction res;
if (makeHardCopy)
{
Derivative copy(*this);
res.setFunction([copy](const double *x){return copy(x);}, f_.getNArg());
}
else
{
res.setFunction([this](const double *x){return (*this)(x);},
f_.getNArg());
}
return res;
}
DoubleFunction Latan::derivative(const DoubleFunction &f, const Index dir,
const Index order, const DVec point,
const double step)
{
return Derivative(f, dir, order, point, step).makeFunction();
}
/******************************************************************************
* CentralDerivative implementation *
******************************************************************************/
// constructor /////////////////////////////////////////////////////////////////
CentralDerivative::CentralDerivative(const DoubleFunction &f, const Index dir,
const Index order, const Index precOrder)
: Derivative(f, dir)
{
setOrder(order, precOrder);
}
// access //////////////////////////////////////////////////////////////////////
Index CentralDerivative::getPrecOrder(void) const
{
return precOrder_;
}
void CentralDerivative::setOrder(const Index order, const Index precOrder)
{
const Index nPoint = 2*(precOrder + (order - 1)/2) + 1;
DVec point(nPoint);
precOrder_ = precOrder;
FOR_VEC(point, i)
{
point(i) = static_cast<double>(i - (nPoint - 1)/2);
}
setOrderAndPoint(order, point);
tuneStep();
}
// step tuning /////////////////////////////////////////////////////////////////
// the rounding error should be O(N*epsilon/h^order)
//
void CentralDerivative::tuneStep(void)
{
const Index nPoint = getNPoint();
const double epsilon = numeric_limits<double>::epsilon();
const double step = pow(epsilon*nPoint, 1./(2.*precOrder_+getOrder()));
setStep(step);
}
// function factory ////////////////////////////////////////////////////////////
DoubleFunction Latan::centralDerivative(const DoubleFunction &f,
const Index dir, const Index order,
const Index precOrder)
{
return CentralDerivative(f, dir, order, precOrder).makeFunction();
}

View File

@ -0,0 +1,103 @@
/*
* Derivative.hpp, part of LatAnalyze 3
*
* 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
* 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/>.
*/
#ifndef Latan_Derivative_hpp_
#define Latan_Derivative_hpp_
#include <LatAnalyze/Global.hpp>
#include <LatAnalyze/Functional/Function.hpp>
BEGIN_LATAN_NAMESPACE
/******************************************************************************
* Derivative *
******************************************************************************/
class Derivative: public DoubleFunctionFactory
{
public:
static constexpr double defaultStep = 1.0e-2;
public:
// constructor
Derivative(const DoubleFunction &f, const Index dir, const Index order,
const DVec &point, const double step = defaultStep);
// destructor
virtual ~Derivative(void) = default;
// access
Index getDir(void) const;
Index getNPoint(void) const;
Index getOrder(void) const;
double getStep(void) const;
void setDir(const Index dir);
void setFunction(const DoubleFunction &f);
void setOrderAndPoint(const Index order, const DVec &point);
void setStep(const double step);
// function call
double operator()(const double *x) const;
// function factory
virtual DoubleFunction makeFunction(const bool makeHardCopy = true) const;
protected:
// constructor
Derivative(const DoubleFunction &f, const Index dir,
const double step = defaultStep);
private:
void makeCoefficients(void);
private:
DoubleFunction f_;
Index dir_, order_;
double step_;
DVec point_, coefficient_;
std::shared_ptr<DVec> buffer_;
};
DoubleFunction derivative(const DoubleFunction &f, const Index dir,
const Index order, const DVec point,
const double step = Derivative::defaultStep);
class CentralDerivative: public Derivative
{
public:
static const Index defaultPrecOrder = 2;
public:
// constructor
CentralDerivative(const DoubleFunction &f = DoubleFunction(),
const Index dir = 0,
const Index order = 1,
const Index precOrder = defaultPrecOrder);
// destructor
virtual ~CentralDerivative(void) = default;
// access
Index getPrecOrder(void) const;
void setOrder(const Index order, const Index precOrder = defaultPrecOrder);
// function call
using Derivative::operator();
private:
// step tuning
void tuneStep(void);
private:
Index precOrder_;
};
DoubleFunction centralDerivative(const DoubleFunction &f, const Index dir = 0,
const Index order = 1,
const Index precOrder =
CentralDerivative::defaultPrecOrder);
END_LATAN_NAMESPACE
#endif // Latan_Derivative_hpp_

53
lib/Numerical/FFT.hpp Normal file
View File

@ -0,0 +1,53 @@
/*
* FFT.hpp, part of LatAnalyze
*
* Copyright (C) 2013 - 2017 Antonin Portelli
*
* LatAnalyze 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 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. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef Latan_FFT_hpp_
#define Latan_FFT_hpp_
#include <LatAnalyze/Global.hpp>
BEGIN_LATAN_NAMESPACE
/******************************************************************************
* FFT abstract class *
******************************************************************************/
class FFT
{
public:
enum
{
Forward = 0,
Backward = 1
};
public:
// constructor
FFT(void) = default;
FFT(const Index size);
// destructor
virtual ~FFT(void) = default;
// size
virtual void resize(const Index size) = 0;
// FFT
virtual void operator()(CMat &x, const unsigned int dir = FFT::Forward) = 0;
};
END_LATAN_NAMESPACE
#endif // Latan_FFT_hpp_

89
lib/Numerical/GslFFT.cpp Normal file
View File

@ -0,0 +1,89 @@
/*
* GslFFT.cpp, part of LatAnalyze
*
* Copyright (C) 2013 - 2017 Antonin Portelli
*
* LatAnalyze 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 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. If not, see <http://www.gnu.org/licenses/>.
*/
#include <LatAnalyze/Numerical/GslFFT.hpp>
#include <LatAnalyze/includes.hpp>
using namespace std;
using namespace Latan;
/******************************************************************************
* GslFFT implementation *
******************************************************************************/
// constructor /////////////////////////////////////////////////////////////////
GslFFT::GslFFT(const Index size)
{
resize(size);
}
// destructor //////////////////////////////////////////////////////////////////
GslFFT::~GslFFT(void)
{
clear();
}
// size ////////////////////////////////////////////////////////////////////////
void GslFFT::resize(const Index size)
{
if (size_ != size)
{
size_ = size;
wavetable_ = gsl_fft_complex_wavetable_alloc(size_);
workspace_ = gsl_fft_complex_workspace_alloc(size_);
}
}
// fft /////////////////////////////////////////////////////////////////////////
void GslFFT::operator()(CMat &x, const unsigned int dir)
{
if (x.size() != size_)
{
LATAN_ERROR(Size, "wrong input vector size");
}
else
{
switch (dir)
{
case FFT::Forward:
gsl_fft_complex_forward((double *)x.data(), 1, size_,
wavetable_, workspace_);
break;
case FFT::Backward:
gsl_fft_complex_backward((double *)x.data(), 1, size_,
wavetable_, workspace_);
break;
default:
LATAN_ERROR(Argument, "invalid FT direction");
break;
}
}
}
// destroy GSL objects /////////////////////////////////////////////////////////
void GslFFT::clear(void)
{
if (!wavetable_)
{
gsl_fft_complex_wavetable_free(wavetable_);
}
if (!workspace_)
{
gsl_fft_complex_workspace_free(workspace_);
}
}

57
lib/Numerical/GslFFT.hpp Normal file
View File

@ -0,0 +1,57 @@
/*
* GslFFT.hpp, part of LatAnalyze
*
* Copyright (C) 2013 - 2017 Antonin Portelli
*
* LatAnalyze 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 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. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef Latan_GslFFT_hpp_
#define Latan_GslFFT_hpp_
#include <LatAnalyze/Global.hpp>
#include <LatAnalyze/Core/Mat.hpp>
#include <LatAnalyze/Numerical/FFT.hpp>
#include <gsl/gsl_fft_complex.h>
BEGIN_LATAN_NAMESPACE
/******************************************************************************
* GSL FFT *
******************************************************************************/
class GslFFT: public FFT
{
public:
// constructors
GslFFT(void) = default;
GslFFT(const Index size);
// destructor
virtual ~GslFFT(void);
// size
void resize(const Index size);
// fft
virtual void operator()(CMat &x, const unsigned int dir = FFT::Forward);
private:
// destroy GSL objects
void clear(void);
private:
Index size_{0};
gsl_fft_complex_wavetable *wavetable_{nullptr};
gsl_fft_complex_workspace *workspace_{nullptr};
};
END_LATAN_NAMESPACE
#endif // Latan_GslFFT_hpp_

View File

@ -0,0 +1,145 @@
/*
* GslHybridRootFinder.cpp, part of LatAnalyze 3
*
* 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
* 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/GslHybridRootFinder.hpp>
#include <LatAnalyze/includes.hpp>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_multiroots.h>
using namespace std;
using namespace Latan;
/******************************************************************************
* GslHybridRootFinder implementation *
******************************************************************************/
// constructor /////////////////////////////////////////////////////////////////
GslHybridRootFinder::GslHybridRootFinder(const Index dim)
: RootFinder(dim)
{}
// output //////////////////////////////////////////////////////////////////////
void GslHybridRootFinder::printState(void)
{
if (solver_)
{
cout << "x=";
for (size_t i = 0; i < solver_->x->size; ++i)
{
cout << " " << scientific << gsl_vector_get(solver_->x, i);
}
cout << endl;
cout << "f=";
for (size_t i = 0; i < solver_->f->size; ++i)
{
cout << " " << scientific << gsl_vector_get(solver_->f, i);
}
cout << endl;
}
}
// solver //////////////////////////////////////////////////////////////////////
const DVec &
GslHybridRootFinder::operator()(const vector<DoubleFunction *> &func)
{
DVec &res = getState();
Verbosity verbosity = getVerbosity();
int status;
unsigned int iter = 0;
const size_t nFunc = func.size();
Index nArg;
gsl_vector *x;
gsl_multiroot_function fStruct;
int (*fWrap)(const gsl_vector *, void *, gsl_vector *) =
[](const gsl_vector *var, void *vFunc, gsl_vector *f)->int
{
vector<DoubleFunction *> &fPt =
*static_cast<vector<DoubleFunction *> *>(vFunc);
for (unsigned int i = 0; i < fPt.size(); ++i)
{
gsl_vector_set(f, i, (*fPt[i])(var->data));
}
return GSL_SUCCESS;
};
nArg = func[0]->getNArg();
for (auto f: func)
{
if (f->getNArg() != nArg)
{
LATAN_ERROR(Size,
"equations do not have the same number of unknown");
}
}
if (nArg != static_cast<Index>(nFunc))
{
LATAN_ERROR(Size, "equation and unknown number mismatch");
}
if (res.size() != nArg)
{
resize(nArg);
}
solver_ = gsl_multiroot_fsolver_alloc(gsl_multiroot_fsolver_hybrids, nFunc);
x = gsl_vector_alloc(nFunc);
FOR_VEC(res, i)
{
gsl_vector_set(x, static_cast<size_t>(i), res(i));
}
fStruct.n = nFunc;
fStruct.params = reinterpret_cast<void *>(
const_cast<vector<DoubleFunction *> *>(&func));
fStruct.f = fWrap;
gsl_multiroot_fsolver_set(solver_, &fStruct, x);
do
{
iter++;
status = gsl_multiroot_fsolver_iterate(solver_);
if (verbosity >= Verbosity::Debug)
{
cout << "--- iteration " << iter << endl;
printState();
}
if (status)
{
break;
}
status = gsl_multiroot_test_residual(solver_->f, getPrecision());
} while ((status == GSL_CONTINUE) and (iter < getMaxIteration()));
if (verbosity >= Verbosity::Debug)
{
cout << "--- done" << endl;
cout << "end status: " << gsl_strerror(status) << endl;
}
if (status)
{
LATAN_WARNING("GSL hybrid root finder ended with status '" +
strFrom(gsl_strerror(status)) + "'");
}
FOR_VEC(res, i)
{
res(i) = gsl_vector_get(solver_->x, static_cast<size_t>(i));
}
gsl_vector_free(x);
gsl_multiroot_fsolver_free(solver_);
solver_ = nullptr;
return res;
}

View File

@ -0,0 +1,52 @@
/*
* GslHybridRootFinder.hpp, part of LatAnalyze 3
*
* 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
* 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/>.
*/
#ifndef Latan_GslHybridRootFinder_hpp_
#define Latan_GslHybridRootFinder_hpp_
#include <LatAnalyze/Global.hpp>
#include <LatAnalyze/Numerical/RootFinder.hpp>
#include <gsl/gsl_multiroots.h>
BEGIN_LATAN_NAMESPACE
/******************************************************************************
* GslHybridRootFinder *
******************************************************************************/
class GslHybridRootFinder: public RootFinder
{
public:
// constructors
GslHybridRootFinder(void) = default;
explicit GslHybridRootFinder(const Index dim);
// destructor
virtual ~GslHybridRootFinder(void) = default;
// solver
virtual const DVec & operator()(const std::vector<DoubleFunction *> &func);
private:
// output
void printState(void);
private:
gsl_multiroot_fsolver *solver_{nullptr};
};
END_LATAN_NAMESPACE
#endif // Latan_GslHybridRootFinder_hpp_

View File

@ -0,0 +1,361 @@
/*
* GslMinimizer.cpp, part of LatAnalyze
*
* Copyright (C) 2013 - 2016 Antonin Portelli
*
* LatAnalyze 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 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. If not, see <http://www.gnu.org/licenses/>.
*/
#include <LatAnalyze/Numerical/GslMinimizer.hpp>
#include <LatAnalyze/includes.hpp>
#include <LatAnalyze/Core/Math.hpp>
#include <gsl/gsl_multimin.h>
#include <gsl/gsl_blas.h>
using namespace std;
using namespace Latan;
/******************************************************************************
* GslMinimizer implementation *
******************************************************************************/
// constructor /////////////////////////////////////////////////////////////////
GslMinimizer::GslMinimizer(const Algorithm algorithm)
{
setAlgorithm(algorithm);
der_.setOrder(1, 1);
}
// access //////////////////////////////////////////////////////////////////////
GslMinimizer::Algorithm GslMinimizer::getAlgorithm(void) const
{
return algorithm_;
}
void GslMinimizer::setAlgorithm(const Algorithm algorithm)
{
algorithm_ = algorithm;
}
bool GslMinimizer::supportLimits(void) const
{
return false;
}
// test ////////////////////////////////////////////////////////////////////////
bool GslMinimizer::isDerAlgorithm(const Algorithm algorithm)
{
return (algorithm <= Algorithm::lastDerAlg);
}
// minimization ////////////////////////////////////////////////////////////////
const DVec & GslMinimizer::operator()(const DoubleFunction &f)
{
DVec &x = getState();
// resize minimizer state to match function number of arguments
if (f.getNArg() != x.size())
{
resize(f.getNArg());
}
// set function data
GslFuncData data;
der_.setFunction(f);
data.f = &f;
data.d = &der_;
// set initial position
gsl_vector *gslX = gsl_vector_alloc(getDim());
for (Index i = 0; i < getDim(); ++i)
{
gsl_vector_set(gslX, i, x(i));
}
// minimization
int status;
if (isDerAlgorithm(getAlgorithm()))
{
// set function
gsl_multimin_function_fdf gslFunc;
gslFunc.n = getDim();
gslFunc.f = &fWrapper;
gslFunc.df = &dfWrapper;
gslFunc.fdf = &fdfWrapper;
gslFunc.params = &data;
// create and set minimizer
const gsl_multimin_fdfminimizer_type *gslAlg;
gsl_multimin_fdfminimizer *gslMin;
switch (getAlgorithm())
{
case Algorithm::cgFR:
gslAlg = gsl_multimin_fdfminimizer_conjugate_fr;
break;
case Algorithm::cgPR:
gslAlg = gsl_multimin_fdfminimizer_conjugate_pr;
break;
case Algorithm::bfgs:
gslAlg = gsl_multimin_fdfminimizer_vector_bfgs;
break;
case Algorithm::bfgs2:
gslAlg = gsl_multimin_fdfminimizer_vector_bfgs2;
break;
case Algorithm::steepDesc:
gslAlg = gsl_multimin_fdfminimizer_vector_bfgs2;
break;
default:
LATAN_ERROR(Argument, "unknow GSL minization algorithm "
+ strFrom(static_cast<int>(getAlgorithm())));
break;
}
gslMin = gsl_multimin_fdfminimizer_alloc(gslAlg, getDim());
// minimize
unsigned int pass = 0, it;
double dxRel;
do
{
pass++;
gsl_multimin_fdfminimizer_set(gslMin, &gslFunc, gslX, 0.01, 0.001);
if (getVerbosity() >= Verbosity::Normal)
{
cout << "========== GSL minimization, pass #" << pass;
cout << " ==========" << endl;
cout << "Algorithm: " << getAlgorithmName(getAlgorithm());
cout << endl;
cout << "Max eval.= " << getMaxIteration();
cout << " -- Precision= " << getPrecision() << endl;
printf("Starting f(x)= %.10e\n", f(x));
}
it = 0;
do
{
it++;
gsl_multimin_fdfminimizer_iterate(gslMin);
dxRel = gsl_blas_dnrm2(gslMin->dx)/gsl_blas_dnrm2(gslMin->x);
status = (dxRel < getPrecision()) ? GSL_SUCCESS : GSL_CONTINUE;
if (getVerbosity() >= Verbosity::Debug)
{
printf("iteration %4d: f= %.10e dxrel= %.10e eval= %d\n",
it, gslMin->f, dxRel, data.evalCount);
}
} while (status == GSL_CONTINUE and
(data.evalCount < getMaxIteration()));
if (getVerbosity() >= Verbosity::Normal)
{
printf("Found minimum %.10e at:\n", gslMin->f);
for (Index i = 0; i < x.size(); ++i)
{
printf("%8s= %.10e\n", f.varName().getName(i).c_str(),
gsl_vector_get(gslMin->x, i));
}
cout << "after " << data.evalCount << " evaluations" << endl;
cout << "Minimization ended with code " << status;
cout << endl;
}
data.evalCount = 0;
for (Index i = 0; i < getDim(); ++i)
{
gsl_vector_set(gslX, i, gsl_vector_get(gslMin->x, i));
}
} while (status != GSL_SUCCESS and (pass < getMaxPass()));
// deallocate GSL minimizer
gsl_multimin_fdfminimizer_free(gslMin);
}
else
{
// set function
gsl_multimin_function gslFunc;
gslFunc.n = getDim();
gslFunc.f = &fWrapper;
gslFunc.params = &data;
// create and set minimizer
const gsl_multimin_fminimizer_type *gslAlg;
gsl_multimin_fminimizer *gslMin;
switch (getAlgorithm())
{
case Algorithm::simplex:
gslAlg = gsl_multimin_fminimizer_nmsimplex;
break;
case Algorithm::simplex2:
gslAlg = gsl_multimin_fminimizer_nmsimplex2;
break;
case Algorithm::simplex2R:
gslAlg = gsl_multimin_fminimizer_nmsimplex2rand;
break;
default:
LATAN_ERROR(Argument, "unknow GSL minization algorithm "
+ strFrom(static_cast<int>(getAlgorithm())));
break;
}
gslMin = gsl_multimin_fminimizer_alloc(gslAlg, getDim());
// minimize
unsigned int pass = 0, it;
gsl_vector *step = gsl_vector_alloc(getDim());
double relSize;
gsl_vector_set_all(step, 0.01);
do
{
pass++;
gsl_multimin_fminimizer_set(gslMin, &gslFunc, gslX, step);
if (getVerbosity() >= Verbosity::Normal)
{
cout << "========== GSL minimization, pass #" << pass;
cout << " ==========" << endl;
cout << "Algorithm: " << getAlgorithmName(getAlgorithm());
cout << endl;
cout << "Max eval.= " << getMaxIteration();
cout << " -- Precision= " << getPrecision() << endl;
printf("Starting f(x)= %.10e\n", f(x));
}
it = 0;
do
{
it++;
gsl_multimin_fminimizer_iterate(gslMin);
relSize = Math::pow<2>(gslMin->size)/gsl_blas_dnrm2(gslMin->x);
status = (relSize < getPrecision()) ? GSL_SUCCESS
: GSL_CONTINUE;
if (getVerbosity() >= Verbosity::Debug)
{
printf("iteration %4d: f= %.10e relSize= %.10e eval= %d\n",
it, gslMin->fval, relSize, data.evalCount);
}
} while (status == GSL_CONTINUE and
(data.evalCount < getMaxIteration()));
if (getVerbosity() >= Verbosity::Normal)
{
printf("Found minimum %.10e at:\n", gslMin->fval);
for (Index i = 0; i < x.size(); ++i)
{
printf("%8s= %.10e\n", f.varName().getName(i).c_str(),
gsl_vector_get(gslMin->x, i));
}
cout << "after " << data.evalCount << " evaluations" << endl;
cout << "Minimization ended with code " << status;
cout << endl;
}
data.evalCount = 0;
for (Index i = 0; i < getDim(); ++i)
{
gsl_vector_set(gslX, i, gsl_vector_get(gslMin->x, i));
}
} while (status != GSL_SUCCESS and (pass < getMaxPass()));
// deallocate GSL minimizer
gsl_multimin_fminimizer_free(gslMin);
gsl_vector_free(step);
}
if (status != GSL_SUCCESS)
{
LATAN_WARNING("invalid minimum: maximum number of call reached");
}
// save final result
for (Index i = 0; i < getDim(); ++i)
{
x(i) = gsl_vector_get(gslX, i);
}
// deallocate GSL state and return
gsl_vector_free(gslX);
return x;
}
// function wrappers ///////////////////////////////////////////////////////////
double GslMinimizer::fWrapper(const gsl_vector *x, void *vdata)
{
GslFuncData &data = *static_cast<GslFuncData *>(vdata);
data.evalCount++;
return (*data.f)(x->data);
}
void GslMinimizer::dfWrapper(const gsl_vector *x, void *vdata, gsl_vector * df)
{
GslFuncData &data = *static_cast<GslFuncData *>(vdata);
const unsigned int n = data.f->getNArg();
for (unsigned int i = 0; i < n; ++i)
{
data.d->setDir(i);
gsl_vector_set(df, i, (*(data.d))(x->data));
}
data.evalCount += data.d->getNPoint()*n;
}
void GslMinimizer::fdfWrapper(const gsl_vector *x, void *vdata, double *f,
gsl_vector * df)
{
GslFuncData &data = *static_cast<GslFuncData *>(vdata);
const unsigned int n = data.f->getNArg();
for (unsigned int i = 0; i < n; ++i)
{
data.d->setDir(i);
gsl_vector_set(df, i, (*(data.d))(x->data));
}
*f = (*data.f)(x->data);
data.evalCount += data.d->getNPoint()*n + 1;
}
// algorithm names /////////////////////////////////////////////////////////////
string GslMinimizer::getAlgorithmName(const Algorithm algorithm)
{
switch (algorithm)
{
case Algorithm::cgFR:
return "Fletcher-Reeves conjugate gradient";
break;
case Algorithm::cgPR:
return "Polak-Ribiere conjugate gradient";
break;
case Algorithm::bfgs:
return "Broyden-Fletcher-Goldfarb-Shanno";
break;
case Algorithm::bfgs2:
return "improved Broyden-Fletcher-Goldfarb-Shanno";
break;
case Algorithm::steepDesc:
return "steepest descent";
break;
case Algorithm::simplex:
return "Nelder-Mead simplex";
break;
case Algorithm::simplex2:
return "improved Nelder-Mead simplex";
break;
case Algorithm::simplex2R:
return "improved Nelder-Mead simplex with random start";
break;
}
return "";
}

View File

@ -0,0 +1,86 @@
/*
* GslMinimizer.hpp, part of LatAnalyze
*
* Copyright (C) 2013 - 2016 Antonin Portelli
*
* LatAnalyze 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 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. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef Latan_GslMinimizer_hpp_
#define Latan_GslMinimizer_hpp_
#include <LatAnalyze/Global.hpp>
#include <LatAnalyze/Numerical/Derivative.hpp>
#include <LatAnalyze/Functional/Function.hpp>
#include <LatAnalyze/Numerical/Minimizer.hpp>
#include <gsl/gsl_vector.h>
BEGIN_LATAN_NAMESPACE
/******************************************************************************
* interface to the GSL minimizers *
******************************************************************************/
class GslMinimizer: public Minimizer
{
public:
enum class Algorithm
{
cgFR = 1,
cgPR = 2,
bfgs = 3,
bfgs2 = 4,
steepDesc = 5,
lastDerAlg = 5,
simplex = 6,
simplex2 = 7,
simplex2R = 8
};
private:
struct GslFuncData
{
const DoubleFunction *f{nullptr};
Derivative *d{nullptr};
unsigned int evalCount{0};
};
public:
// constructor
explicit GslMinimizer(const Algorithm algorithm = defaultAlg_);
// destructor
virtual ~GslMinimizer(void) = default;
// access
Algorithm getAlgorithm(void) const;
void setAlgorithm(const Algorithm algorithm);
virtual bool supportLimits(void) const;
// minimization
virtual const DVec & operator()(const DoubleFunction &f);
private:
// test
static bool isDerAlgorithm(const Algorithm algorithm);
// function wrappers
static double fWrapper(const gsl_vector *x, void * params);
static void dfWrapper(const gsl_vector *x, void * params,
gsl_vector * df);
static void fdfWrapper(const gsl_vector *x, void *params, double *f,
gsl_vector * df);
// algorithm names
std::string getAlgorithmName(const Algorithm algorithm);
private:
Algorithm algorithm_;
static constexpr Algorithm defaultAlg_ = Algorithm::simplex2;
CentralDerivative der_;
};
END_LATAN_NAMESPACE
#endif // Latan_GslMinimizer_hpp_

View File

@ -0,0 +1,87 @@
/*
* GslQagsIntegrator.cpp, part of LatAnalyze 3
*
* 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
* 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/GslQagsIntegrator.hpp>
#include <LatAnalyze/includes.hpp>
#include <LatAnalyze/Core/Math.hpp>
using namespace std;
using namespace Latan;
/******************************************************************************
* GslQagIntegrator implementation *
******************************************************************************/
// constructor /////////////////////////////////////////////////////////////////
GslQagsIntegrator::GslQagsIntegrator(const unsigned int limit,
const double precision)
: limit_(limit)
, precision_(precision)
{
workspace_ = gsl_integration_workspace_alloc(limit);
}
// destructor //////////////////////////////////////////////////////////////////
GslQagsIntegrator::~GslQagsIntegrator(void)
{
gsl_integration_workspace_free(workspace_);
}
// integral calculation ////////////////////////////////////////////////////////
double GslQagsIntegrator::operator()(const DoubleFunction &f, const double xMin,
const double xMax)
{
double (*fWrap)(double, void *) = [](double x, void *fPt)->double
{
return (*static_cast<DoubleFunction *>(fPt))(&x);
};
gsl_function gslF;
double result;
gslF.function = fWrap;
gslF.params = reinterpret_cast<void *>(&const_cast<DoubleFunction &>(f));
if ((xMin > -Math::inf) and (xMax < Math::inf))
{
gsl_integration_qags(&gslF, xMin, xMax, 0.0, precision_, limit_,
workspace_, &result, &error_);
}
else if (xMax < Math::inf)
{
gsl_integration_qagil(&gslF, xMax, 0.0, precision_, limit_,
workspace_, &result, &error_);
}
else if (xMin > -Math::inf)
{
gsl_integration_qagiu(&gslF, xMin, 0.0, precision_, limit_,
workspace_, &result, &error_);
}
else
{
gsl_integration_qagi(&gslF, 0.0, precision_, limit_,
workspace_, &result, &error_);
}
return result;
}
// get last error //////////////////////////////////////////////////////////////
double GslQagsIntegrator::getLastError(void) const
{
return error_;
}

View File

@ -0,0 +1,58 @@
/*
* GslQagsIntegrator.hpp, part of LatAnalyze 3
*
* 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
* 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/>.
*/
#ifndef Latan_GslQagsIntegrator_hpp_
#define Latan_GslQagsIntegrator_hpp_
#include <LatAnalyze/Global.hpp>
#include <LatAnalyze/Functional/Function.hpp>
#include <LatAnalyze/Numerical/Integrator.hpp>
#include <gsl/gsl_integration.h>
BEGIN_LATAN_NAMESPACE
/******************************************************************************
* GSL general quadrature adaptive integration with singularities *
******************************************************************************/
class GslQagsIntegrator: public Integrator
{
public:
static const unsigned int defaultLimit = 1000;
static constexpr double defaultPrec = 1.0e-7;
public:
// constructor
GslQagsIntegrator(const unsigned int limit = defaultLimit,
const double precision = defaultPrec);
// destructor
virtual ~GslQagsIntegrator(void);
// integral calculation
virtual double operator()(const DoubleFunction &f, const double xMin,
const double xMax);
// get last error
double getLastError(void) const;
private:
unsigned int limit_;
double precision_, error_;
gsl_integration_workspace *workspace_;
};
END_LATAN_NAMESPACE
#endif // Latan_GslQagsIntegrator_hpp_

View File

@ -0,0 +1,46 @@
/*
* Integrator.hpp, part of LatAnalyze 3
*
* 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
* 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/>.
*/
#ifndef Latan_Integrator_hpp_
#define Latan_Integrator_hpp_
#include <LatAnalyze/Global.hpp>
#include <LatAnalyze/Functional/Function.hpp>
BEGIN_LATAN_NAMESPACE
/******************************************************************************
* abstract integrator class *
******************************************************************************/
class Integrator
{
public:
// constructor
Integrator(void) = default;
// destructor
virtual ~Integrator(void) = default;
// integral calculation
virtual double operator()(const DoubleFunction &f, const double xMin,
const double xMax) = 0;
};
END_LATAN_NAMESPACE
#endif // Latan_Integrator_hpp_

194
lib/Numerical/Minimizer.cpp Normal file
View File

@ -0,0 +1,194 @@
/*
* Minimizer.cpp, part of LatAnalyze 3
*
* 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
* 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/Minimizer.hpp>
#include <LatAnalyze/includes.hpp>
using namespace std;
using namespace Latan;
// access //////////////////////////////////////////////////////////////////////
void Minimizer::resize(const Index dim)
{
const Index oldDim = getDim();
Solver::resize(dim);
highLimit_.conservativeResize(dim);
lowLimit_.conservativeResize(dim);
hasHighLimit_.conservativeResize(dim);
hasLowLimit_.conservativeResize(dim);
if (dim > oldDim)
{
highLimit_.segment(oldDim, dim - oldDim).fill(0.);
highLimit_.segment(oldDim, dim - oldDim).fill(0.);
lowLimit_.segment(oldDim, dim - oldDim).fill(0.);
hasHighLimit_.segment(oldDim, dim - oldDim).fill(false);
hasLowLimit_.segment(oldDim, dim - oldDim).fill(false);
}
}
#define checkSupport \
if (!supportLimits())\
{\
LATAN_ERROR(Implementation, "minimizer does not support limits");\
}
double Minimizer::getHighLimit(const Index i) const
{
checkSupport;
if (i >= getDim())
{
LATAN_ERROR(Size, "invalid variable index");
}
return highLimit_(i);
}
const DVec & Minimizer::getHighLimit(const PlaceHolder ph __dumb) const
{
checkSupport;
return highLimit_;
}
double Minimizer::getLowLimit(const Index i) const
{
checkSupport;
if (i >= getDim())
{
LATAN_ERROR(Size, "invalid variable index");
}
return lowLimit_(i);
}
const DVec & Minimizer::getLowLimit(const PlaceHolder ph __dumb) const
{
checkSupport;
return lowLimit_;
}
bool Minimizer::hasHighLimit(const Index i) const
{
checkSupport;
if (i >= getDim())
{
LATAN_ERROR(Size, "invalid variable index");
}
return hasHighLimit_(i);
}
bool Minimizer::hasLowLimit(const Index i) const
{
checkSupport;
if (i >= getDim())
{
LATAN_ERROR(Size, "invalid variable index");
}
return hasLowLimit_(i);
}
void Minimizer::setHighLimit(const Index i, const double l)
{
checkSupport;
if (i >= getDim())
{
resize(i + 1);
}
highLimit_(i) = l;
useHighLimit(i);
}
void Minimizer::setHighLimit(const PlaceHolder ph __dumb, const DVec &l)
{
checkSupport;
if (l.size() != getDim())
{
resize(l.size());
}
highLimit_ = l;
useHighLimit(_);
}
void Minimizer::setLowLimit(const Index i, const double l)
{
checkSupport;
if (i >= getDim())
{
resize(i + 1);
}
lowLimit_(i) = l;
useLowLimit(i);
}
void Minimizer::setLowLimit(const PlaceHolder ph __dumb, const DVec &l)
{
checkSupport;
if (l.size() != getDim())
{
resize(l.size());
}
lowLimit_ = l;
useLowLimit(_);
}
void Minimizer::useHighLimit(const Index i, const bool use)
{
checkSupport;
if (i >= getDim())
{
resize(i + 1);
}
hasHighLimit_(i) = use;
}
void Minimizer::useHighLimit(const PlaceHolder ph __dumb, const bool use)
{
checkSupport;
hasHighLimit_.fill(use);
}
void Minimizer::useLowLimit(const Index i, const bool use)
{
checkSupport;
if (i >= getDim())
{
resize(i + 1);
}
hasLowLimit_(i) = use;
}
void Minimizer::useLowLimit(const PlaceHolder ph __dumb, const bool use)
{
checkSupport;
hasLowLimit_.fill(use);
}
unsigned int Minimizer::getMaxPass(void) const
{
return maxPass_;
}
void Minimizer::setMaxPass(const unsigned int maxPass)
{
maxPass_ = maxPass;
}

View File

@ -0,0 +1,72 @@
/*
* Minimizer.hpp, part of LatAnalyze 3
*
* 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
* 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/>.
*/
#ifndef Latan_Minimizer_hpp_
#define Latan_Minimizer_hpp_
#include <LatAnalyze/Global.hpp>
#include <LatAnalyze/Functional/Function.hpp>
#include <LatAnalyze/Core/Mat.hpp>
#include <LatAnalyze/Numerical/Solver.hpp>
BEGIN_LATAN_NAMESPACE
/******************************************************************************
* Abstract minimizer class *
******************************************************************************/
class Minimizer: public Solver
{
public:
// constructor
Minimizer(void) = default;
// destructor
virtual ~Minimizer(void) = default;
// access
virtual void resize(const Index dim);
virtual double getHighLimit(const Index i) const ;
virtual const DVec & getHighLimit(const PlaceHolder ph = _) const;
virtual double getLowLimit(const Index i) const;
virtual const DVec & getLowLimit(const PlaceHolder ph = _) const;
virtual bool hasHighLimit(const Index i) const;
virtual bool hasLowLimit(const Index i) const;
virtual void setHighLimit(const Index i, const double l);
virtual void setHighLimit(const PlaceHolder ph, const DVec &l);
virtual void setLowLimit(const Index i, const double l);
virtual void setLowLimit(const PlaceHolder ph, const DVec &l);
virtual void useHighLimit(const Index i, const bool use = true);
virtual void useHighLimit(const PlaceHolder ph = _,
const bool use = true);
virtual void useLowLimit(const Index i, const bool use = true);
virtual void useLowLimit(const PlaceHolder ph = _,
const bool use = true);
virtual bool supportLimits(void) const = 0;
virtual unsigned int getMaxPass(void) const;
virtual void setMaxPass(const unsigned int maxPass);
// minimization
virtual const DVec & operator()(const DoubleFunction &f) = 0;
private:
DVec highLimit_, lowLimit_;
Vec<bool> hasHighLimit_, hasLowLimit_;
unsigned int maxPass_{5u};
};
END_LATAN_NAMESPACE
#endif // Latan_Minimizer_hpp_

View File

@ -0,0 +1,184 @@
/*
* MinuitMinimizer.cpp, part of LatAnalyze 3
*
* 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
* 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>
#include <LatAnalyze/includes.hpp>
#include <Minuit2/Minuit2Minimizer.h>
#include <Math/Functor.h>
using namespace std;
using namespace Latan;
static constexpr double initErr = 0.1;
/******************************************************************************
* MinuitMinimizer implementation *
******************************************************************************/
// constructors ////////////////////////////////////////////////////////////////
MinuitMinimizer::MinuitMinimizer(const Algorithm algorithm)
{
setAlgorithm(algorithm);
}
// access //////////////////////////////////////////////////////////////////////
MinuitMinimizer::Algorithm MinuitMinimizer::getAlgorithm(void) const
{
return algorithm_;
}
void MinuitMinimizer::setAlgorithm(const Algorithm algorithm)
{
algorithm_ = algorithm;
}
bool MinuitMinimizer::supportLimits(void) const
{
return true;
}
// minimization ////////////////////////////////////////////////////////////////
const DVec & MinuitMinimizer::operator()(const DoubleFunction &f)
{
using namespace ROOT;
using namespace Minuit2;
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;
}
// 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())
{
case Algorithm::migrad:
minuitAlg = kMigrad;
prec /= 0.002;
break;
case Algorithm::simplex:
minuitAlg = kSimplex;
break;
case Algorithm::combined:
minuitAlg = kCombined;
prec /= 0.002;
break;
}
// resize minimizer state to match function number of arguments
if (f.getNArg() != x.size())
{
resize(f.getNArg());
}
// create and set minimizer
Minuit2Minimizer min(minuitAlg);
min.SetStrategy(2);
min.SetMaxFunctionCalls(getMaxIteration());
min.SetTolerance(prec);
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)
{
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))
{
min.SetLimitedVariable(i, name, val, step, getLowLimit(i),
getHighLimit(i));
}
else
{
min.SetVariable(i, name, val, step);
}
}
// minimize
int status;
unsigned int n = 0;
do
{
if (getVerbosity() >= Verbosity::Normal)
{
cout << "========== Minuit minimization, pass #" << n + 1;
cout << " =========" << endl;
}
min.Minimize();
status = min.Status();
n++;
} while ((status >= 2) and (n < getMaxPass()));
if (getVerbosity() >= Verbosity::Normal)
{
cout << "=================================================" << endl;
}
switch (status)
{
case 1:
// 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;
}
// save and return result
for (Index i = 0; i < x.size(); ++i)
{
x(i) = min.X()[i];
}
return x;
}

View File

@ -0,0 +1,60 @@
/*
* MinuitMinimizer.hpp, part of LatAnalyze 3
*
* 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
* 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/>.
*/
#ifndef Latan_MinuitMinimizer_hpp_
#define Latan_MinuitMinimizer_hpp_
#include <LatAnalyze/Global.hpp>
#include <LatAnalyze/Functional/Function.hpp>
#include <LatAnalyze/Numerical/Minimizer.hpp>
BEGIN_LATAN_NAMESPACE
/******************************************************************************
* interface to CERN Minuit minimizer *
* ( http://www.cern.ch/minuit ) *
******************************************************************************/
class MinuitMinimizer: public Minimizer
{
public:
enum class Algorithm
{
migrad = 1,
simplex = 2,
combined = 3
};
public:
// constructor
explicit MinuitMinimizer(const Algorithm algorithm = defaultAlg_);
// destructor
virtual ~MinuitMinimizer(void) = default;
// access
Algorithm getAlgorithm(void) const;
void setAlgorithm(const Algorithm algorithm);
virtual bool supportLimits(void) const;
// minimization
virtual const DVec & operator()(const DoubleFunction &f);
private:
Algorithm algorithm_;
static constexpr Algorithm defaultAlg_ = Algorithm::combined;
};
END_LATAN_NAMESPACE
#endif // Latan_MinuitMinimizer_hpp_

View File

@ -0,0 +1,201 @@
/*
* NloptMinimizer.cpp, part of LatAnalyze 3
*
* 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
* 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/NloptMinimizer.hpp>
#include <LatAnalyze/includes.hpp>
using namespace std;
using namespace Latan;
/******************************************************************************
* NloptMinimizer implementation *
******************************************************************************/
// constructors ////////////////////////////////////////////////////////////////
NloptMinimizer::NloptMinimizer(const Algorithm algorithm)
{
setAlgorithm(algorithm);
der_.setOrder(1, 1);
}
// access //////////////////////////////////////////////////////////////////////
NloptMinimizer::Algorithm NloptMinimizer::getAlgorithm(void) const
{
return algorithm_;
}
void NloptMinimizer::setAlgorithm(const Algorithm algorithm)
{
algorithm_ = algorithm;
}
bool NloptMinimizer::supportLimits(void) const
{
return true;
}
// minimization ////////////////////////////////////////////////////////////////
const DVec & NloptMinimizer::operator()(const DoubleFunction &f)
{
DVec &x = getState();
// resize minimizer state to match function number of arguments
if (f.getNArg() != x.size())
{
resize(f.getNArg());
}
// create and set minimizer
nlopt::opt min(getAlgorithm(), x.size());
NloptFuncData data;
vector<double> lb(x.size()), hb(x.size());
min.set_maxeval(getMaxIteration());
min.set_xtol_rel(getPrecision());
min.set_ftol_rel(-1.);
der_.setFunction(f);
data.f = &f;
data.d = &der_;
min.set_min_objective(&funcWrapper, &data);
for (Index i = 0; i < x.size(); ++i)
{
lb[i] = hasLowLimit(i) ? getLowLimit(i) : -HUGE_VAL;
hb[i] = hasHighLimit(i) ? getHighLimit(i) : HUGE_VAL;
}
min.set_lower_bounds(lb);
min.set_upper_bounds(hb);
// minimize
double res;
vector<double> vx(x.size());
nlopt::result status;
unsigned int n = 0;
for (Index i = 0; i < x.size(); ++i)
{
vx[i] = x(i);
}
do
{
if (getVerbosity() >= Verbosity::Normal)
{
cout << "========== NLopt minimization, pass #" << n + 1;
cout << " ==========" << endl;
cout << "Algorithm: " << min.get_algorithm_name() << endl;
cout << "Max eval.= " << min.get_maxeval();
cout << " -- Precision= " << min.get_xtol_rel() << endl;
printf("Starting f(x)= %.10e\n", f(x));
}
try
{
status = min.optimize(vx, res);
}
catch (invalid_argument &e)
{
LATAN_ERROR(Runtime, "NLopt has reported receving invalid "
"arguments (if you are using a global minimizer, did "
"you specify limits for all variables?)");
}
if (getVerbosity() >= Verbosity::Normal)
{
printf("Found minimum %.10e at:\n", res);
for (Index i = 0; i < x.size(); ++i)
{
printf("%8s= %.10e\n", f.varName().getName(i).c_str(), vx[i]);
}
cout << "after " << data.evalCount << " evaluations" << endl;
cout << "Minimization ended with code " << status;
cout << " (" << returnMessage(status) << ")";
cout << endl;
}
data.evalCount = 0;
for (Index i = 0; i < x.size(); ++i)
{
x(i) = vx[i];
}
n++;
} while (!minSuccess(status) and (n < getMaxPass()));
if (getVerbosity() >= Verbosity::Normal)
{
cout << "=================================================" << endl;
}
if (!minSuccess(status))
{
LATAN_WARNING("invalid minimum: " + returnMessage(status));
}
return x;
}
// NLopt return code parser ////////////////////////////////////////////////////
string NloptMinimizer::returnMessage(const nlopt::result status)
{
switch (status)
{
case nlopt::SUCCESS:
return "success";
case nlopt::STOPVAL_REACHED:
return "stopping value reached";
case nlopt::FTOL_REACHED:
return "tolerance on function reached";
case nlopt::XTOL_REACHED:
return "tolerance on variable reached";
case nlopt::MAXEVAL_REACHED:
return "maximum function evaluation reached";
case nlopt::MAXTIME_REACHED:
return "maximum time reached";
default:
return "";
}
}
// NLopt function wrapper //////////////////////////////////////////////////////
double NloptMinimizer::funcWrapper(unsigned int n, const double *arg,
double *grad , void *vdata)
{
NloptFuncData &data = *static_cast<NloptFuncData *>(vdata);
if (grad)
{
for (unsigned int i = 0; i < n; ++i)
{
data.d->setDir(i);
grad[i] = (*(data.d))(arg);
}
data.evalCount += data.d->getNPoint()*n;
}
data.evalCount++;
return (*data.f)(arg);
}
// NLopt return status parser //////////////////////////////////////////////////
bool NloptMinimizer::minSuccess(const nlopt::result status)
{
switch (status)
{
case nlopt::SUCCESS:
case nlopt::FTOL_REACHED:
case nlopt::XTOL_REACHED:
return true;
break;
default:
return false;
break;
}
}

View File

@ -0,0 +1,76 @@
/*
* NloptMinimizer.hpp, part of LatAnalyze 3
*
* 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
* 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/>.
*/
#ifndef Latan_NloptMinimizer_hpp_
#define Latan_NloptMinimizer_hpp_
#include <LatAnalyze/Global.hpp>
#include <LatAnalyze/Numerical/Derivative.hpp>
#include <LatAnalyze/Functional/Function.hpp>
#include <LatAnalyze/Numerical/Minimizer.hpp>
#include <nlopt.hpp>
BEGIN_LATAN_NAMESPACE
/******************************************************************************
* interface to NLOpt minimizers *
* ( http://ab-initio.mit.edu/wiki/index.php/NLopt ) *
* -------------------------------------------------------------------------- *
* cf. http://ab-initio.mit.edu/wiki/index.php/NLopt_Algorithms for algorithm *
* references and naming conventions *
******************************************************************************/
class NloptMinimizer: public Minimizer
{
public:
typedef nlopt::algorithm Algorithm;
private:
struct NloptFuncData
{
const DoubleFunction *f{nullptr};
Derivative *d{nullptr};
unsigned int evalCount{0};
};
public:
// constructor
explicit NloptMinimizer(const Algorithm algorithm = defaultAlg_);
// destructor
virtual ~NloptMinimizer(void) = default;
// access
Algorithm getAlgorithm(void) const;
void setAlgorithm(const Algorithm algorithm);
virtual bool supportLimits(void) const;
// minimization
virtual const DVec & operator()(const DoubleFunction &f);
private:
// NLopt return code parser
static std::string returnMessage(const nlopt::result status);
// NLopt function wrapper
static double funcWrapper(unsigned int n, const double *arg,
double *grad , void *vdata);
// NLopt return status parser
static bool minSuccess(const nlopt::result status);
private:
Algorithm algorithm_;
static constexpr Algorithm defaultAlg_ = Algorithm::LN_NELDERMEAD;
CentralDerivative der_;
};
END_LATAN_NAMESPACE
#endif // Latan_NloptMinimizer_hpp_

View File

@ -0,0 +1,29 @@
/*
* RootFinder.cpp, part of LatAnalyze 3
*
* 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
* 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/RootFinder.hpp>
#include <LatAnalyze/includes.hpp>
using namespace std;
using namespace Latan;
// constructor /////////////////////////////////////////////////////////////////
RootFinder::RootFinder(const Index dim)
: Solver(dim)
{}

View File

@ -0,0 +1,48 @@
/*
* RootFinder.hpp, part of LatAnalyze 3
*
* 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
* 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/>.
*/
#ifndef Latan_RootFinder_hpp_
#define Latan_RootFinder_hpp_
#include <LatAnalyze/Global.hpp>
#include <LatAnalyze/Functional/Function.hpp>
#include <LatAnalyze/Numerical/Solver.hpp>
BEGIN_LATAN_NAMESPACE
/******************************************************************************
* RootFinder *
******************************************************************************/
class RootFinder: public Solver
{
public:
// constructors
RootFinder(void) = default;
explicit RootFinder(const Index dim);
// destructor
virtual ~RootFinder(void) = default;
// solver
virtual const DVec & operator()(const std::vector<DoubleFunction *> &func)
= 0;
};
END_LATAN_NAMESPACE
#endif // Latan_RootFinder_hpp_

96
lib/Numerical/Solver.cpp Normal file
View File

@ -0,0 +1,96 @@
/*
* Solver.cpp, part of LatAnalyze 3
*
* 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
* 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/Solver.hpp>
#include <LatAnalyze/includes.hpp>
using namespace std;
using namespace Latan;
/******************************************************************************
* Solver implementation *
******************************************************************************/
// constructors ////////////////////////////////////////////////////////////////
Solver::Solver(const double precision, const unsigned int maxIteration)
{
setMaxIteration(maxIteration);
setPrecision(precision);
}
Solver::Solver(const Index dim, const double precision,
const unsigned int maxIteration)
: Solver(precision, maxIteration)
{
resize(dim);
}
// access //////////////////////////////////////////////////////////////////////
Index Solver::getDim(void) const
{
return x_.size();
}
unsigned int Solver::getMaxIteration(void) const
{
return maxIteration_;
}
double Solver::getPrecision(void) const
{
return precision_;
}
DVec & Solver::getState(void)
{
return x_;
}
Solver::Verbosity Solver::getVerbosity(void) const
{
return verbosity_;
}
void Solver::setInit(const DVec &x0)
{
if (x0.size() != x_.size())
{
resize(x0.size());
}
x_ = x0;
}
void Solver::setMaxIteration(const unsigned int maxIteration)
{
maxIteration_ = maxIteration;
}
void Solver::setPrecision(const double precision)
{
precision_ = precision;
}
void Solver::setVerbosity(const Verbosity verbosity)
{
verbosity_ = verbosity;
}
void Solver::resize(const Index dim)
{
x_.resize(dim);
}

73
lib/Numerical/Solver.hpp Normal file
View File

@ -0,0 +1,73 @@
/*
* Solver.hpp, part of LatAnalyze 3
*
* 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
* 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/>.
*/
#ifndef Latan_Solver_hpp_
#define Latan_Solver_hpp_
#include <LatAnalyze/Global.hpp>
BEGIN_LATAN_NAMESPACE
/******************************************************************************
* Solver *
******************************************************************************/
class Solver
{
public:
static const unsigned int defaultMaxIteration = 10000u;
static constexpr double defaultPrec = 1.0e-7;
public:
enum class Verbosity
{
Silent = 0,
Normal = 1,
Debug = 2
};
public:
// constructors
Solver(const double precision = defaultPrec,
const unsigned int maxIteration = defaultMaxIteration);
explicit Solver(const Index dim, const double precision = defaultPrec,
const unsigned int maxIteration = defaultMaxIteration);
// destructor
virtual ~Solver(void) = default;
// access
Index getDim(void) const;
virtual double getPrecision(void) const;
virtual unsigned int getMaxIteration(void) const;
Verbosity getVerbosity(void) const;
virtual void setInit(const DVec &x0);
virtual void setPrecision(const double precision);
virtual void setMaxIteration(const unsigned int maxIteration);
void setVerbosity(const Verbosity verbosity);
virtual void resize(const Index dim);
protected:
// access
DVec & getState(void);
private:
unsigned int maxIteration_;
double precision_;
DVec x_;
Verbosity verbosity_{Verbosity::Silent};
};
END_LATAN_NAMESPACE
#endif // Latan_Solver_hpp_