30 #include <boost/random/normal_distribution.hpp>
31 #include <boost/random/variate_generator.hpp>
32 #include <boost/random/uniform_real.hpp>
33 #include <boost/numeric/conversion/cast.hpp>
34 #include <boost/math/special_functions/fpclassify.hpp>
38 #include "../exceptions.h"
39 #include "../population.h"
40 #include "../problem/base_stochastic.h"
42 #include "../Eigen/Dense"
44 namespace pagmo {
namespace algorithm {
62 cmaes::cmaes(
int gen,
double cc,
double cs,
double c1,
double cmu,
double sigma0,
double ftol,
double xtol,
bool memory):
63 base(), m_gen(
boost::numeric_cast<
std::size_t>(gen)), m_cc(cc), m_cs(cs), m_c1(c1),
64 m_cmu(cmu), m_sigma(sigma0), m_ftol(ftol), m_xtol(xtol), m_memory(memory) {
66 pagmo_throw(value_error,
"number of generations must be nonnegative");
68 if ( ((cc < 0) || (cc > 1)) && !(cc==-1) ){
69 pagmo_throw(value_error,
"cc needs to be in [0,1] or -1 for auto value");
71 if ( ((cs < 0) || (cs > 1)) && !(cs==-1) ){
72 pagmo_throw(value_error,
"cs needs to be in [0,1] or -1 for auto value");
74 if ( ((c1 < 0) || (c1 > 1)) && !(c1==-1) ){
75 pagmo_throw(value_error,
"c1 needs to be in [0,1] or -1 for auto value");
77 if ( ((cmu < 0) || (cmu > 1)) && !(cmu==-1) ){
78 pagmo_throw(value_error,
"cmu needs to be in [0,1] or -1 for auto value");
82 m_mean = Eigen::VectorXd::Zero(1);
83 m_variation = Eigen::VectorXd::Zero(1);
84 m_newpop = std::vector<Eigen::VectorXd>();
85 m_B = Eigen::MatrixXd::Identity(1,1);
86 m_D = Eigen::MatrixXd::Identity(1,1);
87 m_C = Eigen::MatrixXd::Identity(1,1);
88 m_invsqrtC = Eigen::MatrixXd::Identity(1,1);
89 m_pc = Eigen::VectorXd::Zero(1);
90 m_ps = Eigen::VectorXd::Zero(1);
103 cmp_using_cur(
const population &pop):m_pop(pop) {}
107 m_pop.problem().compare_fc(
108 m_pop.get_individual(i1).cur_f, m_pop.get_individual(i1).cur_c,
109 m_pop.get_individual(i2).cur_f, m_pop.get_individual(i2).cur_c)
112 const population &m_pop;
134 pagmo_throw(value_error,
"There is no continuous part in the problem decision vector for CE to optimise");
138 pagmo_throw(value_error,
"The problem is not single objective and CE is not suitable to solve it");
141 if ( prob_c_dimension != 0 ) {
142 pagmo_throw(value_error,
"The problem is not box constrained and CE is not suitable to solve it");
145 if ( prob_i_dimension != 0 ) {
146 pagmo_throw(value_error,
"The problem has an integer part and CE is not suitable to solve it");
150 pagmo_throw(value_error,
"for CE at least 5 individuals in the population are required");
158 using namespace Eigen;
161 boost::normal_distribution<double> normal(0.0,1.0);
162 boost::variate_generator<boost::lagged_fibonacci607 &, boost::normal_distribution<double> > normally_distributed_number(
m_drng,normal);
163 boost::uniform_real<double> uniform(0.0,1.0);
164 boost::variate_generator<boost::lagged_fibonacci607 &, boost::uniform_real<double> > randomly_distributed_number(
m_drng,uniform);
167 VectorXd weights(mu);
168 for (
int i = 0; i < weights.rows(); ++i){
169 weights(i) = std::log(mu+0.5) - std::log(i+1.0);
171 weights /= weights.sum();
172 double mueff = 1.0 / (weights.transpose()*weights);
175 double cc(m_cc),
cs(m_cs), c1(m_c1), cmu(m_cmu);
177 cc = (4 + mueff/N) / (N+4 + 2*mueff/N);
180 cs = (mueff+2) / (N+mueff+5);
183 c1 = 2.0 / ((N+1.3)*(N+1.3)+mueff);
186 cmu = 2.0 * (mueff-2+1/mueff) / ((N+2)*(N+2)+mueff);
189 double damps = 1 + 2*std::max(0.0, std::sqrt((mueff-1)/(N+1))-1) +
cs;
190 double chiN = std::sqrt(N) * (1-1.0/(4*N)+1.0/(21*N*N));
195 VectorXd mean(m_mean);
196 VectorXd variation(m_variation);
197 std::vector<VectorXd> newpop(m_newpop);
201 MatrixXd invsqrtC(m_invsqrtC);
204 int counteval(m_counteval);
205 int eigeneval(m_eigeneval);
206 double sigma(m_sigma);
210 VectorXd meanold = VectorXd::Zero(N);
211 MatrixXd Dinv = MatrixXd::Identity(N,N);
212 MatrixXd Cold = MatrixXd::Identity(N,N);
213 VectorXd tmp = VectorXd::Zero(N);
214 std::vector<VectorXd> elite(mu,tmp);
218 if ( (m_newpop.size() != lam) || ((
unsigned int)(m_newpop[0].rows() ) != N) || (m_memory==
false) ) {
221 mean(i) = pop.champion().
x[i];
223 newpop = std::vector<VectorXd>(lam,tmp);
227 B.resize(N,N); B = MatrixXd::Identity(N,N);
228 D.resize(N,N); D = MatrixXd::Identity(N,N);
231 D(j,j) = std::max((ub[j]-lb[j]),1e-6);
233 C.resize(N,N); C = MatrixXd::Identity(N,N);
235 invsqrtC.resize(N,N); invsqrtC = MatrixXd::Identity(N,N);
237 invsqrtC(j,j) = 1 / D(j,j);
239 pc.resize(N); pc = VectorXd::Zero(N);
240 ps.resize(N); ps = VectorXd::Zero(N);
250 std::cout <<
"CMAES 4 PaGMO: " << std::endl;
251 std::cout <<
"mu: " << mu
252 <<
" - lambda: " << lam
253 <<
" - mueff: " << mueff
254 <<
" - N: " << N << std::endl;
256 std::cout <<
"cc: " << cc
260 <<
" - sigma: " << sigma
261 <<
" - damps: " << damps
262 <<
" - chiN: " << chiN << std::endl;
265 SelfAdjointEigenSolver<MatrixXd> es(N);
266 for (std::size_t g = 0; g < m_gen; ++g) {
272 tmp(j) = normally_distributed_number();
275 newpop[i] = mean + (sigma * B * D * tmp);
279 var_norm = (sigma * B * D * tmp).norm();
284 if ( (sigma*B*D*tmp).norm() < m_xtol ) {
286 std::cout <<
"Exit condition -- xtol < " << m_xtol << std::endl;
295 std::cout <<
"Exit condition -- ftol < " << m_ftol << std::endl;
303 for (decision_vector::size_type j = 0; j<N; ++j ) {
304 if ( (newpop[i](j) < lb[j]) || (newpop[i](j) > ub[j]) ) {
305 newpop[i](j) = lb[j] + randomly_distributed_number() * (ub[j] - lb[j]);
317 for (decision_vector::size_type j = 0; j<N; ++j ) {
318 dumb[j] = newpop[i](j);
324 catch (
const std::bad_cast& e)
328 for (decision_vector::size_type j = 0; j<N; ++j ) {
329 dumb[j] = newpop[i](j);
338 std::vector<population::size_type> best_idx;
339 best_idx.reserve(pop.size());
341 best_idx.push_back(i);
343 cmp_using_cur cmp(pop);
344 std::sort(best_idx.begin(),best_idx.end(),cmp);
347 for (decision_vector::size_type j = 0; j<N; ++j ) {
355 mean = elite[0]*weights(0);
357 mean += elite[i]*weights(i);
361 ps = (1 -
cs) * ps + std::sqrt(
cs*(2-
cs)*mueff) * invsqrtC * (mean-meanold) / sigma;
363 hsig = (ps.squaredNorm() / N / (1-std::pow((1-
cs),(2.0*counteval/lam))) ) < (2.0 + 4/(N+1));
364 pc = (1-cc) * pc + hsig * std::sqrt(cc*(2-cc)*mueff) * (mean-meanold) / sigma;
368 C = (elite[0]-meanold)*(elite[0]-meanold).transpose()*weights(0);
370 C += (elite[i]-meanold)*(elite[i]-meanold).transpose()*weights(i);
373 C = (1-c1-cmu) * Cold +
375 c1 * ((pc * pc.transpose()) + (1-hsig) * cc * (2-cc) * Cold);
378 sigma *= std::exp( std::min( 0.6, (
cs/damps) * (ps.norm()/chiN - 1) ) );
379 if ( (boost::math::isnan)(sigma) || (boost::math::isnan)(sigma) || (boost::math::isinf)(var_norm) || (boost::math::isnan)(var_norm) ) {
380 std::cout <<
"eigen: " << es.info() << std::endl;
381 std::cout <<
"B: " << B << std::endl;
382 std::cout <<
"D: " << D << std::endl;
383 std::cout <<
"Dinv: " << D << std::endl;
384 std::cout <<
"invsqrtC: " << invsqrtC << std::endl;
385 pagmo_throw(value_error,
"NaN!!!!! in CMAES");
389 if ( (counteval - eigeneval) > (lam/(c1+cmu)/N/10) ) {
390 eigeneval = counteval;
391 C = (C+C.transpose())/2;
393 if (es.info()==Success) {
394 B = es.eigenvectors();
395 D = es.eigenvalues().asDiagonal();
396 for (decision_vector::size_type j = 0; j<N; ++j ) {
397 D(j,j) = std::sqrt( std::max(1e-20,D(j,j)) );
399 for (decision_vector::size_type j = 0; j<N; ++j ) {
400 Dinv(j,j) = 1.0 / D(j,j);
402 invsqrtC = B*Dinv*B.transpose();
411 std::cout << std::endl << std::left << std::setw(20) <<
412 "Gen." << std::setw(20) <<
413 "Champion " << std::setw(20) <<
414 "Highest " << std::setw(20) <<
415 "Lowest" << std::setw(20) <<
416 "Variation" << std::setw(20) <<
420 std::cout << std::left << std::setprecision(14) << std::setw(20) <<
421 g << std::setw(20) <<
422 pop.champion().
f[0] << std::setw(20) <<
423 pop.
get_individual(pop.get_best_idx()).best_f[0] << std::setw(20) <<
424 pop.
get_individual(pop.get_worst_idx()).best_f[0] << std::setw(20) <<
425 var_norm << std::setw(20) <<
432 m_variation = variation;
437 m_invsqrtC = invsqrtC;
440 m_counteval = counteval;
441 m_eigeneval = eigeneval;
501 std::ostringstream s;
502 s <<
"gen:" << m_gen <<
' '
503 <<
"cc:" << m_cc <<
' '
504 <<
"cs:" << m_cs <<
' '
505 <<
"c1:" << m_c1 <<
' '
506 <<
"cmu:" << m_cmu <<
' '
507 <<
"sigma0:" << m_sigma <<
' '
508 <<
"ftol:" << m_ftol <<
' '
509 <<
"xtol:" << m_xtol <<
' '
510 <<
"memory:" << m_memory;
boost::shared_ptr< base > base_ptr
Alias for shared pointer to base algorithm.
double get_ftol() const
Getter for m_ftol.
std::vector< double > decision_vector
Decision vector type.
void set_xtol(const double p)
Setter for m_xtol.
void set_gen(const int gen)
Setter for m_gen.
const individual_type & get_individual(const size_type &) const
Get constant reference to individual at position n.
double get_c1() const
Getter for m_c1.
void evolve(population &) const
Evolve implementation.
void set_cmu(const double p)
Setter for m_cmu.
void set_ftol(const double p)
Setter for m_ftol.
cmaes(int gen=500, double cc=-1, double cs=-1, double c1=-1, double cmu=-1, double sigma0=0.5, double ftol=1e-6, double xtol=1e-6, bool memory=true)
Constructor.
double get_cc() const
Getter for m_cc.
Covariance Matrix Adaptation Evolutionary Strategy (CMAES)
size_type get_dimension() const
Return global dimension.
base_ptr clone() const
Clone method.
decision_vector x
Decision vector.
void set_cs(const double p)
Setter for m_cs.
fitness_vector f
Fitness vector.
void set_c1(const double p)
Setter for m_c1.
double get_cmu() const
Getter for m_cmu.
bool m_screen_output
Indicates to the derived class whether to print stuff on screen.
size_type get_i_dimension() const
Return integer dimension.
void set_sigma(const double p)
Setter for m_sigma.
c_size_type get_c_dimension() const
Return global constraints dimension.
double get_xtol() const
Getter for m_xtol.
const decision_vector & get_ub() const
Upper bounds getter.
Base Stochastic Optimization Problem.
container_type::size_type size_type
Population size type.
std::string get_name() const
Algorithm name.
decision_vector cur_x
Current decision vector.
rng_uint32 m_urng
Random number generator for unsigned integer values.
f_size_type get_f_dimension() const
Return fitness dimension.
double get_sigma() const
Getter for m_sigma.
int get_gen() const
Getter for m_gen.
const decision_vector & get_lb() const
Lower bounds getter.
rng_double m_drng
Random number generator for double-precision floating point values.
The Compass Search Solver (CS)
double get_cs() const
Getter for m_cs.
void set_cc(const double p)
Setter for m_cc.
decision_vector::size_type size_type
Problem's size type: the same as pagmo::decision_vector's size type.
std::string human_readable_extra() const
Extra human readable algorithm info.