Commit afb02684 authored by Jean-Baptiste Mouret's avatar Jean-Baptiste Mouret
Browse files

bounded / unbounded cma-es

parent 1121c354
#ifndef LIMBO_OPT_CMAES_HPP
#define LIMBO_OPT_CMAES_HPP
#ifndef USE_LIBCMAES
#warning NO libcmaes support
#else
#include <vector>
#include <iostream>
#include <Eigen/Core>
#ifdef USE_LIBCMAES
# include <libcmaes/cmaes.h>
#endif
#include <limbo/tools/macros.hpp>
#include <limbo/tools/parallel.hpp>
#include <libcmaes/cmaes.h>
namespace limbo {
namespace defaults {
struct opt_cmaes {
......@@ -27,27 +28,81 @@ namespace limbo {
Eigen::VectorXd operator()(const F& f, double bounded) const
{
size_t dim = f.param_size();
#ifdef USE_LIBCMAES
// wrap the function
libcmaes::FitFunc f_cmaes = [&](const double* x, const int n) {
Eigen::Map<const Eigen::VectorXd> m(x, n);
// remember that our optimizers maximize
return -f.utility(m);
};
if (bounded)
return _opt_bounded(f_cmaes, dim);
else
return _opt_unbounded(f_cmaes, dim);
}
private:
// F is a CMA-ES style function, not our function
template <typename F>
Eigen::VectorXd _opt_unbounded(F& f_cmaes, int dim) const
{
using namespace libcmaes;
// initial step-size, i.e. estimated initial parameter error.
double sigma = 0.5;
// initialize x0 as 0.50 in all 10 dimensions
// WARNING: we ignore the init() of the function to optimize!
// (because CMA-ES will perform its own random initialization)
std::vector<double> x0(dim, 0); // center on 0 if unbounded
// -1 for automatically decided lambda, 0 is for random seeding of the internal generator.
CMAParameters<> cmaparams(x0, sigma);
_set_common_params(cmaparams, dim);
// used by restart I think
cmaparams.set_x0(-1.0, 1.0);
// the optimization itself
CMASolutions cmasols = cmaes<>(f_cmaes, cmaparams);
return cmasols.get_best_seen_candidate().get_x_dvec();
}
// F is a CMA-ES style function, not our function
template <typename F>
Eigen::VectorXd _opt_bounded(F& f_cmaes, int dim) const
{
using namespace libcmaes;
// create the parameter object
// boundary_transformation
double lbounds[dim],ubounds[dim]; // arrays for lower and upper parameter bounds, respectively
double lbounds[dim], ubounds[dim]; // arrays for lower and upper parameter bounds, respectively
for (int i = 0; i < dim; i++) {
lbounds[i] = 0.0;
ubounds[i] = 1.005;
lbounds[i] = 0.0;
ubounds[i] = 1.005;
}
GenoPheno<pwqBoundStrategy> gp(lbounds, ubounds, dim);
// initial step-size, i.e. estimated initial parameter error.
// we suppose we are optimizing on [0, 1], but we have no idea where to start
double sigma = 0.5;
// initialize x0 as 0.50 in all 10 dimensions
// initialize x0 as 0.50 in all dimensions
// WARNING: we ignore the init() of the function to optimize!
// (because CMA-ES will perform its own random initialization)
std::vector<double> x0(dim, 0.5);
// -1 for automatically decided lambda, 0 is for random seeding of the internal generator.
CMAParameters<GenoPheno<pwqBoundStrategy>> cmaparams(dim, &x0.front(), sigma, -1 , 0, gp);
CMAParameters<GenoPheno<pwqBoundStrategy>> cmaparams(dim, &x0.front(), sigma, -1, 0, gp);
_set_common_params(cmaparams, dim);
// used by restart I think
cmaparams.set_x0(0, 1.0);
// the optimization itself
CMASolutions cmasols = cmaes<GenoPheno<pwqBoundStrategy>>(f_cmaes, cmaparams);
//cmasols.print(std::cout, 1, gp);
//to_f_representation
return gp.pheno(cmasols.get_best_seen_candidate().get_x_dvec());
}
template <typename P>
void _set_common_params(P& cmaparams, int dim) const
{
using namespace libcmaes;
// set multi-threading to true
cmaparams.set_mt_feval(true);
// aCMAES should be the best choice
......@@ -65,28 +120,9 @@ namespace limbo {
// we do not know if what is the actual maximum / minimum of the function
// therefore we deactivate this stopping criterion
cmaparams.set_stopping_criteria(FTARGET, false);
// wrap the function
FitFunc f_cmaes = [&](const double *x, const int n) {
Eigen::Map<const Eigen::VectorXd> m(x, n);
// remember that our optimizers maximize
return -f.utility(m);
};
// the optimization itself
CMASolutions cmasols = cmaes<GenoPheno<pwqBoundStrategy>>(f_cmaes, cmaparams);
//cmasols.print(std::cout, 1, gp);
//to_f_representation
return gp.pheno(cmasols.get_best_seen_candidate().get_x_dvec());
#else
#warning NO libcmaes
assert(0);
return Eigen::VectorXd::Zero(dim);
#endif
}
};
}
}
#endif
#endif
......@@ -22,7 +22,17 @@ public:
}
};
BOOST_AUTO_TEST_CASE(test_cmaes)
BOOST_AUTO_TEST_CASE(test_cmaes_unbounded)
{
TestOpt util;
Eigen::VectorXd g = limbo::opt::Cmaes<Params>()(util, false);
BOOST_CHECK_SMALL(g(0), 0.00000001);
BOOST_CHECK_SMALL(g(1), 0.00000001);
}
BOOST_AUTO_TEST_CASE(test_cmaes_bounded)
{
TestOpt util;
Eigen::VectorXd g = limbo::opt::Cmaes<Params>()(util, true);
......
......@@ -15,13 +15,13 @@ def build(bld):
source='test_gp.cpp',
includes='. .. ../../',
target='test_gp',
uselib='BOOST EIGEN TBB',
uselib='BOOST EIGEN TBB LIBCMAES',
use='limbo')
bld.program(features='cxx test',
source='test_init_functions.cpp',
includes='. .. ../../',
target='test_init_functions',
uselib='BOOST EIGEN TBB',
uselib='BOOST EIGEN TBB LIBCMAES',
use='limbo')
bld.program(features='cxx test',
source='test_optimizers.cpp',
......@@ -33,7 +33,7 @@ def build(bld):
source='test_macros.cpp',
includes='. .. ../../',
target='test_macros',
uselib='BOOST EIGEN TBB',
uselib='BOOST EIGEN TBB LIBCMAES',
use='limbo')
bld.program(features='cxx test',
source='test_boptimizer.cpp',
......@@ -46,7 +46,7 @@ def build(bld):
source='test_nlopt.cpp',
includes='. .. ../../',
target='test_nlopt',
uselib='BOOST EIGEN TBB NLOPT',
uselib='BOOST EIGEN TBB NLOPT LIBCMAES',
use='limbo')
if bld.env.DEFINES_NLOPT:
bld.program(features='cxx test',
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment