dignea  1.0.0
Diverse Instance Generator with Novelty Search and Evolutionary Algorithms
ParallelGeneticAlgorithm.h
1 //
2 // Created by amarrero on 29/1/21.
3 //
4 
5 #ifndef DIGNEA_PARALLELGENETICALGORITHM_H
6 #define DIGNEA_PARALLELGENETICALGORITHM_H
7 
9 #include <dignea/evaluators/ParallelOMPEvaluator.h>
11 #include <dignea/utilities/random/ParallelPRNG.h>
12 #include <omp.h>
13 
14 #include <algorithm>
15 #include <iterator>
16 #include <ranges>
17 #include <vector>
18 
19 using namespace std;
20 
28 template <class S>
30  public:
32 
33  virtual ~ParallelGeneticAlgorithm();
39  virtual string getName() const override {
40  return "Parallel Genetic Algorithm";
41  };
42 
43  virtual void run() override;
49  int getNumberOfCores() const { return numberOfCores; }
55  void setNumberOfCores(int nCores) { this->numberOfCores = nCores; }
56 
57  void setProblem(shared_ptr<Problem<S>> prob) override;
63  const Problem<S> *getProblem() const { return problem.get(); }
64 
65  json to_json() const override;
66 
67  protected:
68  virtual void initProgress();
69 
70  virtual void updateProgress(){};
71 
72  void runEvolution();
73 
74  virtual void createInitialPopulation();
75 
76  virtual void reproduction(S &, S &);
77 
78  virtual void replacement(vector<S> &offsp){};
79 
80  string getID() const override { return "ParGA"; };
81 
82  protected:
83  S parallelSelection(const int &init, const int &end);
84 
85  void configureEnv();
86 
87  protected:
89  int chunks;
90  ParallelPRNG prng;
92  vector<S> individuals;
93  shared_ptr<Problem<S>> problem;
94  vector<float> bestEvolution;
95 };
96 
103 template <class S>
105  this->numberOfCores = 2; // Lets set 2 cores by default
106  this->chunks = 0;
107  this->evaluator = make_unique<ParallelOMPEvaluator<S>>(numberOfCores);
108 }
114 template <class S>
116  this->individuals.resize(this->populationSize);
117  this->performedEvaluations = 0;
118  this->chunks = this->populationSize / this->numberOfCores;
119  omp_set_num_threads(this->numberOfCores);
120 }
121 
122 template <class S>
124 
130 template <class S>
132  const int popDim = this->populationSize;
133  this->individuals.resize(popDim);
134 #pragma omp parallel for shared(problem) num_threads(numberOfCores)
135  for (int i = 0; i < popDim; i++) {
136  individuals[i] = problem->createSolution();
137  problem->evaluate(individuals[i]);
138  }
139  this->nextCheckpoint = 0;
140  this->initProgress();
141 }
142 
149 template <class S>
151  this->performedEvaluations = this->populationSize;
152 }
153 
163 template <class S>
165  if (this->problem) {
166  this->configureEnv();
167  this->bestEvolution.clear();
168  this->startTime = chrono::system_clock::now();
169  this->createInitialPopulation();
170  this->runEvolution();
171  this->endTime = chrono::system_clock::now();
172  this->finishProgress();
173  } else {
174  throw std::runtime_error("Problem is not set in ParallelGA::run");
175  }
176 }
177 
184 template <class S>
186  const float eps = 1e-9;
187  const int GENERATIONS = this->maxEvaluations / this->populationSize;
188  int performedGenerations = 0;
189  const int popDim = this->populationSize - 1;
190  do {
191  vector<S> offspring(this->populationSize);
192 #pragma omp parallel for schedule(dynamic)
193  for (int i = 0; i < this->populationSize; i++) {
194  // Previously we splitted the population by cores
195  // Splits thepopulation in chunks to perform the selection
196  // int init = omp_get_thread_num() * chunks;
197  // int end = init + (chunks - 1);
198  int idx1 = min(prng.randInt(0, popDim), prng.randInt(0, popDim));
199  int idx2 = min(prng.randInt(0, popDim), prng.randInt(0, popDim));
200  S child1 = individuals[idx1];
201  S child2 = individuals[idx2];
202  this->reproduction(child1, child2);
203  this->problem->evaluate(child1);
204  // Replacement
205  bool update = false;
206  double childPenalty = child1.getConstraintCoeff();
207  double individualPenalty = individuals[i].getConstraintCoeff();
208  double childFitness = child1.getFitness();
209  double individualFitness = individuals[i].getFitness();
210  // If child has less penalty or in equal penalty values it has
211  // better fitness
212  if (childPenalty < individualPenalty) {
213  update = true;
214  } else if ((abs(childPenalty - individualPenalty) < eps) &&
215  (childFitness > individualFitness)) {
216  update = true;
217  }
218  if (update) {
219  offspring[i] = child1;
220  // individuals[i] = child1;
221  } else {
222  offspring[i] = individuals[i];
223  }
224  }
225 // Replacement
226 #pragma omp parallel for schedule(dynamic)
227  for (int i = 0; i < this->populationSize; i++) {
228  this->individuals[i] = offspring[i];
229  }
230 #ifdef EVOLUTION
231  // Get the best fitness in the generation
232  auto it = std::ranges::max_element(individuals, {}, &S::getFitness);
233  if (it != end(individuals)) {
234  const auto pos = std::distance(begin(individuals), it);
235  this->bestEvolution.push_back(individuals[pos].getFitness());
236  }
237 #endif
238  // Updating the performed evaluations
239  performedGenerations++;
240  } while (performedGenerations < GENERATIONS);
241  // Updates superclass variables with this variables used for parallel
242  // executions
243  this->population = this->individuals;
244  this->performedEvaluations = this->maxEvaluations;
245 }
246 
252 template <class S>
253 void ParallelGeneticAlgorithm<S>::reproduction(S &child1, S &child2) {
254  if (prng.randDouble() < this->crossRate) {
255  this->crossover->run(child1, child2);
256  }
257  this->mutation->run(child1, this->mutationRate, problem.get());
258 }
259 
270 template <class S>
272  const int &end) {
273  int firstOption = prng.randInt(init, end);
274  int secondOption = prng.randInt(init, end);
275  S child = individuals[min(firstOption, secondOption)];
276  return child;
277 }
284 template <class S>
286  if (prob->getNumberOfObjs() != 1) {
287  std::string where = "Parallel Genetic Algorithm::setProblem";
288  throw(NoMOAllowed(where));
289  }
290  this->problem = prob;
291 }
299 template <class S>
301  json data = AbstractGA<S>::to_json();
302  data["num_cores"] = this->numberOfCores;
303 #ifdef EVOLUTION
304  data["evolution"] = this->bestEvolution;
305 #endif
306  return data;
307 }
308 
309 #endif // DIGNEA_PARALLELGENETICALGORITHM_H
Class to represent an Abstract Genetic Algorithm. Base skeleton is defined here, to extend in particu...
Definition: AbstractGA.h:38
json to_json() const override
Creates and returns JSON object with the GA information.
Definition: AbstractGA.h:463
Class to represents a Parallel Genetic Algorithm (ParGA). This algorithm runs the evolution in number...
Definition: ParallelGeneticAlgorithm.h:29
virtual void initProgress()
Starts the progress of the parallel algorithm Sets the performedEvaluations to the number of individu...
Definition: ParallelGeneticAlgorithm.h:150
void configureEnv()
Configures the parallel environment.
Definition: ParallelGeneticAlgorithm.h:115
virtual void reproduction(S &, S &)
Applies the genetic operators to the given individuals.
Definition: ParallelGeneticAlgorithm.h:253
virtual void createInitialPopulation()
Creates the initial population using parallel cores.
Definition: ParallelGeneticAlgorithm.h:131
json to_json() const override
Generates and returns a JSON representation of the ParallelGeneticAlgorithm.
Definition: ParallelGeneticAlgorithm.h:300
int numberOfCores
Definition: ParallelGeneticAlgorithm.h:88
string getID() const override
Returns the identificator of the algorithm, this is used in the to_json method. Must be implemented i...
Definition: ParallelGeneticAlgorithm.h:80
virtual void run() override
Run the parallel Algorithm.
Definition: ParallelGeneticAlgorithm.h:164
const Problem< S > * getProblem() const
Get a raw pointer to the problem to solve.
Definition: ParallelGeneticAlgorithm.h:63
ParallelPRNG prng
Definition: ParallelGeneticAlgorithm.h:90
void runEvolution()
Main method of the ParallelGeneticAlgorithm. Runs the evolution of the algorithm.
Definition: ParallelGeneticAlgorithm.h:185
virtual void updateProgress()
Method which updates the evolutionary progress. This method must be implemented in the subclasses and...
Definition: ParallelGeneticAlgorithm.h:70
virtual string getName() const override
Get the Name.
Definition: ParallelGeneticAlgorithm.h:39
ParallelGeneticAlgorithm()
Creates a default ParallelGeneticAlgorithm. Use the ParGABuilder class instead.
Definition: ParallelGeneticAlgorithm.h:104
S parallelSelection(const int &init, const int &end)
Parallel selection operator. This methods performs a binary tournament selection in the range [int,...
Definition: ParallelGeneticAlgorithm.h:271
int chunks
Definition: ParallelGeneticAlgorithm.h:89
int getNumberOfCores() const
Get the number of cores used.
Definition: ParallelGeneticAlgorithm.h:49
void setNumberOfCores(int nCores)
Set the number of cores to use.
Definition: ParallelGeneticAlgorithm.h:55
void setProblem(shared_ptr< Problem< S >> prob) override
Sets the problem to solve. Receives a share_ptr.
Definition: ParallelGeneticAlgorithm.h:285
Class to represent a Problem in the tool. It includes the basic information for a problem a few metho...
Definition: Problem.h:29