OPAL (Object Oriented Parallel Accelerator Library)  2024.1
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 "Util/Types.h"
30 #include "Util/CmdArguments.h"
32 #include "Optimizer/Optimizer.h"
33 
34 #include "boost/property_tree/ptree.hpp"
35 #include "boost/property_tree/json_parser.hpp"
36 
37 template<
38  class ind_t
39  , template <class> class CrossoverOperator
40  , template <class> class MutationOperator
41 >
42 class Variator : public CrossoverOperator<ind_t>,
43  public MutationOperator<ind_t>
44 {
45 
46 public:
47 
48  Variator(std::vector<std::string> dNames,
49  Optimizer::bounds_t dVarBounds, Expressions::Named_t constraints,
50  CmdArguments_t args)
51  : dNames_m(dNames)
52  , dVarBounds_m(dVarBounds)
53  {
54  // add constraints, if only design variables are needed for evaluation
55  for(auto constraint : constraints) {
56  bool allDesignVariables = true;
57  std::set<std::string> req_vars = constraint.second->getReqVars();
58  if (req_vars.empty()) allDesignVariables = false;
59  for (std::string req_var : req_vars) {
60  // check if it is a design variable
61  if (std::find(dNames_m.begin(),dNames_m.end(),req_var) == dNames_m.end()) {
62  allDesignVariables = false;
63  break;
64  }
65  }
66  if (allDesignVariables == true)
67  constraints_m.insert(constraint);
68  }
69 
70  //FIXME: pass population as arg to variator
71  //std::shared_ptr< Population<ind_t> >
72  population_m.reset(new Population<ind_t>());
73 
75  args->getArg<double>("mutation-probability", 0.5);
76 
78  args->getArg<double>("recombination-probability", 0.5);
79 
80  args_ = args;
81  }
82 
84  }
85 
86  //FIXME access population from outside
87  std::shared_ptr< Population<ind_t> > population() {
88  return population_m;
89  }
90 
92  void initial_population(size_t sizeInitial, std::string fname) {
93  if ( fname.empty() ) {
94  for(size_t i = 0; i < sizeInitial; i++) {
96  }
97  return;
98  }
99  // read population from file
100  typedef boost::property_tree::ptree ptree_t;
101  ptree_t tree;
102 
103  boost::property_tree::read_json(fname, tree);
104 
105  if ( tree.get<std::string>("name").compare("opt-pilot") ) {
106  throw OptPilotException("Variator::initial_population",
107  "Json file not generated by opt-pilot.");
108  }
109 
110  std::size_t nDVars = 0;
111  for(auto& elem : tree.get_child("dvar-bounds")) {
112  // check if it is a design variable
113  if (std::find(dNames_m.begin(), dNames_m.end(), elem.first) == dNames_m.end()) {
114  throw OptPilotException("Variator::initial_population",
115  "The design variable '" + elem.first + "' is not in the list.");
116  }
117  ++nDVars;
118  }
119 
120  if ( nDVars != dVarBounds_m.size() ) {
121  throw OptPilotException("Variator::initial_population",
122  "The number of design variables do not agree.");
123  }
124 
125  boost::property_tree::ptree& population = tree.get_child("population");
126 
127  std::size_t size = 0;
128  Individual::genes_t dvars(nDVars);
129  for (auto& ind : population ) {
130 
131  if ( size > sizeInitial - 1 )
132  break;
133 
134  /* just to be sure: It might be that the order of the design variables in the
135  * Json file is not the same as it reads in, therefore, we check and take the order
136  * of the container dNames_m.
137  */
138  for (auto& dvar : population.get_child(ind.first).get_child("dvar")) {
139  auto it = std::find(dNames_m.begin(), dNames_m.end(), dvar.first);
140  std::size_t idx = std::distance(dNames_m.begin(), it);
141  //FIXME requires random access of Individual::genes_t
142  dvars[idx] = dvar.second.get_value<double>();
143  }
144 
145  new_individual(dvars);
146  ++size;
147  }
148 
149  // fill with random individuals
150  for (std::size_t i = size; i < sizeInitial; ++i) {
151  new_individual();
152  }
153  }
154 
156  void infeasible(std::shared_ptr<ind_t> ind) {
157  population_m->remove_individual(ind);
158  new_individual();
159  }
160 
163  return !individualsToEvaluate_m.empty();
164  }
165 
167  std::shared_ptr<ind_t> popIndividualToEvaluate() {
168  unsigned int ind = individualsToEvaluate_m.front();
170  return population_m->get_staging(ind);
171  }
172 
178  void variate(std::vector<unsigned int> parents) {
179 
180  // copying all individuals from parents
181  for(unsigned int parent : parents) {
182  new_individual( population_m->get_individual(parent) );
183  }
184 
185  // only variate new offspring, individuals in staging area have been
186  // variated already
187  std::queue<unsigned int> tmp(individualsToEvaluate_m);
188  while(!tmp.empty()) {
189 
190  // pop first individual
191  unsigned int idx = tmp.front(); tmp.pop();
192  std::shared_ptr<ind_t> a = population_m->get_staging(idx);
193 
194  // handle special case where we have an odd number of offspring
195  if(tmp.empty()) {
196  if (drand(1) <= mutationProbability_m) {
197  // temporary copy in case not successful
198  std::shared_ptr<ind_t> copyA(new ind_t(a));
199  int iter = 0;
200  while (true) {
201  // assign with shared pointer constructor
202  *a = copyA;
203  this->mutate(a, args_);
204  // check if viable offspring
205  if (a->viable()) break;
206 
207  iter++;
208  // if maximum number of tries then create new individual
209  if (iter > 100) {
210  infeasible(a);
211  break;
212  }
213  }
214  }
215  break;
216  }
217 
218  // and second if any
219  idx = tmp.front(); tmp.pop();
220  std::shared_ptr<ind_t> b = population_m->get_staging(idx);
221 
222  // create new individuals
223 
224  // temporary copy in case not successful
225  std::shared_ptr<ind_t> copyA(new ind_t(a));
226  std::shared_ptr<ind_t> copyB(new ind_t(b));
227 
228  int iter = 0;
229  while (true) {
230  // assign with shared pointer constructor
231  *a = copyA;
232  *b = copyB;
233 
234  // do recombination
236  this->crossover(a, b, args_);
237  }
238 
239  // do mutation
240  if (drand(1) <= mutationProbability_m) {
241  this->mutate(a, args_);
242  this->mutate(b, args_);
243  }
244 
245  // check if viable offspring
246  bool viableA = a->viable();
247  bool viableB = b->viable();
248  if (viableA == true && viableB == true) {
249  break;
250  }
251  std::cout << "Individuals not viable, I try again: iter= " << iter << std::endl;
252  iter++;
253  // if maximum number of tries then create new individual(s)
254  if (iter > 100) {
255  if (viableA == false) {
256  infeasible(a);
257  }
258  if (viableB == false) {
259  infeasible(b);
260  }
261  break;
262  }
263  }
264  }
265  }
266 
267 
268 protected:
269 
272  std::shared_ptr<ind_t> ind(new ind_t(dVarBounds_m, dNames_m, constraints_m));
273  std::swap(ind->genes_m, dvars);
274  individualsToEvaluate_m.push( population_m->add_individual(ind) );
275  }
276 
278  void new_individual() {
279  std::shared_ptr<ind_t> ind(new ind_t(dVarBounds_m, dNames_m, constraints_m));
280  individualsToEvaluate_m.push( population_m->add_individual(ind) );
281  }
282 
284  void new_individual(std::shared_ptr<ind_t> ind) {
285  std::shared_ptr<ind_t> return_ind(new ind_t(ind));
287  population_m->add_individual(return_ind) ) ;
288  }
289 
290 private:
291 
293  std::shared_ptr< Population<ind_t> > population_m;
294 
297 
299  std::queue<unsigned int> individualsToEvaluate_m;
300 
302  std::vector<std::string> dNames_m;
307 
312 
318  double drand(double range) {
319  return (range * (double) rand() / (RAND_MAX + 1.0));
320  }
321 };
322 
323 #endif
std::shared_ptr< Population< ind_t > > population_m
population of individuals
Definition: Variator.h:293
void new_individual(std::shared_ptr< ind_t > ind)
copy an individual
Definition: Variator.h:284
void new_individual()
create a new individual
Definition: Variator.h:278
std::vector< double > genes_t
representation of genes
Definition: Individual.h:41
and that you know you can do these things To protect your we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights These restrictions translate to certain responsibilities for you if you distribute copies of the or if you modify it For if you distribute copies of such a whether gratis or for a you must give the recipients all the rights that you have You must make sure that receive or can get the source code And you must show them these terms so they know their rights We protect your rights with two distribute and or modify the software for each author s protection and we want to make certain that everyone understands that there is no warranty for this free software If the software is modified by someone else and passed we want its recipients to know that what they have is not the so that any problems introduced by others will not reflect on the original authors reputations any free program is threatened constantly by software patents We wish to avoid the danger that redistributors of a free program will individually obtain patent in effect making the program proprietary To prevent we have made it clear that any patent must be licensed for everyone s free use or not licensed at all The precise terms and conditions for distribution and modification follow GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR DISTRIBUTION AND MODIFICATION This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License The refers to any such program or and a work based on the Program means either the Program or any derivative work under copyright a work containing the Program or a portion of it
Definition: LICENSE:43
double mutationProbability_m
probability of applying the mutation operator
Definition: Variator.h:309
Optimizer::bounds_t dVarBounds_m
bounds on design variables
Definition: Variator.h:304
void new_individual(Individual::genes_t &dvars)
create a new individual
Definition: Variator.h:271
void initial_population(size_t sizeInitial, std::string fname)
create an initial population
Definition: Variator.h:92
Expressions::Named_t constraints_m
constraints
Definition: Variator.h:306
~Variator()
Definition: Variator.h:83
void variate(std::vector< unsigned int > parents)
Definition: Variator.h:178
double drand(double range)
Definition: Variator.h:318
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
std::shared_ptr< Population< ind_t > > population()
Definition: Variator.h:87
std::map< std::string, Expressions::Expr_t * > Named_t
type of an expressions with a name
Definition: Expression.h:74
Variator(std::vector< std::string > dNames, Optimizer::bounds_t dVarBounds, Expressions::Named_t constraints, CmdArguments_t args)
Definition: Variator.h:48
const T * find(const T table[], const std::string &name)
Look up name.
Definition: TFind.h:34
std::vector< std::pair< double, double > > bounds_t
type of bounds for design variables
Definition: Optimizer.h:39
std::queue< unsigned int > individualsToEvaluate_m
keep a queue of individuals that have to be evaluated
Definition: Variator.h:299
std::vector< std::string > dNames_m
names of the design variables
Definition: Variator.h:302
std::shared_ptr< CmdArguments > CmdArguments_t
Definition: CmdArguments.h:176
double recombinationProbability_m
probability of applying the recombination operator
Definition: Variator.h:311
std::shared_ptr< ind_t > popIndividualToEvaluate()
return next individual to evaluate
Definition: Variator.h:167
CmdArguments_t args_
user specified command line arguments
Definition: Variator.h:296
bool hasMoreIndividualsToEvaluate()
returns false if all individuals have been evaluated
Definition: Variator.h:162
void infeasible(std::shared_ptr< ind_t > ind)
set an individual as infeasible: replace with a new individual
Definition: Variator.h:156