mirror of
https://github.com/aportelli/LatAnalyze.git
synced 2025-06-22 00:42:02 +01:00
reintegration of LatCore & folder restructuration
This commit is contained in:
361
lib/Numerical/GslMinimizer.cpp
Normal file
361
lib/Numerical/GslMinimizer.cpp
Normal 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 "";
|
||||
}
|
Reference in New Issue
Block a user