OPAL (Object Oriented Parallel Accelerator Library)  2021.1.99
OPAL
Variator.h
Go to the documentation of this file.
1 //
2 // Class Variator
3 //
4 // Copyright (c) 2010 - 2013, Yves Ineichen, ETH Zürich
5 // All rights reserved
6 //
7 // Implemented as part of the PhD thesis
8 // "Toward massively parallel multi-objective optimization with application to
9 // particle accelerators" (https://doi.org/10.3929/ethz-a-009792359)
10 //
11 // This file is part of OPAL.
12 //
13 // OPAL is free software: you can redistribute it and/or modify
14 // it under the terms of the GNU General Public License as published by
15 // the Free Software Foundation, either version 3 of the License, or
16 // (at your option) any later version.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with OPAL. If not, see <https://www.gnu.org/licenses/>.
20 //
21 #ifndef __VARIATOR_H__
22 #define __VARIATOR_H__
23 
24 #include <string>
25 #include <vector>
26 #include <map>
27 #include <utility>
28 
29 #include "boost/smart_ptr.hpp"
30 
31 #include "Util/Types.h"
32 #include "Util/CmdArguments.h"
34 #include "Optimizer/Optimizer.h"
35 
36 #include "boost/property_tree/ptree.hpp"
37 #include "boost/property_tree/json_parser.hpp"
38 
39 template<
40  class ind_t
41  , template <class> class CrossoverOperator
42  , template <class> class MutationOperator
43 >
44 class Variator : public CrossoverOperator<ind_t>,
45  public MutationOperator<ind_t>
46 {
47 
48 public:
49 
50  Variator(std::vector<std::string> dNames,
51  Optimizer::bounds_t dVarBounds, Expressions::Named_t constraints,
52  CmdArguments_t args)
53  : dNames_m(dNames)
54  , dVarBounds_m(dVarBounds)
55  {
56  // add constraints, if only design variables are needed for evaluation
57  for(auto constraint : constraints) {
58  bool allDesignVariables = true;
59  std::set<std::string> req_vars = constraint.second->getReqVars();
60  if (req_vars.empty()) allDesignVariables = false;
61  for (std::string req_var : req_vars) {
62  // check if it is a design variable
63  if (std::find(dNames_m.begin(),dNames_m.end(),req_var) == dNames_m.end()) {
64  allDesignVariables = false;
65  break;
66  }
67  }
68  if (allDesignVariables == true)
69  constraints_m.insert(constraint);
70  }
71 
72  //FIXME: pass population as arg to variator
73  //boost::shared_ptr< Population<ind_t> >
74  population_m.reset(new Population<ind_t>());
75 
77  args->getArg<double>("mutation-probability", 0.5);
78 
80  args->getArg<double>("recombination-probability", 0.5);
81 
82  args_ = args;
83  }
84 
86  }
87 
88  //FIXME access population from outside
89  boost::shared_ptr< Population<ind_t> > population() {
90  return population_m;
91  }
92 
94  void initial_population(size_t sizeInitial, std::string fname) {
95  if ( fname.empty() ) {
96  for(size_t i = 0; i < sizeInitial; i++) {
98  }
99  return;
100  }
101  // read population from file
102  typedef boost::property_tree::ptree ptree_t;
103  ptree_t tree;
104 
105  boost::property_tree::read_json(fname, tree);
106 
107  if ( tree.get<std::string>("name").compare("opt-pilot") ) {
108  throw OptPilotException("Variator::initial_population",
109  "Json file not generated by opt-pilot.");
110  }
111 
112  std::size_t nDVars = 0;
113  for(auto& elem : tree.get_child("dvar-bounds")) {
114  // check if it is a design variable
115  if (std::find(dNames_m.begin(), dNames_m.end(), elem.first) == dNames_m.end()) {
116  throw OptPilotException("Variator::initial_population",
117  "The design variable '" + elem.first + "' is not in the list.");
118  }
119  ++nDVars;
120  }
121 
122  if ( nDVars != dVarBounds_m.size() ) {
123  throw OptPilotException("Variator::initial_population",
124  "The number of design variables do not agree.");
125  }
126 
127  boost::property_tree::ptree& population = tree.get_child("population");
128 
129  std::size_t size = 0;
130  Individual::genes_t dvars(nDVars);
131  for (auto& ind : population ) {
132 
133  if ( size > sizeInitial - 1 )
134  break;
135 
136  /* just to be sure: It might be that the order of the design variables in the
137  * Json file is not the same as it reads in, therefore, we check and take the order
138  * of the container dNames_m.
139  */
140  for (auto& dvar : population.get_child(ind.first).get_child("dvar")) {
141  auto it = std::find(dNames_m.begin(), dNames_m.end(), dvar.first);
142  std::size_t idx = std::distance(dNames_m.begin(), it);
143  //FIXME requires random access of Individual::genes_t
144  dvars[idx] = dvar.second.get_value<double>();
145  }
146 
147  new_individual(dvars);
148  ++size;
149  }
150 
151  // fill with random individuals
152  for (std::size_t i = size; i < sizeInitial; ++i) {
153  new_individual();
154  }
155  }
156 
158  void infeasible(boost::shared_ptr<ind_t> ind) {
159  population_m->remove_individual(ind);
160  new_individual();
161  }
162 
165  return !individualsToEvaluate_m.empty();
166  }
167 
169  boost::shared_ptr<ind_t> popIndividualToEvaluate() {
170  unsigned int ind = individualsToEvaluate_m.front();
172  return population_m->get_staging(ind);
173  }
174 
180  void variate(std::vector<unsigned int> parents) {
181 
182  // copying all individuals from parents
183  for(unsigned int parent : parents) {
184  new_individual( population_m->get_individual(parent) );
185  }
186 
187  // only variate new offspring, individuals in staging area have been
188  // variated already
189  std::queue<unsigned int> tmp(individualsToEvaluate_m);
190  while(!tmp.empty()) {
191 
192  // pop first individual
193  unsigned int idx = tmp.front(); tmp.pop();
194  boost::shared_ptr<ind_t> a = population_m->get_staging(idx);
195 
196  // handle special case where we have an odd number of offspring
197  if(tmp.empty()) {
198  if (drand(1) <= mutationProbability_m) {
199  // temporary copy in case not successful
200  boost::shared_ptr<ind_t> copyA(new ind_t(a));
201  int iter = 0;
202  while (true) {
203  // assign with shared pointer constructor
204  *a = copyA;
205  this->mutate(a, args_);
206  // check if viable offspring
207  if (a->viable()) break;
208 
209  iter++;
210  // if maximum number of tries then create new individual
211  if (iter > 100) {
212  infeasible(a);
213  break;
214  }
215  }
216  }
217  break;
218  }
219 
220  // and second if any
221  idx = tmp.front(); tmp.pop();
222  boost::shared_ptr<ind_t> b = population_m->get_staging(idx);
223 
224  // create new individuals
225 
226  // temporary copy in case not successful
227  boost::shared_ptr<ind_t> copyA(new ind_t(a));
228  boost::shared_ptr<ind_t> copyB(new ind_t(b));
229 
230  int iter = 0;
231  while (true) {
232  // assign with shared pointer constructor
233  *a = copyA;
234  *b = copyB;
235 
236  // do recombination
238  this->crossover(a, b, args_);
239  }
240 
241  // do mutation
242  if (drand(1) <= mutationProbability_m) {
243  this->mutate(a, args_);
244  this->mutate(b, args_);
245  }
246 
247  // check if viable offspring
248  bool viableA = a->viable();
249  bool viableB = b->viable();
250  if (viableA == true && viableB == true) {
251  break;
252  }
253  std::cout << "Individuals not viable, I try again: iter= " << iter << std::endl;
254  iter++;
255  // if maximum number of tries then create new individual(s)
256  if (iter > 100) {
257  if (viableA == false) {
258  infeasible(a);
259  }
260  if (viableB == false) {
261  infeasible(b);
262  }
263  break;
264  }
265  }
266  }
267  }
268 
269 
270 protected:
271 
274  boost::shared_ptr<ind_t> ind(new ind_t(dVarBounds_m, dNames_m, constraints_m));
275  std::swap(ind->genes_m, dvars);
276  individualsToEvaluate_m.push( population_m->add_individual(ind) );
277  }
278 
280  void new_individual() {
281  boost::shared_ptr<ind_t> ind(new ind_t(dVarBounds_m, dNames_m, constraints_m));
282  individualsToEvaluate_m.push( population_m->add_individual(ind) );
283  }
284 
286  void new_individual(boost::shared_ptr<ind_t> ind) {
287  boost::shared_ptr<ind_t> return_ind(new ind_t(ind));
289  population_m->add_individual(return_ind) ) ;
290  }
291 
292 private:
293 
295  boost::shared_ptr< Population<ind_t> > population_m;
296 
299 
301  std::queue<unsigned int> individualsToEvaluate_m;
302 
304  std::vector<std::string> dNames_m;
309 
314 
320  double drand(double range) {
321  return (range * (double) rand() / (RAND_MAX + 1.0));
322  }
323 };
324 
325 #endif
std::complex< double > a
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
boost::shared_ptr< CmdArguments > CmdArguments_t
Definition: CmdArguments.h:176
std::map< std::string, Expressions::Expr_t * > Named_t
type of an expressions with a name
Definition: Expression.h:74
const T * find(const T table[], const std::string &name)
Look up name.
Definition: TFind.h:34
std::vector< double > genes_t
representation of genes
Definition: Individual.h:43
CmdArguments_t args_
user specified command line arguments
Definition: Variator.h:298
boost::shared_ptr< Population< ind_t > > population_m
population of individuals
Definition: Variator.h:295
void new_individual()
create a new individual
Definition: Variator.h:280
Optimizer::bounds_t dVarBounds_m
bounds on design variables
Definition: Variator.h:306
boost::shared_ptr< ind_t > popIndividualToEvaluate()
return next individual to evaluate
Definition: Variator.h:169
~Variator()
Definition: Variator.h:85
double drand(double range)
Definition: Variator.h:320
double mutationProbability_m
probability of applying the mutation operator
Definition: Variator.h:311
void infeasible(boost::shared_ptr< ind_t > ind)
set an individual as infeasible: replace with a new individual
Definition: Variator.h:158
void new_individual(boost::shared_ptr< ind_t > ind)
copy an individual
Definition: Variator.h:286
boost::shared_ptr< Population< ind_t > > population()
Definition: Variator.h:89
Expressions::Named_t constraints_m
constraints
Definition: Variator.h:308
void new_individual(Individual::genes_t &dvars)
create a new individual
Definition: Variator.h:273
void variate(std::vector< unsigned int > parents)
Definition: Variator.h:180
Variator(std::vector< std::string > dNames, Optimizer::bounds_t dVarBounds, Expressions::Named_t constraints, CmdArguments_t args)
Definition: Variator.h:50
bool hasMoreIndividualsToEvaluate()
returns false if all individuals have been evaluated
Definition: Variator.h:164
std::vector< std::string > dNames_m
names of the design variables
Definition: Variator.h:304
std::queue< unsigned int > individualsToEvaluate_m
keep a queue of individuals that have to be evaluated
Definition: Variator.h:301
double recombinationProbability_m
probability of applying the recombination operator
Definition: Variator.h:313
void initial_population(size_t sizeInitial, std::string fname)
create an initial population
Definition: Variator.h:94
std::vector< std::pair< double, double > > bounds_t
type of bounds for design variables
Definition: Optimizer.h:39