PaGMO  1.1.5
algorithm/cstrs_co_evolution.cpp
1 /*****************************************************************************
2  * Copyright (C) 2004-2015 The PaGMO development team, *
3  * Advanced Concepts Team (ACT), European Space Agency (ESA) *
4  * *
5  * https://github.com/esa/pagmo *
6  * *
7  * act@esa.int *
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  * This program is distributed in the hope that it will be useful, *
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17  * GNU General Public License for more details. *
18  * *
19  * You should have received a copy of the GNU General Public License *
20  * along with this program; if not, write to the *
21  * Free Software Foundation, Inc., *
22  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
23  *****************************************************************************/
24 
25 #include <boost/random/uniform_int.hpp>
26 #include <boost/random/uniform_real.hpp>
27 #include <boost/random/variate_generator.hpp>
28 #include <boost/random/normal_distribution.hpp>
29 #include <string>
30 #include <vector>
31 
32 #include "../exceptions.h"
33 #include "../population.h"
34 #include "../problem/base.h"
35 #include "../problem/cstrs_co_evolution.h"
36 #include "../types.h"
37 #include "base.h"
38 #include "cstrs_co_evolution.h"
39 
40 namespace pagmo { namespace algorithm {
41 
43 
65  const base &original_algo_penalties, int pop_penalties_size,
66  int gen,method_type method, double pen_lower_bound,
67  double pen_upper_bound,
68  double ftol, double xtol):
69  base(),m_original_algo(original_algo.clone()), m_original_algo_penalties(original_algo_penalties.clone()),
70  m_gen(gen),m_pop_penalties_size(pop_penalties_size),m_method(method),
71  m_pen_lower_bound(pen_lower_bound),m_pen_upper_bound(pen_upper_bound),m_ftol(ftol),m_xtol(xtol)
72 {
73  if(gen < 0) {
74  pagmo_throw(value_error,"number of generations must be nonnegative");
75  }
76  if(pop_penalties_size <= 0) {
77  pagmo_throw(value_error,"the population size of the penalty weights must be greater than 0");
78  }
79  if(pen_lower_bound>=pen_upper_bound){
80  pagmo_throw(value_error,"Lower Bound of penalty coefficients must be smaller than Upper Bound");
81  }
82 }
83 
86  base(algo),m_original_algo(algo.m_original_algo->clone()),
87  m_original_algo_penalties(algo.m_original_algo_penalties->clone()),m_gen(algo.m_gen),
88  m_pop_penalties_size(algo.m_pop_penalties_size),m_method(algo.m_method),
89  m_pen_lower_bound(algo.m_pen_lower_bound),m_pen_upper_bound(algo.m_pen_upper_bound),
90  m_ftol(algo.m_ftol),m_xtol(algo.m_xtol)
91 {}
92 
95 {
96  return base_ptr(new cstrs_co_evolution(*this));
97 }
98 
100 
106 {
107  // Let's store some useful variables.
108  const problem::base &prob = pop.problem();
109  const population::size_type pop_size = pop.size();
110  const problem::base::size_type prob_dimension = prob.get_dimension();
111 
112  // get the constraints dimension
113  problem::base::c_size_type prob_c_dimension = prob.get_c_dimension();
114 
115  //We perform some checks to determine wether the problem/population are suitable for co-evolution
116  if(prob_c_dimension < 1) {
117  pagmo_throw(value_error,"The problem is not constrained and co-evolution is not suitable to solve it");
118  }
119  if(prob.get_f_dimension() != 1) {
120  pagmo_throw(value_error,"The problem is multiobjective and co-evolution is not suitable to solve it");
121  }
122 
123  // Get out if there is nothing to do.
124  if(pop_size == 0) {
125  return;
126  }
127 
128  //get the dimension of the chromosome of P2
129  unsigned int pop_2_dim = 0;
130  switch(m_method)
131  {
132  case algorithm::cstrs_co_evolution::SIMPLE:
133  {
134  pop_2_dim = 2;
135  break;
136  }
137  case algorithm::cstrs_co_evolution::SPLIT_NEQ_EQ:
138  {
139  pop_2_dim = 4;
140  break;
141  }
142  case algorithm::cstrs_co_evolution::SPLIT_CONSTRAINTS:
143  pop_2_dim = 2*prob.get_c_dimension();
144  break;
145  default:
146  pagmo_throw(value_error,"The constraints co-evolutionary method is not valid.");
147  break;
148  }
149 
150  // split the population into two populations
151  // the population P1 associated to the modified problem with penalized fitness
152  // and population P2 encoding the penalty weights
153 
154  // Populations size
155  population::size_type pop_1_size = pop_size;
156  population::size_type pop_2_size = m_pop_penalties_size;
157 
158  //Creates problem associated to P2
159  problem::cstrs_co_evolution_penalty prob_2(prob,pop_2_dim,pop_2_size);
160  prob_2.set_bounds(m_pen_lower_bound,m_pen_upper_bound);
161 
162  //random initialization of the P2 chromosome (needed for the fist generation)
163  std::vector<decision_vector> pop_2_x(pop_2_size);
164  std::vector<fitness_vector> pop_2_f(pop_2_size);
165 
166  for(population::size_type j=0; j<pop_2_size; j++) {
167  pop_2_x[j] = decision_vector(pop_2_dim,0.);
168  // choose random coefficients between lower bound and upper bound
169  for(population::size_type i=0; i<pop_2_dim;i++) {
170  pop_2_x[j][i] = boost::uniform_real<double>(m_pen_lower_bound,m_pen_upper_bound)(m_drng);
171  }
172  }
173 
174  //vector of the population P1. Initialized with clones of the original population
175  std::vector<population> pop_1_vector;
176  for(population::size_type i=0; i<pop_2_size; i++){
177  pop_1_vector.push_back(population(pop));
178  }
179 
180  // Main Co-Evolution loop
181  for(int k=0; k<m_gen; k++) {
182  // for each individuals of pop 2, evolve the current population,
183  // and store the position of the feasible idx
184  for(population::size_type j=0; j<pop_2_size; j++) {
185 
186  problem::cstrs_co_evolution prob_1(prob, pop_1_vector.at(j), m_method);
187 
188  // modify the problem by setting decision vector encoding penalty
189  // coefficients w1 and w2 in prob 1
190  prob_1.set_penalty_coeff(pop_2_x.at(j));
191 
192  // creating the POPULATION 1 instance based on the
193  // updated prob 1
194 
195  // prob_1 is a BASE_META???? THE CLONE OF prob_1 IN POP_1 IS AT THE LEVEL OF
196  // THE BASE CLASS AND NOT AT THE LEVEL OF THE BASE_META, NO?!?
197  population pop_1(prob_1,0);
198 
199  // initialize P1 chromosomes. The fitnesses related to problem 1 are computed
200  for(population::size_type i=0; i<pop_1_size; i++) {
201  pop_1.push_back(pop_1_vector.at(j).get_individual(i).cur_x);
202  }
203 
204  // evolve the P1 instance
205  m_original_algo->evolve(pop_1);
206 
207  //updating the original problem population (computation of fitness and constraints)
208  pop_1_vector.at(j).clear();
209  for(population::size_type i=0; i<pop_1_size; i++){
210  pop_1_vector.at(j).push_back(pop_1.get_individual(i).cur_x);
211  }
212 
213  // set up penalization variables needs for the population 2
214  // the constraints has not been evaluated yet.
215  prob_2.update_penalty_coeff(j,pop_2_x.at(j),pop_1_vector.at(j));
216 
217  }
218  // creating the POPULATION 2 instance based on the
219  // updated prob 2
220  population pop_2(prob_2,0);
221 
222  // compute the fitness values of the second population
223  for(population::size_type i=0; i<pop_2_size; i++) {
224  pop_2.push_back(pop_2_x[i]);
225  }
226 
227  m_original_algo_penalties->evolve(pop_2);
228 
229  // store the new chromosomes
230  for(population::size_type i=0; i<pop_2_size; i++) {
231  pop_2_x[i] = pop_2.get_individual(i).cur_x;
232  pop_2_f[i] = pop_2.get_individual(i).cur_f;
233  }
234 
235  // Check the exit conditions (every 40 generations, just as DE)
236  if(k % 40 == 0) {
237  // finds the best population
238  population::size_type best_idx = 0;
239  for(population::size_type j=1; j<pop_2_size; j++) {
240  if(pop_2_f[j][0] < pop_2_f[best_idx][0]) {
241  best_idx = j;
242  }
243  }
244 
245  const population &current_population = pop_1_vector.at(best_idx);
246 
247  decision_vector tmp(prob_dimension);
248 
249  double dx = 0;
250  for(decision_vector::size_type i=0; i<prob_dimension; i++) {
251  tmp[i] = current_population.get_individual(current_population.get_worst_idx()).best_x[i] -
252  current_population.get_individual(current_population.get_best_idx()).best_x[i];
253  dx += std::fabs(tmp[i]);
254  }
255 
256  if(dx < m_xtol ) {
257  if (m_screen_output) {
258  std::cout << "Exit condition -- xtol < " << m_xtol << std::endl;
259  }
260  break;
261  }
262 
263  double mah = std::fabs(current_population.get_individual(current_population.get_worst_idx()).best_f[0] -
264  current_population.get_individual(current_population.get_best_idx()).best_f[0]);
265 
266  if(mah < m_ftol) {
267  if(m_screen_output) {
268  std::cout << "Exit condition -- ftol < " << m_ftol << std::endl;
269  }
270  break;
271  }
272 
273  // outputs current values
274  if(m_screen_output) {
275  std::cout << "Generation " << k << " ***" << std::endl;
276  std::cout << " Best global fitness: " << current_population.champion().f << std::endl;
277  std::cout << " xtol: " << dx << ", ftol: " << mah << std::endl;
278  std::cout << " xtol: " << dx << ", ftol: " << mah << std::endl;
279  }
280  }
281  }
282 
283  // find the best fitness population in the final pop
284  population::size_type best_idx = 0;
285  for(population::size_type j=1; j<pop_2_size; j++) {
286  if(pop_2_f[j][0] < pop_2_f[best_idx][0]) {
287  best_idx = j;
288  }
289  }
290 
291  // store the final population in the main population
292  // can't avoid to recompute the vectors here, otherwise we
293  // clone the problem stored in the population with the
294  // pop = operator!
295  pop.clear();
296  for(population::size_type i=0; i<pop_1_size; i++) {
297  pop.push_back(pop_1_vector.at(best_idx).get_individual(i).cur_x);
298  }
299 }
300 
302 std::string cstrs_co_evolution::get_name() const
303 {
304  return m_original_algo->get_name() + "[Co-Evolution]";
305 }
306 
308 
312 {
313  return m_original_algo->clone();
314 }
315 
317 
323 {
324  m_original_algo = algo.clone();
325 }
326 
328 
332 {
333  std::ostringstream s;
334  s << "algorithms: " << m_original_algo->get_name() << " - " << m_original_algo_penalties->get_name() << " ";
335  s << "\n\tConstraints handled with co-evolution algorithm";
336  return s.str();
337 }
338 }} //namespaces
339 
340 BOOST_CLASS_EXPORT_IMPLEMENT(pagmo::algorithm::cstrs_co_evolution)
boost::shared_ptr< base > base_ptr
Alias for shared pointer to base algorithm.
Root PaGMO namespace.
std::vector< double > decision_vector
Decision vector type.
Definition: types.h:40
fitness_vector cur_f
Current fitness vector.
Definition: population.h:89
const individual_type & get_individual(const size_type &) const
Get constant reference to individual at position n.
Definition: population.cpp:277
Base algorithm class.
base_ptr get_algorithm() const
Get a copy of the internal local algorithm.
Base problem class.
Definition: problem/base.h:148
Population class.
Definition: population.h:70
size_type get_dimension() const
Return global dimension.
void set_algorithm(const base &)
Set algorithm.
virtual base_ptr clone() const =0
Clone method.
fitness_vector f
Fitness vector.
Definition: population.h:153
Co-Evolution constraints handling meta-algorithm.
bool m_screen_output
Indicates to the derived class whether to print stuff on screen.
c_size_type get_c_dimension() const
Return global constraints dimension.
void evolve(population &) const
Evolve implementation.
container_type::size_type size_type
Population size type.
Definition: population.h:192
decision_vector cur_x
Current decision vector.
Definition: population.h:83
f_size_type get_f_dimension() const
Return fitness dimension.
constraint_vector::size_type c_size_type
Constraints' size type: the same as pagmo::constraint_vector's size type.
Definition: problem/base.h:164
rng_double m_drng
Random number generator for double-precision floating point values.
std::string human_readable_extra() const
Extra human readable algorithm info.
decision_vector::size_type size_type
Problem's size type: the same as pagmo::decision_vector's size type.
Definition: problem/base.h:160
std::string get_name() const
Algorithm name.
cstrs_co_evolution(const base &=jde(), const base &=sga(1), int pop_penalties_size=30, int gen=1, method_type method=SIMPLE, double pen_lower_bound=0., double pen_upper_bound=100000., double=1e-15, double=1e-15)
Constructor.