dignea  1.0.0
Diverse Instance Generator with Novelty Search and Evolutionary Algorithms
NSGA2.h
1 
12 #ifndef DIGNEA_NSGA2_H
13 #define DIGNEA_NSGA2_H
14 
15 #include <dignea/core/AbstractGA.h>
16 #include <dignea/core/Crossover.h>
17 #include <dignea/core/Mutation.h>
18 #include <dignea/core/Solution.h>
21 #include <dignea/utilities/random/PseudoRandom.h>
22 
23 #include <ranges>
24 #include <string>
25 #include <vector>
26 
27 using namespace std;
28 
50 template <class S>
51 class NSGA2 : public AbstractGA<S> {
52  public:
53  NSGA2();
54 
55  virtual ~NSGA2() = default;
61  string getName() const override {
62  return "Non-dominated Sorting Genetic Algorithm II";
63  }
69  string getID() const override { return "NSGA-II"; }
70 
71  void run() override;
72 
73  void setProblem(shared_ptr<Problem<S>> prob) override;
74 
75  void setProblem(Problem<S> *prob) override;
76 
77  virtual Front<S> getResults() const;
78 
79  protected:
80  void initProgress() override;
81 
82  void updateProgress() override;
83 
84  virtual void createInitialPopulation() override;
85 
86  virtual void evaluatePopulation(vector<S> &pop) override;
87 
88  virtual vector<S> createMating() override;
89 
90  virtual void reproduction(S &, S &) override;
91 
92  private:
93  void rankPopulation();
94  vector<S> rankCrowdingPopulation(vector<S> &combinedPopulation);
95 };
96 
102 template <class S>
104 
111 template <class S>
113  this->population.resize(this->populationSize);
114  for (int i = 0; i < this->getPopulationSize(); i++) {
115  this->population[i] = this->problem->createSolution();
116  }
117  // Usamos el método por si empleamos un evaluador paralelo
118  this->evaluatePopulation(this->population);
119  // Reseteamos el printingcheck --> Para el uso de repeticiones en los
120  // experimentos
121  this->nextCheckpoint = 0;
122  this->updateEvolution(0, this->population);
123  this->initProgress();
124 }
125 
134 template <class S>
136  this->performedEvaluations = this->populationSize;
137 }
138 
152 template <class S>
154  if (this->problem) {
155  this->createInitialPopulation();
156  this->startTime = chrono::system_clock::now();
157  this->rankPopulation();
158  while (!this->isStoppingConditionReached()) {
159  vector offspring = this->createMating();
160 
161  offspring.insert(offspring.end(), this->population.begin(),
162  this->population.end());
163  this->population = this->rankCrowdingPopulation(offspring);
164  this->updateEvolution(this->performedEvaluations, this->population);
165  }
166  this->endTime = chrono::system_clock::now();
167  this->finishProgress();
168  } else {
169  throw std::runtime_error("Problem is not set in GA::run");
170  }
171 }
172 
178 template <class S>
180  vector<vector<S>> fronts =
181  fastNonDominatedSort(this->population, this->problem.get());
182  this->population.clear();
183  for (vector<S> front : fronts) {
184  for (S solution : front) {
185  this->population.push_back(solution);
186  }
187  }
188 }
189 
201 template <class S>
202 vector<S> NSGA2<S>::rankCrowdingPopulation(vector<S> &combinedPopulation) {
203  vector<vector<S>> fronts =
204  fastNonDominatedSort(combinedPopulation, this->problem.get());
205  vector<S> newPopulation;
206  newPopulation.reserve(this->populationSize);
207  auto toInsert = this->populationSize;
208  auto index = 0;
209  // We sort the front using the crowding operator
210  // Then we include each solution in the new population
211  std::for_each(fronts.begin(), fronts.end(),
212  [&](vector<S> &f) { crowOrder(f, this->problem.get()); });
213  // Include all solutions in the fronts that fits perfectly
214  bool fits = toInsert <= (int)fronts[0].size();
215  while (fits) {
216  for (S solution : fronts[index]) {
217  newPopulation.push_back(solution);
218  toInsert--;
219  if (toInsert == 0) {
220  break;
221  }
222  }
223  index++;
224  if ((toInsert <= 0) || (toInsert <= (int)fronts[index].size())) {
225  fits = false;
226  }
227  }
228  // If we don't have enough solutions yet to create a new population
229  // and the remaining fronts doesn't fit entirely, we include only
230  // the `n` necessary new solutions
231  if (toInsert > 0) {
232  vector<vector<S>> remaining(fronts.begin() + index, fronts.end());
233  auto jv = std::ranges::join_view(remaining);
234  std::ranges::for_each(
235  jv | std::ranges::views::take(toInsert),
236  [&](const S &solution) { newPopulation.push_back(solution); });
237  }
238  return newPopulation;
239 }
240 
248 template <class S>
249 void NSGA2<S>::evaluatePopulation(vector<S> &pop) {
250  this->evaluator->evaluate(pop, this->problem.get());
251 }
252 
261 template <class S>
263  // Generates offsprings
264  vector<S> offspring;
265  for (int i = 0; i < this->populationSize; i++) {
266  S child1 = this->selection->select(this->population);
267  S child2 = this->selection->select(this->population);
268  reproduction(child1, child2);
269  this->problem->evaluate(child1);
270  this->problem->evaluate(child2);
271  offspring.push_back(child1);
272  offspring.push_back(child2);
273  this->performedEvaluations += 2;
274  }
275  return offspring;
276 }
277 
286 template <class S>
287 void NSGA2<S>::reproduction(S &child1, S &child2) {
288  // Cruzamos los individuos con cierta probabilidad
289  if (PseudoRandom::randDouble() < this->crossRate) {
290  this->crossover->run(child1, child2);
291  }
292  this->mutation->run(child1, this->mutationRate, this->problem.get());
293  this->mutation->run(child2, this->mutationRate, this->problem.get());
294 }
295 
301 template <class S>
303  this->performedEvaluations += 2;
304 }
305 
313 template <class S>
314 void NSGA2<S>::setProblem(shared_ptr<Problem<S>> prob) {
315  if (prob->getNumberOfObjs() != 2) {
316  std::string where = "NSGA2 setProblem";
317  throw(NoMOAllowed(where));
318  }
319  this->problem = prob;
320 }
328 template <class S>
330  if (prob->getNumberOfObjs() != 2) {
331  std::string where = "NSGA2 setProblem";
332  throw(NoMOAllowed(where));
333  }
334  this->problem.reset(prob);
335 }
336 
343 template <class S>
345  Front<S> front(0);
346  std::ranges::for_each(this->population, [&](const S &solution) {
347  front.addSolution(solution, this->problem.get());
348  });
349  return front;
350 }
351 
352 #endif // DIGNEA_NSGA2_H
vector< vector< S > > fastNonDominatedSort(vector< S > &population, const Problem< S > *problem)
Fast Non Dominated Sorting operator. Sorts the population in different fronts Used in NSGA-II.
Definition: Sorter.h:158
Class to represent an Abstract Genetic Algorithm. Base skeleton is defined here, to extend in particu...
Definition: AbstractGA.h:38
Front class which stores the final results of an EA execution.
Definition: Front.h:26
void addSolution(const S &solution)
Includes a new solution in the front. This is only for single-objective solutions.
Definition: Front.h:144
Definition: NSGA2.h:51
void updateProgress() override
Updates the performed evaluations to the population size on each call.
Definition: NSGA2.h:302
NSGA2()
Creates a RAW instance of a Generational GA algorithm.
Definition: NSGA2.h:103
void initProgress() override
Starts the evolutionary process. By default this methods sets the number of performed evaluations to ...
Definition: NSGA2.h:135
virtual Front< S > getResults() const
Creates the front of solution from the evolution.
Definition: NSGA2.h:344
virtual void createInitialPopulation() override
Creates the initial population of individuals before starting the evolutionary process.
Definition: NSGA2.h:112
void run() override
Runs the evolutionary process. This is the main EA method. This methods is in charge of:
Definition: NSGA2.h:153
void setProblem(shared_ptr< Problem< S >> prob) override
Uptades the problem to solve using a share_ptr. The problem must be multi-objective.
Definition: NSGA2.h:314
virtual void reproduction(S &, S &) override
Applies the genetic operator. This methods is invoked from createMating.
Definition: NSGA2.h:287
virtual vector< S > createMating() override
Generates the mating population of individuals to be evaluated. The individuals are selected and afte...
Definition: NSGA2.h:262
string getID() const override
Get the ID of the algorithm.
Definition: NSGA2.h:69
string getName() const override
Get the Name.
Definition: NSGA2.h:61
virtual void evaluatePopulation(vector< S > &pop) override
Evaluates the entire population of individuals using the problem evaluation function.
Definition: NSGA2.h:249
Class to represent a Problem in the tool. It includes the basic information for a problem a few metho...
Definition: Problem.h:29
int getNumberOfObjs() const
Get the number of objectives of the problem.
Definition: Problem.h:135
static double randDouble()
Generates a random double value between 0.0 and 1.0.
Definition: PseudoRandom.cpp:31