PaGMO  1.1.5
decompose.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 <boost/random/uniform_real.hpp>
27 
28 #include "../exceptions.h"
29 #include "../types.h"
30 #include "../population.h"
31 #include "../rng.h"
32 #include "decompose.h"
33 
34 namespace pagmo { namespace problem {
35 
36 
50 decompose::decompose(const base & p, method_type method, const std::vector<double> & weights, const std::vector<double> & z, const bool adapt_ideal):
51  base_meta(
52  p,
53  p.get_dimension(), // Ambiguous without the cast ...
54  p.get_i_dimension(),
55  1, //it transforms the problem into a single-objective problem
56  p.get_c_dimension(),
57  p.get_ic_dimension(),
58  p.get_c_tol()),
59  m_method(method),
60  m_weights(weights),
61  m_z(z),
62  m_adapt_ideal(adapt_ideal)
63 {
64 
65  //0 - Check whether method is implemented
66  if(m_method != WEIGHTED && m_method != TCHEBYCHEFF && m_method != BI) {
67  pagmo_throw(value_error,"non existing decomposition method");
68  }
69 
70  if (p.get_f_dimension() == 1) {
71  pagmo_throw(value_error,"decompose works only for multi-objective problems, you are trying to decompose a single objective one.");
72  }
73 
74  //1 - Checks whether the weight vector has a dimension, if not, sets its default value
75  if (m_weights.size() == 0) {
76  //Initialise a random weight vector
77  rng_double m_drng = rng_generator::get<rng_double>();
78  m_weights = std::vector<double>((int)p.get_f_dimension(), 0.0);
79  double sum = 0;
80  for(std::vector<double>::size_type i = 0; i<m_weights.size(); ++i) {
81  m_weights[i] = (1-sum) * (1 - pow(boost::uniform_real<double>(0,1)(m_drng), 1.0 / (m_weights.size() - i - 1)));
82  sum += m_weights[i];
83  }
84  } else {
85 
86  //1.1 - Checks whether the weight has lenght equal to the fitness size
87  if (m_weights.size() != p.get_f_dimension()) {
88  pagmo_throw(value_error,"the weight vector must have length equal to the fitness size");
89  }
90 
91  //1.2 - Checks whether the weight vector sums to 1
92  double sum = 0.0;
93  for (std::vector<double>::size_type i=0; i<m_weights.size(); ++i) {
94  sum += m_weights[i];
95  }
96  if (fabs(sum-1.0) > 1E-8) {
97  pagmo_throw(value_error,"the weight vector should sum to 1 with a tolerance of E1-8");
98  }
99 
100  //1.4 - Checks that all weights are positive
101  for (std::vector<double>::size_type i=0; i<m_weights.size(); ++i) {
102  if (m_weights[i] < 0) {
103  pagmo_throw(value_error,"the weight vector should contain only positive values");
104  }
105  }
106  }
107 
108  //2 - Checks whether the reference point has a dimension, if not, sets its default value m_z = (0, ..., 0)
109  if (m_z.size() == 0) {
110  m_z = std::vector<double>((int)p.get_f_dimension(), 0.0); //by default m_z = (0, ..., 0)
111  } else {
112  //2.1 - Checks whether the reference point has lenght equal to the fitness size
113  if (m_z.size() != p.get_f_dimension()) {
114  pagmo_throw(value_error,"the the reference point vector must have equal length to the fitness size");
115  }
116  }
117 }
118 
121 {
122  return base_ptr(new decompose(*this));
123 }
124 
127 {
128  fitness_vector fit(m_original_problem->get_f_dimension());
129  compute_original_fitness(fit, x);
130  compute_decomposed_fitness(f, fit,m_weights);
131 }
132 
135  return m_z;
136 }
137 
140  m_z = f;
141 }
142 
144 
152  m_original_problem->objfun(f,x);
153  if (m_adapt_ideal) {
154  for (fitness_vector::size_type i=0; i<f.size(); ++i) {
155  if (f[i] < m_z[i]) m_z[i] = f[i];
156  }
157  }
158 }
159 
161 
168 {
169  compute_decomposed_fitness(f, original_fit,m_weights);
170 }
171 
173 
180 void decompose::compute_decomposed_fitness(fitness_vector &f, const fitness_vector &original_fit, const fitness_vector &weights) const
181 {
182  if ( (m_weights.size() != weights.size()) || (original_fit.size() != m_weights.size()) ) {
183  pagmo_throw(value_error,"Check the sizes of input weights and fitness vector");
184  }
185  if(m_method == WEIGHTED) {
186  f[0] = 0.0;
187  for(base::f_size_type i = 0; i < m_original_problem->get_f_dimension(); ++i) {
188  f[0]+= weights[i]*original_fit[i];
189  }
190  } else if (m_method == TCHEBYCHEFF) {
191  f[0] = 0.0;
192  double tmp,weight;
193  for(base::f_size_type i = 0; i < m_original_problem->get_f_dimension(); ++i) {
194  (weights[i]==0) ? (weight = 1e-4) : (weight = weights[i]); //fixes the numerical problem of 0 weights
195  tmp = weight * fabs(original_fit[i] - m_z[i]);
196  if(tmp > f[0]) {
197  f[0] = tmp;
198  }
199  }
200  } else { //BI method
201  const double THETA = 5.0;
202  double d1 = 0.0;
203  double weight_norm = 0.0;
204  for(base::f_size_type i = 0; i < m_original_problem->get_f_dimension(); ++i) {
205  d1 += (original_fit[i] - m_z[i]) * weights[i];
206  weight_norm += pow(weights[i],2);
207  }
208  weight_norm = sqrt(weight_norm);
209  d1 = fabs(d1)/weight_norm;
210 
211  double d2 = 0.0;
212  for(base::f_size_type i = 0; i < m_original_problem->get_f_dimension(); ++i) {
213  d2 += pow(original_fit[i] - (m_z[i] + d1*weights[i]/weight_norm), 2);
214  }
215  d2 = sqrt(d2);
216 
217  f[0] = d1 + THETA * d2;
218  }
219 }
220 
221 std::string decompose::get_name() const
222 {
223  return m_original_problem->get_name() + " [Decomposed]";
224 }
225 
227 {
228  std::ostringstream oss;
229  oss << m_original_problem->human_readable_extra() << std::endl;
230  oss << "\n\tDecomposition method: ";
231  switch(m_method){
232  case WEIGHTED: {
233  oss << "Weighted ";
234  break;
235  }
236  case BI: {
237  oss << "Boundary Interception ";
238  break;
239  }
240  case TCHEBYCHEFF: {
241  oss << "Tchebycheff ";
242  break;
243  }
244  }
245  oss << std::endl << "\tWeight vector: " << m_weights << std::endl;
246  oss << "\tReference point: " << m_z << std::endl;
247  return oss.str();
248 }
249 
250 
256 const std::vector<double>& decompose::get_weights() const
257 {
258  return m_weights;
259 }
260 }}
261 
262 BOOST_CLASS_EXPORT_IMPLEMENT(pagmo::problem::decompose)
Root PaGMO namespace.
boost::shared_ptr< base > base_ptr
Alias for shared pointer to base problem.
Definition: problem/base.h:62
std::vector< double > decision_vector
Decision vector type.
Definition: types.h:40
decompose(const base &=zdt(1, 2), method_type=WEIGHTED, const std::vector< double > &=std::vector< double >(), const std::vector< double > &=std::vector< double >(), const bool=false)
Definition: decompose.cpp:50
Decompose meta-problem.
Definition: decompose.h:62
void set_ideal_point(const fitness_vector &f)
Sets the ideal point.
Definition: decompose.cpp:139
const std::vector< double > & get_weights() const
Definition: decompose.cpp:256
fitness_vector::size_type f_size_type
Fitness' size type: the same as pagmo::fitness_vector's size type.
Definition: problem/base.h:162
Base problem class.
Definition: problem/base.h:148
std::string get_name() const
Get problem's name.
Definition: decompose.cpp:221
fitness_vector get_ideal_point() const
Gets the ideal point.
Definition: decompose.cpp:134
The Boundary Intersection method is used to perform the decomposition.
Definition: decompose.h:69
Meta=problems base class.
Definition: base_meta.h:50
void compute_original_fitness(fitness_vector &, const decision_vector &) const
Computes the original fitness.
Definition: decompose.cpp:151
void objfun_impl(fitness_vector &, const decision_vector &) const
Implementation of the objective function.
Definition: decompose.cpp:126
void compute_decomposed_fitness(fitness_vector &, const fitness_vector &) const
Computes the decomposed fitness.
Definition: decompose.cpp:167
std::vector< double > fitness_vector
Fitness vector type.
Definition: types.h:42
std::string human_readable_extra() const
Extra information in human readable format.
Definition: decompose.cpp:226
method_type
Mechanism used to perform the problem decomposition.
Definition: decompose.h:66
f_size_type get_f_dimension() const
Return fitness dimension.
The fitness function is the weighted sum of the multiple original fitnesses.
Definition: decompose.h:67
The Tchebycheff method is used to perform the decomposition.
Definition: decompose.h:68
base_ptr clone() const
Clone method.
Definition: decompose.cpp:120
This rng returns a double in the [0,1[ range.
Definition: rng.h:89
base_ptr m_original_problem
Smart pointer to the original problem instance.
Definition: base_meta.h:80