OPAL (Object Oriented Parallel Accelerator Library)  2024.1
OPAL
FixedPisaNsga2.tcc
Go to the documentation of this file.
1 //
2 // Class FixedPisaNsga2
3 // Implementing the Variator for the PISA state machine.
4 //
5 // @see http://www.tik.ee.ethz.ch/pisa/
6 //
7 // The convergence behavior of the optimizer can be steered in 3 ways,
8 // corresponding command line arguments are given in brackets:
9 // - limit the number of generations (maxGenerations),
10 // - specify a target hypervolume (expected-hypervol) and tolerance
11 // (epsilon)
12 // - specify a minimal hypervolume progress (conv-hvol-prog), relative to
13 // the last generation, ((prev - new)/prev) that has to be attained to
14 // continue optimizing.
15 //
16 // Copyright (c) 2010 - 2013, Yves Ineichen, ETH Zürich
17 // All rights reserved
18 //
19 // Implemented as part of the PhD thesis
20 // "Toward massively parallel multi-objective optimization with application to
21 // particle accelerators" (https://doi.org/10.3929/ethz-a-009792359)
22 //
23 // This file is part of OPAL.
24 //
25 // OPAL is free software: you can redistribute it and/or modify
26 // it under the terms of the GNU General Public License as published by
27 // the Free Software Foundation, either version 3 of the License, or
28 // (at your option) any later version.
29 //
30 // You should have received a copy of the GNU General Public License
31 // along with OPAL. If not, see <https://www.gnu.org/licenses/>.
32 //
33 #include <iostream>
34 #include <sstream>
35 #include <cmath>
36 #include <cstring>
37 #include <set>
38 #include <cstdlib>
39 #include <string>
40 #include <limits>
41 
42 #include <sys/stat.h>
43 
44 #include "boost/algorithm/string.hpp"
45 
46 #include <boost/archive/text_oarchive.hpp>
47 #include <boost/archive/text_iarchive.hpp>
48 #include <boost/serialization/map.hpp>
49 
50 #include "OPALconfig.h"
51 #include "Utilities/Util.h"
52 
53 #include <boost/property_tree/ptree.hpp>
54 #include <boost/property_tree/json_parser.hpp>
55 
56 #include "Util/OptPilotException.h"
57 #include "Util/MPIHelper.h"
58 
60 #include "Util/Trace/Timestamp.h"
61 #include "Util/Trace/FileSink.h"
62 
63 
64 template< template <class> class CO, template <class> class MO >
66  Expressions::Named_t objectives,
67  Expressions::Named_t constraints,
68  DVarContainer_t dvars,
69  size_t dim, Comm::Bundle_t comms,
70  CmdArguments_t args,
71  std::vector<double> hypervolRef,
72  int nrWorkerGroups)
73  : Optimizer(comms.opt)
74  , statistics_(new Statistics<size_t>("individuals"))
75  , comms_(comms)
76  , objectives_m(objectives)
77  , constraints_m(constraints)
78  , dvars_m(dvars)
79  , args_m(args)
80  , dim_m(dim)
81  , num_workergroups_m(nrWorkerGroups)
82  , hvol_ref_m(hypervolRef)
83 {
84  //FIXME: proper rand gen initialization (use boost?!)
85  srand(time(NULL) + comms_.island_id);
86 
87  dump_freq_m = args->getArg<int>("dump-freq", 1, false);
88  dump_offspring_m = args->getArg<bool>("dump-offspring", true, false);
89  dump_dat_m = args->getArg<bool>("dump-dat", false, false);
90 
91  maxGenerations_m = args->getArg<int>("maxGenerations", true);
92  resultFile_m = args->getArg<std::string>("outfile", "-th_generation.dat", false);
93  resultDir_m = args->getArg<std::string>("outdir", "generations", false);
94 
95  // create output directory if it does not exists
96  struct stat dirInfo;
97  if(stat(resultDir_m.c_str(),&dirInfo) != 0)
98  mkdir((const char*)(resultDir_m.c_str()), 0777);
99 
100  // solution exchange frequency
101  exchangeSolStateFreq_m = args->getArg<size_t>("sol-synch", 0, false);
102 
103  // convergence arguments
104  hvol_eps_ = args->getArg<double>("epsilon", 1e-3, false);
105  expected_hvol_ = args->getArg<double>("expected-hypervol", 0.0,
106  false);
107  conv_hvol_progress_ = args->getArg<double>("conv-hvol-prog", 0.0, false);
110 
111  lambda_m = args->getArg<int>("num-ind-gen", 2, false);
112  alpha_m = args->getArg<int>("initialPopulation", true);
113  //mu_m = lambda_m;
114 
115  // initial population arguments
116  file_start_m = args_m->getArg<std::string>("start-population", "", false);
117  initialOptimization_m = args_m->getArg<bool> ("initial-optimization", false, false);
118  birthControl_m = args_m->getArg<bool> ("birth-control", false, false);
119 
120  file_param_descr_ = "%ID,";
121 
123  for(it = objectives_m.begin(); it != objectives_m.end(); it++)
124  file_param_descr_ += '%' + it->first + ',';
125 
126  file_param_descr_ += " DVAR: ";
127 
129  std::vector<std::string> dNames;
130 
131  for(itr = dvars_m.begin(); itr != dvars_m.end(); itr++) {
132  std::string dName = boost::get<VAR_NAME>(itr->second);
133  file_param_descr_ += '%' + dName + ',';
134  dNames.push_back(dName);
135  dVarBounds_m.push_back(
136  std::pair<double, double>
137  (boost::get<LOWER_BOUND>(itr->second),
138  boost::get<UPPER_BOUND>(itr->second)));
139  }
140  file_param_descr_ = file_param_descr_.substr(0,
141  file_param_descr_.size()-1);
142 
143  // setup variator
144  variator_m. reset(new Variator_t(dNames, dVarBounds_m, constraints_m, args));
145  paretoFront_m.reset(new Population_t());
146 
147  // Traces and statistics
148  std::ostringstream trace_filename;
149  trace_filename << "opt.trace." << comms_.island_id;
150  job_trace_.reset(new Trace("Optimizer Job Trace"));
151  job_trace_->registerComponent( "sink",
152  std::shared_ptr<TraceComponent>(
153  new FileSink(trace_filename.str())));
154 
155  std::ostringstream prog_filename;
156  prog_filename << "opt.progress." << comms_.island_id;
157  progress_.reset(new Trace("Optimizer Progress"));
158  progress_->registerComponent( "timestamp",
159  std::shared_ptr<TraceComponent>(new Timestamp()));
160  progress_->registerComponent( "sink",
161  std::shared_ptr<TraceComponent>(
162  new FileSink(prog_filename.str())));
163 
164  statistics_->registerStatistic("accepted", 0);
165  statistics_->registerStatistic("infeasible", 0);
166 }
167 
168 template<
169  template <class> class CO
170  , template <class> class MO
171 >
173 {}
174 
175 template<
176  template <class> class CO
177  , template <class> class MO
178 >
180 
181  curState_m = Initialize;
182  initialized_m = false;
183 
184  // start poll loop
185  run_clock_start_ = std::chrono::system_clock::now();
186  last_clock_ = std::chrono::system_clock::now();
187  run();
188 
189  // run has ended
190  bool compHyvol = (objectives_m.size() > (hyper_opt / 2 + 1));
191  if (compHyvol)
192  current_hvol_ =
193  variator_m->population()->computeHypervolume(comms_.island_id, hvol_ref_m);
194 
195  std::chrono::duration<double> total =
196  std::chrono::system_clock::now() - run_clock_start_;
197  std::ostringstream stats;
198  stats << "__________________________________________" << std::endl;
199  stats << "GENERATION " << act_gen << std::endl;
200  stats << "TOTAL = " << total.count() << "s" << std::endl;
201  if (compHyvol)
202  stats << "HYPERVOLUME = " << current_hvol_ << std::endl;
203  stats << "time per accepted ind = "
204  << total.count()/statistics_->getStatisticValue("accepted")
205  << std::endl;
206  stats << "time per infeasible ind = "
207  << (statistics_->getStatisticValue("infeasible") ? total.count()/statistics_->getStatisticValue("infeasible") : 0)
208  << std::endl;
209  statistics_->dumpStatistics(stats);
210  stats << "__________________________________________" << std::endl;
211  progress_->log(stats);
212 }
213 
214 template< template <class> class CO, template <class> class MO >
215 bool FixedPisaNsga2<CO, MO>::onMessage(MPI_Status status, size_t length) {
216 
217  MPITag_t tag = MPITag_t(status.MPI_TAG);
218  switch(tag) {
219 
221 
222  size_t buf_size = length;
223  size_t pilot_rank = status.MPI_SOURCE;
224 
225  std::ostringstream dump;
226  dump << "new results from other cores " << buf_size << std::endl;
227  job_trace_->log(dump);
228 
229  char *buffer = new char[buf_size];
230  MPI_Recv(buffer, buf_size, MPI_CHAR, pilot_rank,
231  MPI_EXCHANGE_SOL_STATE_RES_TAG, comms_.opt, &status);
232 
233  dump.clear();
234  dump.str(std::string());
235  dump << "got results from other cores " << buf_size << std::endl;
236  job_trace_->log(dump);
237 
238  SolutionState_t new_states;
239  std::istringstream is(buffer);
240  boost::archive::text_iarchive ia(is);
241  ia >> new_states;
242  delete[] buffer;
243 
244  std::set<unsigned int> new_state_ids;
245  for (Individual_t ind : new_states) {
246 
247  // only insert individual if not already in population
248  if(variator_m->population()->isRepresentedInPopulation(ind.genes_m))
249  continue;
250 
251  individual new_ind(new Individual_t);
252  new_ind->genes_m = ind.genes_m;
253  new_ind->objectives_m = ind.objectives_m;
254 
255  //XXX: can we pass more than lambda_m files to selector?
256  unsigned int id =
257  variator_m->population()->add_individual(new_ind);
258  finishedBuffer_m.push_back(id);
259 
260  dump.clear();
261  dump.str(std::string());
262  dump << "individual (ID: " << id
263  << ") successfully migrated from another island" << std::endl;
264  job_trace_->log(dump);
265  }
266 
267  return true;
268  }
269 
270  case REQUEST_FINISHED: {
271 
272  unsigned int jid = static_cast<unsigned int>(length);
274  it = jobmapping_m.find(jid);
275 
276  std::ostringstream dump;
277  dump << "job with ID " << jid << " delivered results" << std::endl;
278  job_trace_->log(dump);
279 
280  if(it == jobmapping_m.end()) {
281  dump << "\t |-> NOT FOUND!" << std::endl;
282  job_trace_->log(dump);
283  std::cout << "NON-EXISTING JOB with ID = " << jid << std::endl;
284  throw OptPilotException("FixedPisaNsga2::onMessage",
285  "non-existing job");
286  }
287 
288  individual ind = it->second;
289  jobmapping_m.erase(it);
290 
291  //size_t dummy = 1;
292  //MPI_Send(&dummy, 1, MPI_UNSIGNED_LONG, status.MPI_SOURCE,
293  // MPI_WORKER_FINISHED_ACK_TAG, comms_.listen);
294 
295  reqVarContainer_t res;
296  MPI_Recv_reqvars(res, status.MPI_SOURCE, comms_.opt);
297 
298  ind->objectives_m.clear();
299 
300  //XXX: check order of genes
301  reqVarContainer_t::iterator itr = res.begin();
302  for(; itr != res.end(); ++itr) {
303  // mark invalid if expression could not be evaluated or constraint does not hold
304  if(!itr->second.is_valid || (itr->second.value.size() > 1 && !itr->second.value[0])) {
305  std::ostringstream dump;
306  if (!itr->second.is_valid) {
307  dump << "invalid individual, objective or constraint \"" << itr->first
308  << "\" failed to be evaluated correctly"
309  << std::endl;
310  } else {
311  dump << "invalid individual, constraint \"" << itr->first
312  << "\" failed to yield true; result: " << itr->second.value[1]
313  << std::endl;
314  }
315  job_trace_->log(dump);
316  variator_m->infeasible(ind);
317  statistics_->changeStatisticBy("infeasible", 1);
318  dispatch_forward_solves();
319  return true;
320  } else {
321  // update objective value for valid objective
322  if(itr->second.value.size() == 1)
323  ind->objectives_m.push_back(itr->second.value[0]);
324  }
325  }
326 
327  finishedBuffer_m.push_back(jid);
328  statistics_->changeStatisticBy("accepted", 1);
329  // check for pareto front
330  checkParetoFront(jid);
331 
332  return true;
333  }
334 
335  default: {
336  std::cout << "(FixedPisaNsga2) Error: unexpected MPI_TAG: "
337  << status.MPI_TAG << std::endl;
338  return false;
339  }
340  }
341 }
342 
343 
344 template< template <class> class CO, template <class> class MO >
346 
347  // whenever lambda children are ready and we are in the variator phase
348  // run the selector
349  // std::ostringstream debug;
350  // debug << "IN POST POLL: ";
351  // debug << finishedBuffer_m.size() << " / " << lambda_m << std::endl;
352  // debug << getStateString(curState_m) << std::endl;
353  // progress_->log(debug);
354  if(finishedBuffer_m.size() >= lambda_m && curState_m == Variate) {
355  //std::cout << "▉";
356  std::cout << "░" << std::flush;
357 
358  bool compHyvol = (objectives_m.size() > (hyper_opt / 2 + 1));
359  if (compHyvol) {
360  double hvol =
361  variator_m->population()->computeHypervolume(comms_.island_id, hvol_ref_m);
362  hvol_progress_ = fabs(current_hvol_ - hvol) / current_hvol_;
363  current_hvol_ = hvol;
364  }
365 
366  std::chrono::duration<double> total =
367  std::chrono::system_clock::now() - run_clock_start_;
368  std::chrono::duration<double> dt =
369  std::chrono::system_clock::now() - last_clock_;
370  last_clock_ = std::chrono::system_clock::now();
371  std::ostringstream stats;
372  stats << "__________________________________________" << std::endl;
373  stats << "Arriving at generation " << act_gen + 1 << std::endl;
374  stats << "dt = " << dt.count() << "s, total = " << total.count()
375  << "s" << std::endl;
376  if (compHyvol)
377  stats << "Hypervolume = " << current_hvol_ << std::endl;
378  stats << "__________________________________________" << std::endl;
379  progress_->log(stats);
380 
381  // dump current generation (or their parents)
382  if((act_gen + 1) % dump_freq_m == 0) {
383  dumpPopulation(variator_m->population());
384  }
385 
386  // we can only send all finished individuals (selector does not support
387  // variable size).
388  toSelectorAndCommit();
389 
390  exchangeSolutionStates();
391 
392  //XXX: at the end of the Variate state (previous runStateMachine()
393  // call) we can safely change the state.
394  curState_m = Select;
395 
396  act_gen++;
397  }
398 
399  // state will be reset to whatever is in the state file
400  runStateMachine();
401 }
402 
403 
404 template< template <class> class CO , template <class> class MO >
406 
407  size_t num_masters = args_m->getArg<size_t>("num-masters", 1, false);
408 
409  if(num_masters <= 1 ||
410  exchangeSolStateFreq_m == 0 ||
411  act_gen % exchangeSolStateFreq_m != 0)
412  return;
413 
414  int pilot_rank = comms_.master_local_pid;
415 
416  std::ostringstream os;
417  boost::archive::text_oarchive oa(os);
418 
419  SolutionState_t population;
421  for(itr = variator_m->population()->begin();
422  itr != variator_m->population()->end(); itr++) {
423 
424  Individual_t ind;
425  ind.genes_m = std::vector<double>(itr->second->genes_m);
426  ind.objectives_m = std::vector<double>(itr->second->objectives_m);
427  population.push_back(ind);
428  }
429 
430  oa << population;
431 
432  size_t buf_size = os.str().length();
433 
434  std::ostringstream dump;
435  dump << "sending my buffer size " << buf_size << " bytes to PILOT"
436  << std::endl;
437  job_trace_->log(dump);
438 
439  MPI_Send(&buf_size, 1, MPI_UNSIGNED_LONG, pilot_rank,
440  EXCHANGE_SOL_STATE_TAG, comms_.opt);
441 
442  char *buffer = new char[buf_size];
443  memcpy(buffer, os.str().c_str(), buf_size);
444  MPI_Send(buffer, buf_size, MPI_CHAR, pilot_rank,
445  MPI_EXCHANGE_SOL_STATE_DATA_TAG, comms_.opt);
446  delete[] buffer;
447 
448  dump.clear();
449  dump.str(std::string());
450  dump << "Sent " << buf_size << " bytes to PILOT" << std::endl;
451  job_trace_->log(dump);
452 }
453 
454 
455 template< template <class> class CO, template <class> class MO >
457 
458  to_selector_.clear();
459  const size_t size = finishedBuffer_m.size();
460  for(size_t i = 0; i < size; i++) {
461  unsigned int id = finishedBuffer_m.front();
462  to_selector_.insert(id);
463  finishedBuffer_m.pop_front();
464  }
465 
466  variator_m->population()->commit_individuals(to_selector_);
467 }
468 
469 
470 template< template <class> class CO, template <class> class MO >
472 
473  while(variator_m->hasMoreIndividualsToEvaluate()) {
474 
475  //reqVarContainer_t reqs;
476  //Expressions::Named_t::iterator it;
477  //for(it = objectives_m.begin(); it != objectives_m.end(); it++) {
478  //std::set<std::string> vars = it->second.getReqVars();
479  //std::set<std::string>::iterator setitr;
480  //for(setitr = vars.begin(); setitr != vars.end(); setitr++) {
481  //if(reqs.count(*setitr) == 0) {
482  //reqVarInfo_t tmp;
483  //tmp.type = EVALUATE;
484  //tmp.value = 0.0;
485  //reqs.insert(std::pair<std::string, reqVarInfo_t>
486  //(*setitr, tmp));
487  //}
488  //}
489  //}
490 
491  individual ind = variator_m->popIndividualToEvaluate();
492  if (ind == NULL) continue;
493  Param_t params;
495  size_t i = 0;
496  for(itr = dvars_m.begin(); itr != dvars_m.end(); itr++, i++) {
497  params.insert(
498  std::pair<std::string, double>
499  (boost::get<VAR_NAME>(itr->second),
500  ind->genes_m[i]));
501  }
502 
503  size_t jid = static_cast<size_t>(ind->id_m);
504  int pilot_rank = comms_.master_local_pid;
505 
506  // now send the request to the pilot
507  MPI_Send(&jid, 1, MPI_UNSIGNED_LONG, pilot_rank, OPT_NEW_JOB_TAG, comms_.opt);
508 
509  MPI_Send_params(params, pilot_rank, comms_.opt);
510 
511  //MPI_Send_reqvars(reqs, pilot_rank, comms_.opt);
512 
513  jobmapping_m.insert(
514  std::pair<size_t, individual >(jid, ind));
515 
516  std::ostringstream dump;
517  dump << "dispatched simulation with ID " << jid << std::endl;
518  job_trace_->log(dump);
519  }
520 }
521 
522 
523 template<
524  template <class> class CO
525  , template <class> class MO
526 >
528 
529  switch(curState_m) {
530 
531  // State 2 of the FSM: we read mu parents
532  // and create lambda children by variation of the individuals specified
533  // in sel file.
534  case Variate: {
535 
536  if( (maxGenerations_m > 0 && act_gen > maxGenerations_m) ||
537  (hvol_progress_ < conv_hvol_progress_) ||
538  (expected_hvol_ > 0.0 && fabs(current_hvol_ - expected_hvol_) < hvol_eps_)
539  ) {
540  curState_m = Stop;
541  } else {
542  if(parent_queue_.size() > 0) {
543  std::vector<unsigned int> parents(parent_queue_.begin(),
544  parent_queue_.end());
545  parent_queue_.clear();
546 
547  // remove non-surviving individuals
548  //std::set<unsigned int> survivors(archive_.begin(),
549  //archive_.end());
550  std::set<unsigned int> survivors(pp_all.begin(),
551  pp_all.end());
552 
553  variator_m->population()->keepSurvivors(survivors);
554 
555  // only enqueue new individuals to pilot, the poll loop will
556  // feed results back to the selector.
557  //FIXME: variate works on staging set!!!
558  variator_m->variate(parents);
559  dispatch_forward_solves();
560 
561  curState_m = Variate;
562  }
563  }
564  break;
565  }
566 
567  // State 0 of the FSM: generate initial population and write
568  // information about initial population to ini file.
569  case Initialize: {
570  if(initialized_m == false) {
571  variator_m->initial_population(alpha_m, file_start_m);
572  if (initialOptimization_m == true && birthControl_m == false && file_start_m.empty()) {
573  // increase population such that workers keep busy until full initial population is found
574  variator_m->initial_population(num_workergroups_m, "");
575  }
576  dispatch_forward_solves();
577  initialized_m = true;
578  }
579 
580  //XXX: wait till the first alpha_m individuals are ready then start
581  // the selector
582  if(finishedBuffer_m.size() >= alpha_m) {
583  if(dump_offspring_m == true) { // dump first generation - no parents yet
584  dumpPopulation(variator_m->population());
585  }
586  act_gen = 2;
587  toSelectorAndCommit();
588  curState_m = InitializeSelector;
589 
590  // add additional worker jobs to the queue so that single job won't keep system idle
591  if (initialOptimization_m == false && birthControl_m == false && file_start_m.empty()) {
592  // increase population to have all workers busy
593  variator_m->initial_population(num_workergroups_m, "");
594  dispatch_forward_solves();
595  }
596  }
597  break;
598  }
599 
600  // State 4 of the FSM: stopping state for the variator.
601  case Stop: {
602  // variator_m->population()->keepSurvivors(archive_);
603  if (dump_offspring_m == false) {
604  dumpPopulation(variator_m->population());
605  }
606  // dump Pareto front
607  std::ostringstream filename;
608  filename << resultDir_m << "/" << "ParetoFront_" << resultFile_m
609  << "_" << comms_.island_id;
610  dumpPopulationToJSON(paretoFront_m, filename, false);
611 
612  curState_m = VariatorStopped;
613 
614  // notify pilot that we have converged
615  int dummy = 0;
616  MPI_Request req;
617  MPI_Isend(&dummy, 1, MPI_INT, comms_.master_local_pid,
618  MPI_OPT_CONVERGED_TAG, comms_.opt, &req);
619 
620  break;
621  }
622 
623  // State 7 of the FSM: stopping state for the selector.
624  // case SelectorStopped: {
625  // curState_m = Stop;
626  // break;
627  // }
628 
629  // State 8 of the FSM: reset the variator, restart in state 0.
630  // case Reset: {
631  // act_gen = 1;
632  // variator_m->population()->keepSurvivors(archive_);
633  // dumpPopulation(variator_m->population());
634 
635  // variator_m->population()->clean_population();
636  // curState_m = ReadyForReset;
637  // break;
638  // }
639 
640  // State 11 of the FSM: selector has just reset and is ready to
641  // start again in state 1.
642  // case Restart: {
643  // curState_m = Initialize;
644  // break;
645  // }
646 
647 
648 //-----------------------| selector STM |-----------------------------//
649 
650  case InitializeSelector: {
651 
652  selection();
653 
654  // write arc file (all individuals that could ever be used again)
655  typename std::map<unsigned int, individual >
656  ::iterator it;
657  for(it = variator_m->population()->begin();
658  it != variator_m->population()->end(); it++) {
659  //archive_.insert(it->first);
660  pp_all.push_back(it->first);
661  }
662 
663  curState_m = Variate;
664 
665  break;
666  }
667 
668  case Select: {
669  selection();
670  curState_m = Variate;
671 
672  break;
673  }
674 
675  // variator terminated
676  case VariatorStopped: {
677  curState_m = VariatorTerminate;
678  break;
679  }
680 
681  // // variator ready for reset
682  // case ReadyForReset: {
683  // curState_m = ReadyForResetS;
684  // break;
685  // }
686 
687  // // reset
688  // case ReadyForResetS: {
689  // curState_m = Restart;
690  // break;
691  // }
692 
693  case VariatorTerminate:
694  default:
695  break;
696 
697  }
698 }
699 
700 template< template <class> class CO, template <class> class MO >
701 void FixedPisaNsga2<CO, MO>::dumpPopulation(std::shared_ptr<Population_t> population) {
702  std::ostringstream filename;
703  int fileNumber = act_gen;
704  if (dump_offspring_m == false) fileNumber--; // parents are from generation earlier (keeping filenumbers the same)
705  filename << resultDir_m << "/" << fileNumber << "_" << resultFile_m
706  << "_" << comms_.island_id;
707 
708  // only dump old data format if the user requests it
709  if (dump_dat_m == true)
710  dumpPopulationToFile(population, filename, dump_offspring_m);
711 
712  dumpPopulationToJSON(population, filename, dump_offspring_m);
713 }
714 
715 template< template <class> class CO, template <class> class MO >
716 void FixedPisaNsga2<CO, MO>::dumpPopulationToFile(std::shared_ptr<Population_t> population,
717  std::ostringstream& filename,
718  bool dump_offspring) {
719 
720  std::ofstream file;
721  file.open(filename.str().c_str(), std::ios::out);
722 
724  it = population->begin();
725  // find maximum length of ID
726  auto maxID = it->first;
727  for(it ++; it != population->end(); it++) {
728  if (it->first > maxID)
729  maxID = it->first;
730  }
731  const size_t numDigits = std::to_string(maxID).length();
732  size_t next = 0, last = 0;
733  std::string delimiter = ",";
734  next = file_param_descr_.find(delimiter, last);
735  file << std::setw(numDigits + 1) << file_param_descr_.substr(last, next - last) << " ";
736  last = next + 1;
737  while ((next = file_param_descr_.find(delimiter, last)) != std::string::npos) {
738  size_t next2 = file_param_descr_.substr(last, next - last).find(":");
739  if (next2 != std::string::npos) {
740  last += next2 + 1;
741  file << "DVAR: ";
742  }
743  file << std::setw(14) << file_param_descr_.substr(last, next - last) << " ";
744  last = next + 1;
745  }
746  file << std::setw(14) << file_param_descr_.substr(last) << std::endl;
747 
748  file.precision(6);
749  file << std::scientific;
750 
751  if (dump_offspring == true) {
752  for (auto id : finishedBuffer_m) {
753  auto ind = population->get_staging(id); // get from staging area
754  if (ind) // pointer might be uninitialised (should not happen)
755  dumpIndividualToFile(id, ind, file, numDigits);
756  else
757  std::cout << "Individual " << id << " from buffer not found!" << std::endl;
758  }
759  } else {
760  for(it = population->begin(); it != population->end(); it++) {
761  dumpIndividualToFile(it->first, it->second, file, numDigits);
762  }
763  }
764 
765  file.close();
766 }
767 
768 template< template <class> class CO, template <class> class MO >
770  individual& ind,
771  std::ofstream& file,
772  const size_t numDigits) {
773 
774  file << std::setw(numDigits + 1) << idx << " ";
775 
776  for(size_t i=0; i<ind->objectives_m.size(); i++)
777  file << std::setw(14) << ind->objectives_m[i] << " ";
778  file << " ";
779  for(size_t i=0; i<ind->genes_m.size(); i++)
780  file << std::setw(14) << ind->genes_m[i] << " ";
781 
782  file << std::endl;
783 }
784 
785 template< template <class> class CO, template <class> class MO >
786 void FixedPisaNsga2<CO, MO>::dumpPopulationToJSON(std::shared_ptr<Population_t> population,
787  std::ostringstream& filename,
788  bool dump_offspring) {
789 
790  typedef boost::property_tree::ptree ptree_t;
791  ptree_t tree;
792 
793  tree.put("name", "opt-pilot");
794  tree.put(OPAL_PROJECT_NAME " version", OPAL_PROJECT_VERSION);
795  tree.put("git revision", Util::getGitRevision());
796 
797  std::stringstream bounds;
798  DVarContainer_t::iterator itr = dvars_m.begin();
799  for (bounds_t::iterator it = dVarBounds_m.begin();
800  it != dVarBounds_m.end(); ++it, ++itr)
801  {
802  std::string dvar = boost::get<VAR_NAME>(itr->second);
803  bounds << "[ " << it->first << ", " << it->second << " ]";
804  tree.put("dvar-bounds." + dvar, bounds.str());
805  bounds.str("");
806  }
807 
808  ptree_t constraints;
809 
810  for ( Expressions::Named_t::iterator it = constraints_m.begin();
811  it != constraints_m.end(); ++it )
812  {
813  std::string s = it->second->toString();
815  s.erase(std::remove(s.begin(), s.end(), '"'), s.end());
816 
817  // 22. November 2018
818  // https://stackoverflow.com/questions/2114466/creating-json-arrays-in-boost-using-property-trees
819  ptree_t constraint;
820  constraint.put("", s);
821  constraints.push_back(std::make_pair("", constraint));
822  }
823 
824  tree.add_child("constraints", constraints);
825 
826  if (dump_offspring == true) {
827  for (auto id : finishedBuffer_m) {
828  auto ind = population->get_staging(id); // get from staging area
829  if (ind) // pointer might be uninitialised (should not happen)
830  dumpIndividualToJSON(id, ind, tree);
831  else
832  std::cout << "Individual " << id << " from buffer not found!" << std::endl;
833  }
834  } else {
835  for (auto it = population->begin(); it != population->end(); it++) {
836  dumpIndividualToJSON(it->first, it->second, tree);
837  }
838  }
839 
840  filename << ".json";
841  boost::property_tree::write_json(filename.str(), tree);
842 }
843 
844 template< template <class> class CO, template <class> class MO >
846  individual& ind,
847  boost::property_tree::ptree& tree) {
848 
849  std::string id = std::to_string(idx);
850 
852  expr_it = objectives_m.begin();
853 
854  for(size_t i=0; i < ind->objectives_m.size(); i++, expr_it++) {
855  std::string name = expr_it->first;
856  tree.put("population." + id + ".obj." + name, ind->objectives_m[i]);
857  }
858 
859  size_t i = 0;
860  for(DVarContainer_t::iterator itr = dvars_m.begin(); itr != dvars_m.end(); ++i, ++itr) {
861  std::string name = boost::get<VAR_NAME>(itr->second);
862  tree.put("population." + id + ".dvar." + name, ind->genes_m[i]);
863  }
864 }
865 
866 
867 /*-----------------------| selection functions|--------------------------*/
868 
869 template< template <class> class CO, template <class> class MO >
871 
872  /* Join offspring individuals from variator to population */
873  mergeOffspring();
874 
875  int size = pp_all.size();
876 
877  /* Create internal data structures for selection process */
878  copies.resize(size);
879  dist.resize(size);
880  for (int i = 0; i < size; i++) front.push_back(std::vector<int>(size));
881 
882 
883  /* Calculates NSGA2 fitness values for all individuals */
884  calcFitnesses();
885 
886  /* Calculates distance cuboids */
887  calcDistances();
888 
889  /* Performs environmental selection
890  (truncates 'pp_all' to size 'alpha') */
891  environmentalSelection();
892 
893  /* Performs mating selection
894  (fills mating pool / offspring population pp_sel */
895  matingSelection();
896 
897 
898  copies.clear();
899  dist.clear();
900  front.clear();
901 }
902 
903 
904 template< template <class> class CO, template <class> class MO >
906  pp_all.insert(pp_all.end(), to_selector_.begin(), to_selector_.end());
907  to_selector_.clear();
908 }
909 
910 
911 template< template <class> class CO, template <class> class MO >
913 {
914  int i, j, l;
915  int size = pp_all.size();
916 
917  std::vector<int> d(size,0); // 1 if dominated by another ind, 0 if not
918  std::vector<int> f(size,1); // 1 if not yet in a front, -1 if in a front
919 
920  /* initialize fitness and strength values */
921  for (i = 0; i < size; i++) {
922  fitness_.insert(std::pair<size_t, double>(pp_all[i], 0.0));
923  copies[i] = 0;
924  }
925 
926  /* calculate strength values */
927  int num = size; // number of individuals not yet in a front
928  for (l = 0; l < size; l++) { // loop over fronts, there can be maximally `size` fronts
929  /* find next front */
930  for (i = 0; i < size; i++) {
931  d[i] = 0; // reset dominate flag
932  if (f[i] == -1) continue; // don't consider if already in a front
933  for (j = 0; j < size && j != i; j++) {
934  if (f[j] == -1) continue;
935  individual ind_i = variator_m->population()->get_individual(pp_all[i]);
936  individual ind_j = variator_m->population()->get_individual(pp_all[j]);
937  if (dominates(ind_j, ind_i)) {
938  d[i] = 1;
939  break;
940  }
941  }
942  }
943 
944  /* extract front */
945  for (i = 0; i < size; i++) {
946  if (f[i] != -1 && d[i] == 0) {
947  // add to front
948  fitness_[pp_all[i]] = l;
949  f[i] = -1;
950  num--;
951  front[l][copies[l]] = i;
952  copies[l] += 1;
953  }
954  }
955 
956  if (num == 0)
957  break;
958  }
959 }
960 
961 
962 template< template <class> class CO, template <class> class MO >
964 {
965  int i, j, l;
966  int size = pp_all.size();
967  double dmax = 1E99 / (dim_m + 1);
968 
969  for (i = 0; i < size; i++) {
970  dist[i] = 1;
971  }
972 
973  for (l = 0; l < size; l++) {
974  for (size_t d = 0; d < dim_m; d++) {
975  /* sort accorting to d-th objective */
976  for (i = 0; i < copies[l]; i++) {
977  int min_index = -1;
978  int min = i;
979  size_t idx1 = pp_all[front[l][i]];
980  individual ind1 =
981  variator_m->population()->get_individual(idx1);
982  double obj_min = ind1->objectives_m[d];
983 
984  for (j = i + 1; j < copies[l]; j++) {
985 
986  // size_t idx1 = pp_all[front[l][j]];
987  size_t idx2 = pp_all[front[l][j]];
988  // individual ind1 =
989  // variator_m->population()->get_individual(idx1);
990  individual ind2 =
991  variator_m->population()->get_individual(idx2);
992  // double obj1 = ind1->objectives_m[d];
993  double obj2 = ind2->objectives_m[d];
994 
995  if ( obj2 < obj_min ) {
996  min = j;
997  obj_min = obj2;
998  }
999  }
1000  min_index = front[l][min];
1001  front[l][min] = front[l][i];
1002  front[l][i] = min_index;
1003  }
1004 
1005  /* add distances */
1006  for (i = 0; i < copies[l]; i++) {
1007  if (i == 0 || i == copies[l] - 1)
1008  dist[front[l][i]] += dmax;
1009  else {
1010  size_t idx1 = pp_all[front[l][i+1]];
1011  size_t idx2 = pp_all[front[l][i-1]];
1012  individual ind1 =
1013  variator_m->population()->get_individual(idx1);
1014  individual ind2 =
1015  variator_m->population()->get_individual(idx2);
1016  double obj1 = ind1->objectives_m[d];
1017  double obj2 = ind2->objectives_m[d];
1018 
1019  dist[front[l][i]] += obj1 - obj2;
1020  }
1021  }
1022  }
1023  }
1024 }
1025 
1026 
1027 template< template <class> class CO, template <class> class MO >
1029 
1030  int size = pp_all.size();
1031 
1032  for (int i = 0; i < size; i++)
1033  fitness_[pp_all[i]] += 1.0 / dist[i];
1034 
1035  // get alpha_m fittest individuals
1036  for (size_t i = 0; i < alpha_m; i++) {
1037  int min = i;
1038  for (int j = i + 1; j < size; j++) {
1039  if (fitness_[pp_all[j]] < fitness_[pp_all[min]])
1040  min = j;
1041  }
1042  // swap
1043  std::swap(pp_all[min], pp_all[i]);
1044  }
1045  // erase others
1046  pp_all.erase(pp_all.begin() + alpha_m, pp_all.end());
1047 }
1048 
1049 
1050 /* Fills mating pool 'parent_queue_' */
1051 template< template <class> class CO, template <class> class MO >
1053  // select lambda_m parents
1054  for (size_t i = 0; i < lambda_m; i++) {
1055  int winner = irand(pp_all.size());
1056  for (int j = 0; j < tournament_m; j++) {
1057  int opponent = irand(pp_all.size());
1058  if (fitness_[pp_all[opponent]] < fitness_[pp_all[winner]]
1059  || winner == opponent) {
1060  winner = opponent;
1061  }
1062  }
1063  parent_queue_.push_back(pp_all[winner]);
1064  }
1065 }
1066 
1067 
1068 /* Determines if one individual dominates another.
1069  Minimizing fitness values. */
1070 template< template <class> class CO, template <class> class MO >
1072 
1073  int a_is_worse = 0, b_is_worse = 0;
1074  // int equal = 1;
1075 
1076  for (size_t i = 0; i < ind_a->objectives_m.size()/* && !a_is_worse*/; i++) {
1077  if (ind_a->objectives_m[i] > ind_b->objectives_m[i]) a_is_worse = 1;
1078  if (ind_a->objectives_m[i] < ind_b->objectives_m[i]) b_is_worse = 1;
1079  // a_is_worse = ind_a->objectives_m[i] > ind_b->objectives_m[i];
1080  // equal = (ind_a->objectives_m[i] == ind_b->objectives_m[i]) && equal;
1081  }
1082 
1083  return (b_is_worse && !a_is_worse);
1084  // return (!equal && !a_is_worse);
1085 }
1086 
1087 template< template <class> class CO, template <class> class MO >
1089  individual newInd = variator_m->population()->get_staging(newid);
1090 
1091  for (auto it = paretoFront_m->begin(); it != paretoFront_m->end(); it++) {
1092  if (dominates(it->second, newInd) == true) return false;
1093  }
1094  //check if same (should happen rarely)
1095  if (paretoFront_m->isRepresentedInPopulation(newInd->genes_m) == true)
1096  return false;
1097 
1098  for (auto it = paretoFront_m->begin(); it != paretoFront_m->end(); it++) {
1099  if (dominates(newInd, it->second) == true) {
1100  // remove individuals no longer in Pareto front
1101  it = paretoFront_m->erase(it);
1102  }
1103  }
1104  paretoFront_m->add_individual(newInd);
1105  paretoFront_m->commit_individuals();
1106 
1107  return true;
1108 }
1109 
1110 template< template <class> class CO, template <class> class MO >
1112  switch(state) {
1113  case Initialize:
1114  return "Initialize";
1115  case InitializeSelector:
1116  return "InitializeSelector";
1117  case Variate:
1118  return "Variate";
1119  case Select:
1120  return "Select";
1121  case Stop:
1122  return "Stop";
1123  case VariatorStopped:
1124  return "VariatorStopped";
1125  case VariatorTerminate:
1126  return "VariatorTerminate";
1127  // case SelectorStopped:
1128  // return "SelectorStopped";
1129  // case Reset:
1130  // return "Reset";
1131  // case ReadyForReset:
1132  // return "ReadyForReset";
1133  // case ReadyForResetS:
1134  // return "ReadyForResetS";
1135  // case Restart:
1136  // return "Restart";
1137  default:
1138  return "";
1139  }
1140 }
int island_id
Definition: types.h:33
void dumpIndividualToFile(int id, individual &ind, std::ofstream &file, const size_t numDigits)
bool dump_dat_m
dump old data format
namedVariableCollection_t Param_t
Definition: Types.h:48
std::unique_ptr< Variator_t > variator_m
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 conv_hvol_progress_
#define OPAL_PROJECT_VERSION
Definition: config.h.in:5
void dispatch_forward_solves()
std::string file_param_descr_
file header for result files contains this parameter description
std::string getGitRevision()
Definition: Util.cpp:33
std::string resultFile_m
result file name
std::string file_start_m
population file to be started from
void dumpIndividualToJSON(int id, individual &ind, boost::property_tree::ptree &tree)
objectives_t objectives_m
values of objectives of an individual
Definition: Individual.h:118
#define OPAL_PROJECT_NAME
Definition: config.h.in:2
bool dump_offspring_m
dump offspring / parents flag
and give any other recipients of the Program a copy of this License along with the Program You may charge a fee for the physical act of transferring a and you may at your option offer warranty protection in exchange for a fee You may modify your copy or copies of the Program or any portion of thus forming a work based on the and copy and distribute such modifications or work under the terms of Section provided that you also meet all of these that in whole or in part contains or is derived from the Program or any part to be licensed as a whole at no charge to all third parties under the terms of this License c If the modified program normally reads commands interactively when run
Definition: LICENSE:87
std::map< std::string, DVar_t > DVarContainer_t
Definition: Types.h:92
void bounds(const PETE_Expr< T1 > &expr, Vektor< T2, D > &minval, Vektor< T2, D > &maxval)
std::unique_ptr< Trace > progress_
#define MPI_EXCHANGE_SOL_STATE_DATA_TAG
Definition: MPIHelper.h:59
const std::unique_ptr< Statistics< size_t > > statistics_
collect some statistics of rejected and accepted individuals
int precision() const
Definition: Inform.h:112
Inform & endl(Inform &inf)
Definition: Inform.cpp:42
T::PETE_Expr_t::PETE_Return_t min(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:76
Comm::Bundle_t comms_
communicator bundle for the optimizer
std::map< std::string, Expressions::Expr_t * > Named_t
type of an expressions with a name
Definition: Expression.h:74
PisaState_t
all PISA states
bounds_t dVarBounds_m
bounds on each specified gene
T::PETE_Expr_t::PETE_Return_t max(const PETE_Expr< T > &expr, NDIndex< D > &loc)
Definition: ReductionLoc.h:84
PETE_TUTree< FnFabs, typename T::PETE_Expr_t > fabs(const PETE_Expr< T > &l)
Definition: PETE.h:732
size_t lambda_m
number of parents the selector chooses
Definition: Select.h:26
std::string::iterator iterator
Definition: MSLang.h:15
CmdArguments_t args_m
command line arguments specified by the user
std::vector< Individual > SolutionState_t
type used in solution state exchange with other optimizers
void exchangeSolutionStates()
if necessary exchange solution state with other optimizers
FixedPisaNsga2(Expressions::Named_t objectives, Expressions::Named_t constraints, DVarContainer_t dvars, size_t dim, Comm::Bundle_t comms, CmdArguments_t args, std::vector< double > hypervolRef, int nrWorkerGroups)
std::shared_ptr< CmdArguments > CmdArguments_t
Definition: CmdArguments.h:176
#define MPI_EXCHANGE_SOL_STATE_RES_TAG
Definition: MPIHelper.h:61
size_t maxGenerations_m
maximal generation (stopping criterion)
DVarContainer_t dvars_m
design variables
virtual bool onMessage(MPI_Status status, size_t length)
implementing poller hooks
std::string getStateString(PisaState_t) const
Expressions::Named_t constraints_m
constraints
#define MPI_OPT_CONVERGED_TAG
optimizer notifies pilot that optimization has converged (EXIT)
Definition: MPIHelper.h:48
void MPI_Recv_reqvars(reqVarContainer_t &reqvars, size_t pid, MPI_Comm comm)
Definition: MPIHelper.cpp:165
void environmentalSelection()
void dumpPopulationToFile(std::shared_ptr< Population_t >, std::ostringstream &filename, bool dump_offspring)
const std::string name
bundles all communicators for a specific role/pid
Definition: types.h:32
virtual void initialize()
Starting selection algorithm and variator PISA state machine.
std::string resultDir_m
void dumpPopulation(std::shared_ptr< Population_t >)
bool initialOptimization_m
initial population optimization flag (increases initial population)
double hvol_eps_
convergence accuracy if maxGenerations not set
Variator< Individual_t, CrossoverOperator, MutationOperator > Variator_t
b mention the algorithm in the References section The appropriate citation is
Definition: README.TXT:103
void MPI_Send_params(Param_t params, size_t pid, MPI_Comm comm)
Definition: MPIHelper.cpp:87
int dominates(individual ind_a, individual ind_b)
constexpr double e
The value of .
Definition: Physics.h:39
void runStateMachine()
executes one loop of the PISA state machine
Definition: Trace.h:31
#define hyper_opt
Definition: hypervolume.h:38
void toSelectorAndCommit()
passes finished individuals to the selector
size_t alpha_m
size of initial population
bool birthControl_m
enforce strict population size
virtual void postPoll()
executed after handling (if any) new request
Population< Individual_t > Population_t
size_t exchangeSolStateFreq_m
how often do we exchange solutions with other optimizers
std::unique_ptr< Trace > job_trace_
std::map< std::string, reqVarInfo_t > reqVarContainer_t
Definition: Types.h:79
genes_t genes_m
genes of an individual
Definition: Individual.h:116
Definition: Stop.h:24
objs obj2
Definition: Problem.in:8
void dumpPopulationToJSON(std::shared_ptr< Population_t >, std::ostringstream &filename, bool dump_offspring)
void clear()
Clear the occurrence counter.
Definition: Object.cpp:341
MPITag_t
Definition: MPIHelper.h:71
c Accompany it with the information you received as to the offer to distribute corresponding source complete source code means all the source code for all modules it plus any associated interface definition plus the scripts used to control compilation and installation of the executable as a special the source code distributed need not include anything that is normally and so on of the operating system on which the executable unless that component itself accompanies the executable If distribution of executable or object code is made by offering access to copy from a designated then offering equivalent access to copy the source code from the same place counts as distribution of the source even though third parties are not compelled to copy the source along with the object code You may not or distribute the Program except as expressly provided under this License Any attempt otherwise to sublicense or distribute the Program is and will automatically terminate your rights under this License parties who have received copies
Definition: LICENSE:162
Expressions::Named_t objectives_m
objectives
std::shared_ptr< typename FixedPisaNsga2::Individual_t > individual
alias for usage in template
std::shared_ptr< Population_t > paretoFront_m
population of pareto-front (for final output)
bool checkParetoFront(unsigned int id)
check if individual in pareto front and add if not