OPAL (Object Oriented Parallel Accelerator Library) 2024.2
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 <cstdlib>
25#include <map>
26#include <memory>
27#include <set>
28#include <string>
29#include <utility>
30#include <vector>
31
32#include "Util/Types.h"
33#include "Util/CmdArguments.h"
35#include "Optimizer/Optimizer.h"
36
37#include "boost/property_tree/ptree.hpp"
38#include "boost/property_tree/json_parser.hpp"
39
40template<
41 class ind_t
42 , template <class> class CrossoverOperator
43 , template <class> class MutationOperator
44>
45class Variator : public CrossoverOperator<ind_t>,
46 public MutationOperator<ind_t>
47{
48
49public:
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 //std::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 std::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(std::shared_ptr<ind_t> ind) {
159 population_m->remove_individual(ind);
161 }
162
165 return !individualsToEvaluate_m.empty();
166 }
167
169 std::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 std::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 std::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 std::shared_ptr<ind_t> b = population_m->get_staging(idx);
223
224 // create new individuals
225
226 // temporary copy in case not successful
227 std::shared_ptr<ind_t> copyA(new ind_t(a));
228 std::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
269protected:
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
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
290private:
292 std::shared_ptr< Population<ind_t> > population_m;
293
296
298 std::queue<unsigned int> individualsToEvaluate_m;
299
301 std::vector<std::string> dNames_m;
306
311
317 double drand(double range) {
318 return (range * (double) std::rand() / (RAND_MAX + 1.0));
319 }
320};
321
322#endif
std::complex< double > a
std::shared_ptr< CmdArguments > CmdArguments_t
std::map< std::string, Expressions::Expr_t * > Named_t
type of an expressions with a name
Definition Expression.h:68
std::vector< double > genes_t
representation of genes
Definition Individual.h:46
CmdArguments_t args_
user specified command line arguments
Definition Variator.h:295
void new_individual()
create a new individual
Definition Variator.h:278
Optimizer::bounds_t dVarBounds_m
bounds on design variables
Definition Variator.h:303
~Variator()
Definition Variator.h:85
double drand(double range)
Definition Variator.h:317
double mutationProbability_m
probability of applying the mutation operator
Definition Variator.h:308
std::shared_ptr< Population< ind_t > > population()
Definition Variator.h:89
void infeasible(std::shared_ptr< ind_t > ind)
set an individual as infeasible: replace with a new individual
Definition Variator.h:158
Expressions::Named_t constraints_m
constraints
Definition Variator.h:305
void new_individual(Individual::genes_t &dvars)
create a new individual
Definition Variator.h:271
void variate(std::vector< unsigned int > parents)
Definition Variator.h:180
void new_individual(std::shared_ptr< ind_t > ind)
copy an individual
Definition Variator.h:284
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:301
std::queue< unsigned int > individualsToEvaluate_m
keep a queue of individuals that have to be evaluated
Definition Variator.h:298
std::shared_ptr< Population< ind_t > > population_m
population of individuals
Definition Variator.h:292
std::shared_ptr< ind_t > popIndividualToEvaluate()
return next individual to evaluate
Definition Variator.h:169
double recombinationProbability_m
probability of applying the recombination operator
Definition Variator.h:310
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