PaGMO  1.1.5
hypervolume.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 "hypervolume.h"
26 #include "hv_algorithm/base.h"
27 #include "hv_algorithm/hv2d.h"
28 #include "hv_algorithm/hv3d.h"
29 #include "hv_algorithm/hv4d.h"
30 #include "hv_algorithm/wfg.h"
31 #include "hv_algorithm/bf_approx.h"
32 #include "hv_algorithm/bf_fpras.h"
33 #include "hv_algorithm/hoy.h"
34 #include "hv_algorithm/fpl.h"
35 
36 namespace pagmo { namespace util {
37 
39 
45 hypervolume::hypervolume(boost::shared_ptr<population> pop, const bool verify) : m_copy_points(true), m_verify(verify)
46  {
47  m_points.resize(pop->size());
48  for (population::size_type idx = 0 ; idx < pop->size() ; ++idx) {
49  m_points[idx] = fitness_vector(pop->get_individual(idx).cur_f);
50  }
51 
52  if (m_verify) {
53  verify_after_construct();
54  }
55 }
56 
58 
64 hypervolume::hypervolume(const std::vector<fitness_vector> &points, const bool verify) : m_points(points), m_copy_points(true), m_verify(verify)
65 {
66  if (m_verify) {
67  verify_after_construct();
68  }
69 }
70 
72 
77 hypervolume::hypervolume(const hypervolume &hv): m_points(hv.m_points), m_copy_points(hv.m_copy_points), m_verify(hv.m_verify) { }
78 
80 
84 hypervolume::hypervolume() : m_copy_points(true), m_verify(true)
85 {
86  m_points.resize(0);
87 }
88 
90 
99 void hypervolume::set_copy_points(const bool copy_points)
100 {
101  m_copy_points = copy_points;
102 }
103 
106 {
107  return m_copy_points;
108 }
109 
111 
120 void hypervolume::set_verify(const bool verify)
121 {
122  m_verify = verify;
123 }
124 
127 {
128  return m_verify;
129 }
130 
132 
137 void hypervolume::verify_after_construct() const
138 {
139  if ( m_points.size() == 0 ) {
140  pagmo_throw(value_error, "Point set cannot be empty.");
141  }
142  fitness_vector::size_type f_dim = m_points[0].size();
143  if (f_dim <= 1) {
144  pagmo_throw(value_error, "Points of dimension > 1 required.");
145  }
146  for (std::vector<fitness_vector>::size_type idx = 1 ; idx < m_points.size() ; ++idx) {
147  if ( m_points[idx].size() != f_dim ) {
148  pagmo_throw(value_error, "All point set dimensions must be equal.");
149  }
150  }
151 }
152 
154 
161 void hypervolume::verify_before_compute(const fitness_vector &r_point, hv_algorithm::base_ptr hv_algorithm) const
162 {
163  if ( m_points[0].size() != r_point.size() ) {
164  pagmo_throw(value_error, "Point set dimensions and reference point dimension must be equal.");
165  }
166  hv_algorithm->verify_before_compute(m_points, r_point);
167 }
168 
170 
174 hv_algorithm::base_ptr hypervolume::get_best_compute(const fitness_vector &r_point) const
175 {
176  unsigned int fdim = r_point.size();
177  unsigned int n = m_points.size();
178  if (fdim == 2) {
179  return hv_algorithm::hv2d().clone();
180  } else if (fdim == 3) {
181  return hv_algorithm::hv3d().clone();
182  } else if (fdim == 4) {
183  return hv_algorithm::hv4d().clone();
184  } else if (fdim == 5 && n < 80) {
185  return hv_algorithm::fpl().clone();
186  } else {
187  return hv_algorithm::wfg().clone();
188  }
189 }
190 
191 hv_algorithm::base_ptr hypervolume::get_best_exclusive(const unsigned int p_idx, const fitness_vector &r_point) const
192 {
193  (void)p_idx;
194  // Exclusive contribution and compute method share the same "best" set of algorithms.
195  return get_best_compute(r_point);
196 }
197 
198 hv_algorithm::base_ptr hypervolume::get_best_contributions(const fitness_vector &r_point) const
199 {
200  unsigned int fdim = r_point.size();
201  if (fdim == 2) {
202  return hv_algorithm::hv2d().clone();
203  } else if (fdim == 3) {
204  return hv_algorithm::hv3d().clone();
205  } else {
206  return hv_algorithm::wfg().clone();
207  }
208 }
209 
211 
219 double hypervolume::compute(const fitness_vector &r_point, hv_algorithm::base_ptr hv_algorithm) const
220 {
221  if (m_verify) {
222  verify_before_compute(r_point, hv_algorithm);
223  }
224 
225  // copy the initial set of points, as the algorithm may alter its contents
226  if (m_copy_points) {
227  std::vector<fitness_vector> points_cpy(m_points.begin(), m_points.end());
228  return hv_algorithm->compute(points_cpy, r_point);
229  } else {
230  return hv_algorithm->compute(const_cast<std::vector<fitness_vector> &>(m_points), r_point);
231  }
232 }
233 
235 
243 double hypervolume::compute(const fitness_vector &r_point) const
244 {
245  return compute(r_point, get_best_compute(r_point));
246 }
247 
249 
258 double hypervolume::exclusive(const unsigned int p_idx, const fitness_vector &r_point, hv_algorithm::base_ptr hv_algorithm) const
259 {
260  if (m_verify) {
261  verify_before_compute(r_point, hv_algorithm);
262  }
263 
264  if (p_idx >= m_points.size()) {
265  pagmo_throw(value_error, "Index of the individual is out of bounds.");
266 
267  }
268 
269  // copy the initial set of points, as the algorithm may alter its contents
270  if (m_copy_points) {
271  std::vector<fitness_vector> points_cpy(m_points.begin(), m_points.end());
272  return hv_algorithm->exclusive(p_idx, points_cpy, r_point);
273  } else {
274  return hv_algorithm->exclusive(p_idx, const_cast<std::vector<fitness_vector> &>(m_points), r_point);
275  }
276 }
277 
279 
288 double hypervolume::exclusive(const unsigned int p_idx, const fitness_vector &r_point) const
289 {
290  return exclusive(p_idx, r_point, get_best_exclusive(p_idx, r_point));
291 }
292 
294 
302 unsigned int hypervolume::least_contributor(const fitness_vector &r_point, hv_algorithm::base_ptr hv_algorithm) const
303 {
304  if (m_verify) {
305  verify_before_compute(r_point, hv_algorithm);
306  }
307 
308  // Trivial case
309  if (m_points.size() == 1) {
310  return 0;
311  }
312 
313  // copy the initial set of points, as the algorithm may alter its contents
314  if (m_copy_points) {
315  std::vector<fitness_vector> points_cpy(m_points.begin(), m_points.end());
316  return hv_algorithm->least_contributor(points_cpy, r_point);
317  } else {
318  return hv_algorithm->least_contributor(const_cast<std::vector<fitness_vector> &>(m_points), r_point);
319  }
320 }
321 
323 
331 unsigned int hypervolume::least_contributor(const fitness_vector &r_point) const
332 {
333  return least_contributor(r_point, get_best_contributions(r_point));
334 }
335 
337 
345 unsigned int hypervolume::greatest_contributor(const fitness_vector &r_point, hv_algorithm::base_ptr hv_algorithm) const
346 {
347  if (m_verify) {
348  verify_before_compute(r_point, hv_algorithm);
349  }
350 
351  // copy the initial set of points, as the algorithm may alter its contents
352  if (m_copy_points) {
353  std::vector<fitness_vector> points_cpy(m_points.begin(), m_points.end());
354  return hv_algorithm->greatest_contributor(points_cpy, r_point);
355  } else {
356  return hv_algorithm->greatest_contributor(const_cast<std::vector<fitness_vector> &>(m_points), r_point);
357  }
358 }
359 
361 
369 unsigned int hypervolume::greatest_contributor(const fitness_vector &r_point) const
370 {
371  return greatest_contributor(r_point, get_best_contributions(r_point));
372 }
373 
375 
383 std::vector<double> hypervolume::contributions(const fitness_vector &r_point, const hv_algorithm::base_ptr hv_algorithm) const
384 {
385  if (m_verify) {
386  verify_before_compute(r_point, hv_algorithm);
387  }
388 
389  // Trivial case
390  if (m_points.size() == 1) {
391  std::vector<double> c;
392  c.push_back(hv_algorithm::base::volume_between(m_points[0], r_point));
393  return c;
394  }
395 
396  // copy the initial set of points, as the algorithm may alter its contents
397  if (m_copy_points) {
398  std::vector<fitness_vector> points_cpy(m_points.begin(), m_points.end());
399  return hv_algorithm->contributions(points_cpy, r_point);
400  } else {
401  return hv_algorithm->contributions(const_cast<std::vector<fitness_vector> &>(m_points), r_point);
402  }
403 }
404 
406 
414 std::vector<double> hypervolume::contributions(const fitness_vector &r_point) const
415 {
416  return contributions(r_point, get_best_contributions(r_point));
417 }
418 
420 
429 double hypervolume::get_expected_operations(const unsigned int n, const unsigned int d)
430 {
431  if (d <= 3) {
432  return d * n * log(n); // hv3d
433  } else if (d == 4) {
434  return 4.0 * n * n; // hv4d
435  } else {
436  return 0.0005 * d * pow(n, d * 0.5); // exponential complexity
437  }
438 }
439 
441 
448 fitness_vector hypervolume::get_nadir_point(const double epsilon) const
449 {
450  fitness_vector nadir_point(m_points[0].begin(), m_points[0].end());
451  for (std::vector<fitness_vector>::size_type idx = 1 ; idx < m_points.size() ; ++ idx){
452  for (fitness_vector::size_type f_idx = 0 ; f_idx < m_points[0].size() ; ++f_idx){
453  // assuming minimization problem, thus maximum value by each dimension is taken
454  nadir_point[f_idx] = std::max(nadir_point[f_idx], m_points[idx][f_idx]);
455  }
456  }
457  for (fitness_vector::size_type f_idx = 0 ; f_idx < nadir_point.size() ; ++f_idx) {
458  nadir_point[f_idx] += epsilon;
459  }
460  return nadir_point;
461 }
462 
463 
465 
470 const std::vector<fitness_vector> hypervolume::get_points() const
471 {
472  return m_points;
473 }
474 
476 
482 {
483  return hypervolume_ptr(new hypervolume(*this));
484 }
485 
486 }}
Root PaGMO namespace.
bool get_verify()
Getter for the 'verify' flag.
double compute(const fitness_vector &, const hv_algorithm::base_ptr) const
Compute hypervolume.
boost::shared_ptr< hypervolume > hypervolume_ptr
Alias for the shared pointer to a pagmo::util::hypervolume.
Definition: hypervolume.h:37
static double volume_between(const fitness_vector &, const fitness_vector &, unsigned int=0)
Compute volume between two points.
hypervolume_ptr clone() const
Clone method.
bool get_copy_points()
Getter for 'copy_points' flag.
unsigned int least_contributor(const fitness_vector &, const hv_algorithm::base_ptr) const
Find the least contributing individual.
void set_verify(const bool)
Setter for the 'verify' flag.
static double get_expected_operations(const unsigned int n, const unsigned int d)
Get expected numer of operations.
std::vector< double > contributions(const fitness_vector &, const hv_algorithm::base_ptr) const
Contributions method.
fitness_vector get_nadir_point(const double epsilon=0.0) const
Calculate the nadir point.
std::vector< double > fitness_vector
Fitness vector type.
Definition: types.h:42
boost::shared_ptr< base > base_ptr
Base hypervolume algorithm class.
hypervolume()
Default constructor.
Definition: hypervolume.cpp:84
const std::vector< fitness_vector > get_points() const
Get points.
container_type::size_type size_type
Population size type.
Definition: population.h:192
unsigned int greatest_contributor(const fitness_vector &, const hv_algorithm::base_ptr) const
Find the most contributing individual.
Hypervolume class.
Definition: hypervolume.h:49
double exclusive(const unsigned int, const fitness_vector &, const hv_algorithm::base_ptr) const
Compute exclusive contribution.
void set_copy_points(const bool)
Setter for 'copy_points' flag.
Definition: hypervolume.cpp:99