PaGMO  1.1.5
problem/cstrs_self_adaptive.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 <cmath>
26 #include <algorithm>
27 
28 #include "../exceptions.h"
29 #include "../types.h"
30 #include "../population.h"
31 #include "cstrs_self_adaptive.h"
32 
35 
36 namespace pagmo { namespace problem {
37 
49 cstrs_self_adaptive::cstrs_self_adaptive(const base &problem, const population &pop):
50  base_meta(
51  problem,
52  problem.get_dimension(),
53  problem.get_i_dimension(),
54  problem.get_f_dimension(),
55  0,
56  0,
57  std::vector<double>()),
58  m_apply_penalty_1(false),
59  m_scaling_factor(0.0),
60  m_c_scaling(problem.get_c_dimension(),0.0),
61  m_f_hat_down(problem.get_f_dimension(),0.0),
62  m_f_hat_up(problem.get_f_dimension(),0.0),
63  m_f_hat_round(problem.get_f_dimension(),0.0),
64  m_i_hat_down(0.0),
65  m_i_hat_up(0.0),
66  m_i_hat_round(0.0),
67  m_map_fitness(),
68  m_map_constraint(),
69  m_decision_vector_hash()
70 {
71  if(m_original_problem->get_c_dimension() <= 0){
72  pagmo_throw(value_error,"The original problem has no constraints.");
73  }
74 
75  // check that the dimension of the problem is 1
76  if (m_original_problem->get_f_dimension() != 1) {
77  pagmo_throw(value_error,"The original fitness dimension of the problem must be one, multi objective problems can't be handled with self adaptive meta problem.");
78  }
79 
80  if(problem != pop.problem()) {
81  pagmo_throw(value_error,"The problem linked to the population is not the same as the problem given in argument.");
82  }
83 
84  update_penalty_coeff(pop);
85 }
86 
87 cstrs_self_adaptive::cstrs_self_adaptive(const base &problem):
88  base_meta(
89  problem,
90  problem.get_dimension(),
91  problem.get_i_dimension(),
92  problem.get_f_dimension(),
93  0,
94  0,
95  std::vector<double>()),
96  m_apply_penalty_1(false),
97  m_scaling_factor(0.0),
98  m_c_scaling(problem.get_c_dimension(),0.0),
99  m_f_hat_down(problem.get_f_dimension(),0.0),
100  m_f_hat_up(problem.get_f_dimension(),0.0),
101  m_f_hat_round(problem.get_f_dimension(),0.0),
102  m_i_hat_down(0.0),
103  m_i_hat_up(0.0),
104  m_i_hat_round(0.0),
105  m_map_fitness(),
106  m_map_constraint(),
107  m_decision_vector_hash()
108 {
109  population pop(*m_original_problem,0);
110 
111  if(m_original_problem->get_c_dimension() <= 0){
112  pagmo_throw(value_error,"The original problem has no constraints.");
113  }
114 
115  // check that the dimension of the problem is 1
116  if (m_original_problem->get_f_dimension() != 1) {
117  pagmo_throw(value_error,"The original fitness dimension of the problem must be one, multi objective problems can't be handled with self adaptive meta problem.");
118  }
119  update_penalty_coeff(pop);
120 }
121 
124 {
125  return base_ptr(new cstrs_self_adaptive(*this));
126 }
127 
130 
133 void cstrs_self_adaptive::objfun_impl(fitness_vector &f, const decision_vector &x) const
134 {
135  std::map<std::size_t, fitness_vector>::const_iterator it_f;
136  std::map<std::size_t, constraint_vector>::const_iterator it_c;
137 
138  double solution_infeasibility;
139 
140  it_f = m_map_fitness.find(m_decision_vector_hash(x));
141  if(it_f != m_map_fitness.end()) {
142  // we suppose that the constraints is also available
143  it_c = m_map_constraint.find(m_decision_vector_hash(x));
144 
145  f = it_f->second;
146 
147  solution_infeasibility = compute_solution_infeasibility(it_c->second);
148  } else {
149  // we compute the function f
150  m_original_problem->objfun(f, x);
151 
152  // we compute the constraints
153  constraint_vector c(m_original_problem->get_c_dimension(), 0.);
154  m_original_problem->compute_constraints(c,x);
155 
156  solution_infeasibility = compute_solution_infeasibility(c);
157  }
158 
159  if(solution_infeasibility > 0.) {
160  // apply penalty 1
161  if(m_apply_penalty_1) {
162  double inf_tilde = 0.;
163  inf_tilde = (solution_infeasibility - m_i_hat_down) /
164  (m_i_hat_up - m_i_hat_down);
165 
166  f[0] += inf_tilde * (m_f_hat_down[0] - m_f_hat_up[0]);
167  }
168 
169  // apply penalty 2
170  f[0] += m_scaling_factor * std::fabs(f[0]) * ( (std::exp(2. * solution_infeasibility) - 1.) / (std::exp(2.) - 1.) );
171  }
172 }
173 
175 
179 {
180  std::ostringstream oss;
181  oss << m_original_problem->human_readable_extra() << std::endl;
182  oss << "\n\tConstraints handled with self-adaptive method ";
183  oss << std::endl;
184  return oss.str();
185 }
186 
187 std::string cstrs_self_adaptive::get_name() const
188 {
189  return m_original_problem->get_name() + " [cstrs_self_adaptive]";
190 }
191 
194 
198 void cstrs_self_adaptive::update_penalty_coeff(const population &pop)
199 {
200  if(*m_original_problem != pop.problem()) {
201  pagmo_throw(value_error,"The problem linked to the population is not the same as the problem given in argument.");
202  }
203 
204  // Let's store some useful variables.
205  const population::size_type pop_size = pop.size();
206 
207  // Get out if there is nothing to do.
208  if (pop_size == 0) {
209  return;
210  }
211 
212  m_map_fitness.clear();
213  m_map_constraint.clear();
214  // store f and c in maps depending on the the x hash
215  for(population::size_type i=0; i<pop_size; i++) {
216  const population::individual_type &current_individual = pop.get_individual(i);
217  // m_map_fitness.insert(std::pair<std::size_t, fitness_vector>(m_decision_vector_hash(current_individual.cur_x),current_individual.cur_f));
218  m_map_fitness[m_decision_vector_hash(current_individual.cur_x)]=current_individual.cur_f;
219  m_map_constraint[m_decision_vector_hash(current_individual.cur_x)]=current_individual.cur_c;
220  }
221 
222  std::vector<population::size_type> feasible_idx(0);
223  std::vector<population::size_type> infeasible_idx(0);
224 
225  // store indexes of feasible and non feasible individuals
226  for(population::size_type i=0; i<pop_size; i++) {
227  const population::individual_type &current_individual = pop.get_individual(i);
228 
229  if(m_original_problem->feasibility_c(current_individual.cur_c)) {
230  feasible_idx.push_back(i);
231  } else {
232  infeasible_idx.push_back(i);
233  }
234  }
235 
236  // if the population is only feasible, then nothing is done
237  if(infeasible_idx.size() == 0) {
238  update_c_scaling(pop);
239  m_apply_penalty_1 = false;
240  m_scaling_factor = 0.;
241  return;
242  }
243  m_apply_penalty_1 = false;
244  m_scaling_factor = 0.;
245 
246  // updates the c_scaling, needed for solution infeasibility computation
247  update_c_scaling(pop);
248 
249  // evaluate solutions infeasibility
250  //compute_pop_solution_infeasibility(solution_infeasibility, pop);
251 
252  std::vector<double> solution_infeasibility(pop_size);
253  std::fill(solution_infeasibility.begin(),solution_infeasibility.end(),0.);
254 
255  // evaluate solutions infeasibility
256  solution_infeasibility.resize(pop_size);
257  std::fill(solution_infeasibility.begin(),solution_infeasibility.end(),0.);
258 
259  for(population::size_type i=0; i<pop_size; i++) {
260  const population::individual_type &current_individual = pop.get_individual(i);
261 
262  // compute the infeasibility of the constraint
263  solution_infeasibility[i] = compute_solution_infeasibility(current_individual.cur_c);
264  }
265 
266  // search position of x_hat_down, x_hat_up and x_hat_round
267  population::size_type hat_down_idx = -1;
268  population::size_type hat_up_idx = -1;
269  population::size_type hat_round_idx = -1;
270 
271  // first case, the population contains at least one feasible solution
272  if(feasible_idx.size() > 0) {
273  // initialize hat_down_idx
274  hat_down_idx = feasible_idx.at(0);
275 
276  // x_hat_down = feasible individual with lowest objective value in p
277  for(population::size_type i=0; i<feasible_idx.size(); i++) {
278  const population::size_type current_idx = feasible_idx.at(i);
279  const population::individual_type &current_individual = pop.get_individual(current_idx);
280 
281  if(m_original_problem->compare_fitness(current_individual.cur_f, pop.get_individual(hat_down_idx).cur_f)) {
282  hat_down_idx = current_idx;
283  }
284  }
285 
286  // hat down is now available
287  fitness_vector f_hat_down = pop.get_individual(hat_down_idx).cur_f;
288 
289  // x_hat_up value depends if the population contains infeasible individual with objective
290  // function better than f_hat_down
291  bool pop_contains_infeasible_f_better_x_hat_down = false;
292  for(population::size_type i=0; i<infeasible_idx.size(); i++) {
293  const population::size_type current_idx = infeasible_idx.at(i);
294  const population::individual_type &current_individual = pop.get_individual(current_idx);
295 
296  if(m_original_problem->compare_fitness(current_individual.cur_f, f_hat_down)) {
297  pop_contains_infeasible_f_better_x_hat_down = true;
298 
299  // initialize hat_up_idx
300  hat_up_idx = current_idx;
301 
302  break;
303  }
304  }
305 
306  if(pop_contains_infeasible_f_better_x_hat_down) {
307  // hat_up_idx is already initizalized
308 
309  // gets the individual with maximum infeasibility and objfun lower than f_hat_down
310  for(population::size_type i=0; i<infeasible_idx.size(); i++) {
311  const population::size_type current_idx = infeasible_idx.at(i);
312  const population::individual_type &current_individual = pop.get_individual(current_idx);
313 
314  if(m_original_problem->compare_fitness(current_individual.cur_f, f_hat_down) &&
315  (solution_infeasibility.at(current_idx) >= solution_infeasibility.at(hat_up_idx)) ) {
316 
317  if(solution_infeasibility.at(current_idx) == solution_infeasibility.at(hat_up_idx)) {
318  if(m_original_problem->compare_fitness(current_individual.cur_f, pop.get_individual(hat_up_idx).cur_f)) {
319  hat_up_idx = current_idx;
320  }
321  } else {
322  hat_up_idx = current_idx;
323  }
324  }
325  }
326 
327  // apply penalty 1
328  m_apply_penalty_1 = true;
329 
330  } else {
331  // all the infeasible soutions have an objective function value greater than f_hat_down
332  // the worst is the one that has the maximum infeasibility
333  // initialize hat_up_idx
334  hat_up_idx = infeasible_idx.at(0);
335 
336  for(population::size_type i=0; i<infeasible_idx.size(); i++) {
337  const population::size_type current_idx = infeasible_idx.at(i);
338  const population::individual_type &current_individual = pop.get_individual(current_idx);
339 
340  if(solution_infeasibility.at(current_idx) >= solution_infeasibility.at(hat_up_idx)) {
341  if(solution_infeasibility.at(current_idx) == solution_infeasibility.at(hat_up_idx)) {
342  if(m_original_problem->compare_fitness(pop.get_individual(hat_up_idx).cur_f, current_individual.cur_f)) {
343  hat_up_idx = current_idx;
344  }
345  } else {
346  hat_up_idx = current_idx;
347  }
348  }
349  }
350 
351  // do not apply penalty 1
352  m_apply_penalty_1 = false;
353  }
354 
355  } else { // case where there is no feasible solution in the population
356  // best is the individual with the lowest infeasibility
357  hat_down_idx = 0;
358  hat_up_idx = 0;
359 
360  for(population::size_type i=0; i<pop_size; i++) {
361  const population::individual_type &current_individual = pop.get_individual(i);
362 
363  if(solution_infeasibility.at(i) <= solution_infeasibility.at(hat_down_idx)) {
364  if(solution_infeasibility.at(i) == solution_infeasibility.at(hat_down_idx)) {
365  if(m_original_problem->compare_fitness(current_individual.cur_f, pop.get_individual(hat_down_idx).cur_f)) {
366  hat_down_idx = i;
367  }
368  } else {
369  hat_down_idx = i;
370  }
371  }
372  }
373 
374  // worst individual
375  for(population::size_type i=0; i<pop_size; i++) {
376  const population::individual_type &current_individual = pop.get_individual(i);
377 
378  if(solution_infeasibility.at(i) >= solution_infeasibility.at(hat_up_idx)) {
379  if(solution_infeasibility.at(i) == solution_infeasibility.at(hat_up_idx)) {
380  if(m_original_problem->compare_fitness(pop.get_individual(hat_up_idx).cur_f, current_individual.cur_f)) {
381  hat_up_idx = i;
382  }
383  } else {
384  hat_up_idx = i;
385  }
386  }
387  }
388 
389  // apply penalty 1 to the population
390  m_apply_penalty_1 = true;
391  }
392 
393  // stores the hat round idx, i.e. the solution with highest objective
394  // function value in the population
395  hat_round_idx = 0;
396  for(population::size_type i=0; i<pop_size; i++) {
397  const population::individual_type &current_individual = pop.get_individual(i);
398 
399  if(m_original_problem->compare_fitness(pop.get_individual(hat_round_idx).cur_f, current_individual.cur_f)) {
400  hat_round_idx = i;
401  }
402  }
403 
404  // get the objective function values of the three individuals
405  m_f_hat_round = pop.get_individual(hat_round_idx).cur_f;
406  m_f_hat_down = pop.get_individual(hat_down_idx).cur_f;
407  m_f_hat_up = pop.get_individual(hat_up_idx).cur_f;
408 
409  // get the solution infeasibility values of the three individuals
410  m_i_hat_round = solution_infeasibility.at(hat_round_idx);
411  m_i_hat_down = solution_infeasibility.at(hat_down_idx);
412  m_i_hat_up = solution_infeasibility.at(hat_up_idx);
413 
414  // computes the scaling factor
415  m_scaling_factor = 0.;
416  // evaluates scaling factor
417  if(m_original_problem->compare_fitness(m_f_hat_down, m_f_hat_up)) {
418  m_scaling_factor = (m_f_hat_round[0] - m_f_hat_up[0]) / m_f_hat_up[0];
419  } else {
420  m_scaling_factor = (m_f_hat_round[0] - m_f_hat_down[0]) / m_f_hat_down[0];
421  }
422  if(m_f_hat_up[0] == m_f_hat_round[0]) {
423  m_scaling_factor = 0.;
424  }
425 
426 }
427 
429 
433 void cstrs_self_adaptive::update_c_scaling(const population &pop)
434 {
435  if(*m_original_problem != pop.problem()) {
436  pagmo_throw(value_error,"The problem linked to the population is not the same as the problem given in argument.");
437  }
438 
439  // Let's store some useful variables.
440  const population::size_type pop_size = pop.size();
441 
442  // get the constraints dimension
443  //constraint_vector c(m_original_problem->get_c_dimension(), 0.);
444  problem::base::c_size_type prob_c_dimension = m_original_problem->get_c_dimension();
445  problem::base::c_size_type number_of_eq_constraints =
446  m_original_problem->get_c_dimension() -
447  m_original_problem->get_ic_dimension();
448 
449  const std::vector<double> &c_tol = m_original_problem->get_c_tol();
450 
451  m_c_scaling.resize(m_original_problem->get_c_dimension());
452  std::fill(m_c_scaling.begin(),m_c_scaling.end(),0.);
453 
454  // evaluates the scaling factor
455  for(population::size_type i=0; i<pop_size; i++) {
456  // updates the current constraint vector
457  const population::individual_type &current_individual = pop.get_individual(i);
458 
459  const constraint_vector &c = current_individual.cur_c;
460 
461  // computes scaling with the right definition of the constraints (can be in base problem? currently used
462  // by con2mo as well)
463  for(problem::base::c_size_type j=0; j<number_of_eq_constraints; j++) {
464  m_c_scaling[j] = std::max(m_c_scaling[j], std::max(0., (std::abs(c.at(j)) - c_tol.at(j))) );
465  }
466  for(problem::base::c_size_type j=number_of_eq_constraints; j<prob_c_dimension; j++) {
467  m_c_scaling[j] = std::max(m_c_scaling[j], std::max(0., c.at(j) - c_tol.at(j)) );
468  }
469  }
470 }
471 
474 
479 double cstrs_self_adaptive::compute_solution_infeasibility(const constraint_vector &c) const
480 {
481  // get the constraints dimension
482  problem::base::c_size_type prob_c_dimension = m_original_problem->get_c_dimension();
483  problem::base::c_size_type number_of_eq_constraints =
484  m_original_problem->get_c_dimension() -
485  m_original_problem->get_ic_dimension();
486 
487  double solution_infeasibility = 0.;
488 
489  const std::vector<double> &c_tol = m_original_problem->get_c_tol();
490 
491  // computes solution infeasibility with the right definition of the constraints (can be in base problem? currently used
492  // by con2mo as well)
493  for(problem::base::c_size_type j=0; j<number_of_eq_constraints; j++) {
494  // test needed otherwise the c_scaling can be 0, and division by 0 occurs
495  if(m_c_scaling[j] > 0.) {
496  solution_infeasibility += std::max(0.,(std::abs(c.at(j)) - c_tol.at(j))) / m_c_scaling[j];
497  }
498  }
499  for(problem::base::c_size_type j=number_of_eq_constraints; j<prob_c_dimension; j++) {
500  if(m_c_scaling[j] > 0.) {
501  solution_infeasibility += std::max(0.,c.at(j) - c_tol.at(j)) / m_c_scaling[j];
502  }
503  }
504 
505  solution_infeasibility /= prob_c_dimension;
506 
507  return solution_infeasibility;
508 }
509 }}
510 
512 
513 BOOST_CLASS_EXPORT_IMPLEMENT(pagmo::problem::cstrs_self_adaptive)
514 
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
STL namespace.
std::string human_readable_extra() const
Extra human readable algorithm info.
std::vector< double > fitness_vector
Fitness vector type.
Definition: types.h:42
std::vector< double > constraint_vector
Constraint vector type.
Definition: types.h:44
cstrs_self_adaptive(const base &=jde(), int gen=1, double=1e-15, double=1e-15)
Constructor.
container_type::size_type size_type
Population size type.
Definition: population.h:192
constraint_vector::size_type c_size_type
Constraints' size type: the same as pagmo::constraint_vector's size type.
Definition: problem/base.h:164
std::string get_name() const
Algorithm name.