OPAL (Object Oriented Parallel Accelerator Library) 2022.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 "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
39template<
40 class ind_t
41 , template <class> class CrossoverOperator
42 , template <class> class MutationOperator
43>
44class Variator : public CrossoverOperator<ind_t>,
45 public MutationOperator<ind_t>
46{
47
48public:
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> >
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) {
154 }
155 }
156
158 void infeasible(boost::shared_ptr<ind_t> ind) {
159 population_m->remove_individual(ind);
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
270protected:
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
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
292private:
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< Population< ind_t > > population()
Definition: Variator.h:89
~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
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
boost::shared_ptr< ind_t > popIndividualToEvaluate()
return next individual to evaluate
Definition: Variator.h:169
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