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