GALib-Parallel
Header-only C++ library for parallel evolutionary algorithms
Loading...
Searching...
No Matches
StandardGA.h
Go to the documentation of this file.
1#ifndef STANDARD_GA_H
2#define STANDARD_GA_H
3
4#pragma once
5
6#include "core/Population.h"
11
12#include <iostream>
13#include <random>
14#include <utility>
15#include <fstream>
16#include <omp.h>
17#include <filesystem>
18#include <thread>
19
21
22namespace galib {
23
24 template <typename GeneType = double>
25 class StandardGA : public Algorithm<GeneType> {
26 private:
27 FitnessFunction<GeneType>& fitness_function_m;
28 std::unique_ptr<Selection<GeneType>> selection_m;
29 std::unique_ptr<Mutation<GeneType>> mutation_m;
30 std::unique_ptr<Crossover<GeneType>> crossover_m;
31 std::size_t threads_m;
32
33 double mutation_rate_m;
34 double crossover_rate_m;
35 std::size_t max_generations_m;
36 bool use_elitism_m;
37
38 void evaluatePopulation(Population<GeneType>& population) {
39 int population_size = static_cast<int>(population.size());
40
41 #pragma omp parallel for schedule(dynamic)
42 for (int i = 0; i < population_size; ++i) {
43 double score = fitness_function_m.evaluate(population[i].getGenotype());
44 population[i].setFitness(score);
45 }
46 }
47
48 public:
51 std::unique_ptr<Selection<GeneType>> sel,
52 std::unique_ptr<Mutation<GeneType>> mu,
53 std::unique_ptr<Crossover<GeneType>> cs,
54 double m_rate,
55 double c_rate,
56 std::size_t max_gen,
57 bool elitism = true,
58 std::size_t threads = 1
59 ) : fitness_function_m(ff), selection_m(std::move(sel)), mutation_m(std::move(mu)), crossover_m(std::move(cs)),
60 mutation_rate_m(m_rate), crossover_rate_m(c_rate), max_generations_m(max_gen),
61 use_elitism_m(elitism), threads_m(threads) {
62 if (threads_m == 0) {
63 threads_m = std::thread::hardware_concurrency() / 2;
64 }
65 omp_set_num_threads(static_cast<int>(threads_m));
66 }
67
68 void run(Population<GeneType>& population) override {
69 if (population.empty()) { return; }
70
71 std::size_t population_size = population.size();
72 std::size_t num_genes = population.getNumGenes();
73
74 Population<GeneType> new_population(population_size, num_genes);
75
76 evaluatePopulation(population);
77
78 for (std::size_t generation_idx = 0; generation_idx < max_generations_m; ++generation_idx) {
79 this->notifyLoggers(generation_idx, population);
80
81 std::size_t elitism_offset = 0;
82
83 if (use_elitism_m) {
84 new_population[0] = population.getBestIndividual();
85 elitism_offset = 1;
86 }
87
88 #pragma omp parallel for schedule(static)
89 for (std::size_t i = elitism_offset; i < population_size; i += 2) {
90 thread_local static std::random_device tl_rd;
91 thread_local static std::mt19937_64 tl_gen(tl_rd());
92 thread_local static std::uniform_real_distribution<double> tl_dist(0.0, 1.0);
93
94 const Individual<GeneType>& parent1 = selection_m->select(population);
95 const Individual<GeneType>& parent2 = selection_m->select(population);
96
97 if (tl_dist(tl_gen) < crossover_rate_m) {
98 auto children = crossover_m->crossover(parent1, parent2);
99 new_population[i] = std::move(children.first);
100 if (i + 1 < population_size) {
101 new_population[i + 1] = std::move(children.second);
102 }
103 } else {
104 new_population[i] = parent1;
105 if (i + 1 < population_size) {
106 new_population[i + 1] = parent2;
107 }
108 }
109
110 mutation_m->mutate(new_population[i], mutation_rate_m);
111 if (i + 1 < population_size) {
112 mutation_m->mutate(new_population[i + 1], mutation_rate_m);
113 }
114 }
115
116 std::swap(population, new_population);
117 evaluatePopulation(population);
118
119 this->notifyLoggers(generation_idx, population);
120 if (!this->console_logger_m && ((generation_idx + 1) % 50 == 0 || generation_idx == 0)) {
121 std::cout << "Generation " << (generation_idx + 1)
122 << " | Best Fitness: " << population.getBestIndividual().getFitness()
123 << std::endl;
124 }
125 }
126 }
127 };
128
129}
130
131#endif // STANDARD_GA_H
Abstract base class for all optimization algorithms.
Definition Algorithm.h:22
std::unique_ptr< utils::ConsoleLogger< GeneType > > console_logger_m
Definition Algorithm.h:24
void notifyLoggers(std::size_t gen, const Population< GeneType > &pop)
Notifies all active loggers to record the current state.
Definition Algorithm.h:32
Interface for crossover (recombination) operators.
Definition Crossover.h:20
Abstract base class for objective functions to be minimized.
virtual double evaluate(const std::vector< GeneType > &phenotype) const =0
Evaluates the fitness of a candidate solution.
Represents a single candidate solution in the population.
Definition Individual.h:23
Interface for mutation operators.
Definition Mutation.h:19
A container for a group of individuals in the genetic algorithm.
Definition Population.h:24
bool empty() const
Checks if the population is empty.
Definition Population.h:74
std::size_t getNumGenes() const
Returns the number of genes for individuals in this population.
Definition Population.h:80
const Individual< GeneType > & getBestIndividual() const
Finds and returns the individual with the best fitness score.
Definition Population.h:112
std::size_t size() const
Returns the total number of individuals in the population.
Definition Population.h:68
Interface for selection operators.
Definition Selection.h:20
void run(Population< GeneType > &population) override
Executes the optimization process on the given population.
Definition StandardGA.h:68
StandardGA(FitnessFunction< GeneType > &ff, std::unique_ptr< Selection< GeneType > > sel, std::unique_ptr< Mutation< GeneType > > mu, std::unique_ptr< Crossover< GeneType > > cs, double m_rate, double c_rate, std::size_t max_gen, bool elitism=true, std::size_t threads=1)
Definition StandardGA.h:49