31 #include <boost/math/special_functions/binomial.hpp>
32 #include <boost/random/uniform_real.hpp>
33 #include <boost/random/uniform_int.hpp>
34 #include <boost/random/variate_generator.hpp>
36 #include "../exceptions.h"
37 #include "../population.h"
38 #include "../problem/base.h"
39 #include "../population.h"
40 #include "../util/neighbourhood.h"
45 namespace pagmo {
namespace algorithm {
59 spea2::spea2(
int gen,
double cr,
double eta_c,
double m,
double eta_m,
int archive_size):
base(),
60 m_gen(gen),m_cr(cr),m_eta_c(eta_c),m_m(m),m_eta_m(eta_m),m_archive_size(archive_size)
63 pagmo_throw(value_error,
"number of generations must be nonnegative");
65 if (cr >= 1 || cr < 0) {
66 pagmo_throw(value_error,
"crossover probability must be in the [0,1[ range");
69 pagmo_throw(value_error,
"mutation probability must be in the [0,1] range");
71 if (eta_c <1 || eta_c >= 100) {
72 pagmo_throw(value_error,
"Distribution index for crossover must be in 1..100");
74 if (eta_m <1 || eta_m >= 100) {
75 pagmo_throw(value_error,
"Distribution index for mutation must be in 1..100");
77 if ((archive_size!=0) && (archive_size<5)) {
78 pagmo_throw(value_error,
"archive_size must larger than 4 or 0 (in this last case the archive size is set to the population size)");
81 pagmo_throw(value_error,
"archive_size must be a multiple of 4");
106 if(m_archive_size == 0) {
114 pagmo_throw(value_error,
"There is no continuous part in the problem decision vector for spea2 to optimise");
117 if( prob_c_dimension != 0 ){
118 pagmo_throw(value_error,
"The problem is not box constrained and spea2 is not suitable to solve it");
121 if( prob_f_dimension < 2 ){
122 pagmo_throw(value_error,
"The problem is not multi-objective. Use a single-objectie optimization algorithm instead");
125 if (NP < 5 || (NP % 4 != 0) ) {
126 pagmo_throw(value_error,
"for SPEA2 at least 5 individuals in the population are needed and the population size must be a multiple of 4");
130 if (NP == 0 || m_gen == 0) {
134 if (archive_size > NP) {
135 pagmo_throw(value_error,
"archive_size must be smaller than the population size");
138 std::vector<spea2_individual> new_pop(NP,spea2_individual());
139 for(
unsigned int i=0; i < NP; ++i) {
145 std::vector<spea2_individual> archive(archive_size,spea2_individual());
146 std::vector<population::size_type> ordered_by_fitness;
149 for(
int g = 0; g <= m_gen; ++g) {
152 for(
unsigned int i=0; i < archive.size(); ++i) {
153 new_pop.push_back(archive[i]);
157 std::vector<double> F(new_pop.size(),0);
161 compute_spea2_fitness(F, sqrt(new_pop.size()), new_pop, prob);
165 unsigned int n_non_dominated;
166 for(n_non_dominated = 0; n_non_dominated < F.size() && F[ordered_by_fitness[n_non_dominated]] < 1; ++n_non_dominated);
169 if(n_non_dominated > archive_size) {
171 archive = std::vector<spea2_individual>(n_non_dominated,spea2_individual());
172 for(
unsigned int i = 0; i < n_non_dominated; ++i) {
173 archive[i] = new_pop[ordered_by_fitness[i]];
177 std::vector<fitness_vector> fit_nd(n_non_dominated);
179 fit_nd[i] = archive[i].f;
183 std::vector<std::vector<pagmo::population::size_type> > neighbours_nd;
185 std::vector<population::size_type> rv(n_non_dominated);
186 for(
unsigned int i=0; i<n_non_dominated; ++i) rv[i] = i;
188 while(archive.size() > archive_size) {
194 rv.erase(rv.end()-1);
195 archive.erase(archive.begin() + idx_to_delete);
196 fit_nd.erase(fit_nd.begin() + idx_to_delete);
199 neighbours_nd.erase(neighbours_nd.begin() + idx_to_delete);
201 for(
unsigned int i=0; i < neighbours_nd.size(); ++i) {
202 for(
unsigned int j=0; j < neighbours_nd[i].size(); ++j) {
204 if (neighbours_nd[i][j] == idx_to_delete) {
205 neighbours_nd[i].erase(neighbours_nd[i].begin() + j);
208 }
else if (neighbours_nd[i][j] > idx_to_delete) {
209 neighbours_nd[i][j]--;
217 for(
unsigned int i = 0; i < archive_size; ++i) {
218 archive[i] = new_pop[ordered_by_fitness[i]];
225 boost::uniform_int<int> pop_idx(0,archive_size-1);
226 boost::variate_generator<boost::mt19937 &, boost::uniform_int<int> > p_idx(
m_urng,pop_idx);
233 std::vector<population::size_type> shuffle(archive_size);
239 std::vector<fitness_vector> archive_fit(archive_size);
240 std::vector<constraint_vector> archive_cons(archive_size);
242 archive_fit[i] = archive[i].f;
243 archive_cons[i] = archive[i].c;
246 std::vector<std::vector<population::size_type> > domination_list = compute_domination_list(prob, archive_fit,archive_cons);
247 std::vector<population::size_type> pareto_rank = compute_pareto_rank(domination_list);
252 std::random_shuffle(shuffle.begin(),shuffle.end(), p_idx);
257 parent1_idx = tournament_selection(shuffle[i], shuffle[i+1], pareto_rank);
258 parent2_idx = tournament_selection(shuffle[i+2], shuffle[i+3], pareto_rank);
259 crossover(child1_x, child2_x, parent1_idx,parent2_idx,archive, prob);
260 mutate(child1_x,prob);
261 mutate(child2_x,prob);
263 spea2_individual child1;
265 child1.f = prob.
objfun(child1_x);
268 spea2_individual child2;
270 child2.f = prob.
objfun(child2_x);
273 new_pop[idx++] = child1;
274 new_pop[idx++] = child2;
284 for(
unsigned int i=0; i<NP; ++i) {
286 pop.push_back(archive[i].x);
289 pop.push_back(new_pop[ordered_by_fitness[i]].x);
298 return "Strength Pareto Evolutionary Algorithm (SPEA2)";
307 std::ostringstream s;
308 s <<
"gen:" << m_gen <<
' ';
309 s <<
"cr: " << m_cr <<
' ';
310 s <<
"eta_c: " << m_eta_c <<
' ';
311 s <<
"m: " << m_m <<
' ';
312 s <<
"eta_m: " << m_eta_m <<
' ';
313 s <<
"archive_size: " << m_archive_size <<
' ';
317 std::vector<std::vector<population::size_type> > spea2::compute_domination_list(
const pagmo::problem::base &prob,
318 const std::vector<fitness_vector> &fit,
319 const std::vector<constraint_vector> &cons)
const
321 std::vector<population::size_type> dummy;
322 std::vector<std::vector<population::size_type> > domination_list(fit.size(), dummy);
324 for(
unsigned int i=0; i<fit.size();++i) {
325 for(
unsigned int j=0; j<fit.size(); ++j) {
327 if(prob.
compare_fc(fit[i],cons[i],fit[j],cons[j])) {
328 domination_list[i].push_back(j);
333 return domination_list;
336 void spea2::compute_spea2_fitness(std::vector<double> &F,
338 const std::vector<spea2_individual> &pop,
343 std::vector<int> S(NP, 0);
346 std::vector<fitness_vector> fit(NP);
347 std::vector<fitness_vector> cons(NP);
352 std::vector<std::vector<pagmo::population::size_type> > neighbours;
355 std::vector<std::vector<population::size_type> > domination_list = compute_domination_list(prob, fit,cons);
357 for(
unsigned int i=0; i<NP; ++i) {
358 S[i] = domination_list[i].size();
361 std::fill(F.begin(), F.end(), 0);
363 for(
unsigned int i=0; i<NP; ++i) {
364 for(
unsigned int j=0; j<domination_list[i].size(); ++j) {
365 F[domination_list[i][j]] += S[i];
369 for(
unsigned int i=0; i<NP; ++i) {
377 if (pareto_rank[idx1] < pareto_rank[idx2])
return idx1;
378 if (pareto_rank[idx1] > pareto_rank[idx2])
return idx2;
379 return ((
m_drng() > 0.5) ? idx1 : idx2);
382 std::vector<population::size_type> spea2::compute_domination_count(
const std::vector<std::vector<population::size_type> > &dom_list)
const
384 std::vector<population::size_type> domination_count(dom_list.size(),0);
385 for(
unsigned int i=0; i<dom_list.size(); ++i) {
386 for(
unsigned int j = 0; j < dom_list[i].size(); ++j) {
387 domination_count[dom_list[i][j]]++;
391 return domination_count;
394 std::vector<population::size_type> spea2::compute_pareto_rank(
const std::vector<std::vector<population::size_type> > &dom_list)
const
396 std::vector<population::size_type> pareto_rank(dom_list.size(),0);
399 std::vector<population::size_type> F,S;
402 std::vector<population::size_type> dom_count = compute_domination_count(dom_list);
406 if (dom_count[idx] == 0) {
411 unsigned int irank = 1;
414 while (F.size()!=0) {
419 dom_count[dom_list[F[i]][j]]--;
420 if (dom_count[dom_list[F[i]][j]] == 0){
421 S.push_back(dom_list[F[i]][j]);
422 pareto_rank[dom_list[F[i]][j]] = irank;
446 double y1,y2,yl,yu, rand, beta, alpha, betaq, c1, c2;
454 if ( (
m_drng() <= 0.5) && (std::fabs(parent1[i]-parent2[i]) ) > 1.0e-14) {
455 if (parent1[i] < parent2[i]) {
466 beta = 1.0 + (2.0*(y1-yl)/(y2-y1));
467 alpha = 2.0 - std::pow(beta,-(m_eta_c+1.0));
468 if (rand <= (1.0/alpha))
470 betaq = std::pow((rand*alpha),(1.0/(m_eta_c+1.0)));
472 betaq = std::pow((1.0/(2.0 - rand*alpha)),(1.0/(m_eta_c+1.0)));
474 c1 = 0.5*((y1+y2)-betaq*(y2-y1));
476 beta = 1.0 + (2.0*(yu-y2)/(y2-y1));
477 alpha = 2.0 - std::pow(beta,-(m_eta_c+1.0));
478 if (rand <= (1.0/alpha))
480 betaq = std::pow((rand*alpha),(1.0/(m_eta_c+1.0)));
482 betaq = std::pow((1.0/(2.0 - rand*alpha)),(1.0/(m_eta_c+1.0)));
484 c2 = 0.5*((y1+y2)+betaq*(y2-y1));
486 if (c1<lb[i]) c1=lb[i];
487 if (c2<lb[i]) c2=lb[i];
488 if (c1>ub[i]) c1=ub[i];
489 if (c2>ub[i]) c2=ub[i];
491 child1[i] = c1; child2[i] = c2;
493 child1[i] = c2; child2[i] = c1;
503 boost::uniform_int<int> in_dist(0,Di-1);
504 boost::variate_generator<boost::mt19937 &, boost::uniform_int<int> > ra_num(
m_urng,in_dist);
507 if (site1 > site2) std::swap(site1,site2);
508 for(
int j=0; j<site1; j++)
510 child1[j] = parent1[j];
511 child2[j] = parent2[j];
513 for(
int j=site1; j<site2; j++)
515 child1[j] = parent2[j];
516 child2[j] = parent1[j];
520 child1[j] = parent1[j];
521 child2[j] = parent2[j];
525 child1[i] = parent1[i];
526 child2[i] = parent2[i];
538 double rnd, delta1, delta2, mut_pow, deltaq;
539 double y, yl, yu, val, xy;
548 delta1 = (y-yl)/(yu-yl);
549 delta2 = (yu-y)/(yu-yl);
551 mut_pow = 1.0/(m_eta_m+1.0);
555 val = 2.0*rnd+(1.0-2.0*rnd)*(pow(xy,(m_eta_m+1.0)));
556 deltaq = pow(val,mut_pow) - 1.0;
561 val = 2.0*(1.0-rnd)+2.0*(rnd-0.5)*(pow(xy,(m_eta_m+1.0)));
562 deltaq = 1.0 - (pow(val,mut_pow));
564 y = y + deltaq*(yu-yl);
577 boost::uniform_int<int> in_dist(yl,yu-1);
578 boost::variate_generator<boost::mt19937 &, boost::uniform_int<int> > ra_num(
m_urng,in_dist);
580 if (gen_num >= y) gen_num = gen_num + 1;
boost::shared_ptr< base > base_ptr
Alias for shared pointer to base algorithm.
spea2(int gen=100, double cr=0.95, double eta_c=10, double m=0.01, double eta_m=50, int archive_size=0)
Constructor.
std::vector< double > decision_vector
Decision vector type.
"Strength Pareto Evolutionary Algorithm (SPEA2)"
fitness_vector cur_f
Current fitness vector.
const individual_type & get_individual(const size_type &) const
Get constant reference to individual at position n.
constraint_vector cur_c
Current constraint vector.
std::vector< population::size_type > order(const std::vector< T > &values)
Sort according the the values in the values vector but return the permutation.
size_type get_dimension() const
Return global dimension.
fitness_vector objfun(const decision_vector &) const
Return fitness of pagmo::decision_vector.
size_type get_i_dimension() const
Return integer dimension.
static double distance(const std::vector< double > &, const std::vector< double > &)
std::string get_name() const
Algorithm name.
void evolve(population &) const
Evolve implementation.
constraint_vector compute_constraints(const decision_vector &) const
Compute constraints and return constraint vector.
c_size_type get_c_dimension() const
Return global constraints dimension.
const decision_vector & get_ub() const
Upper bounds getter.
container_type::size_type size_type
Population size type.
static void compute_neighbours(std::vector< std::vector< pagmo::population::size_type > > &, const std::vector< std::vector< double > > &)
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.
bool compare_fc(const fitness_vector &, const constraint_vector &, const fitness_vector &, const constraint_vector &) const
Simultaneous fitness-constraint comparison.
const decision_vector & get_lb() const
Lower bounds getter.
std::string human_readable_extra() const
Extra human readable algorithm info.
rng_double m_drng
Random number generator for double-precision floating point values.
decision_vector::size_type size_type
Problem's size type: the same as pagmo::decision_vector's size type.
base_ptr clone() const
Clone method.