GALib-Parallel
Header-only C++ library for parallel evolutionary algorithms
Loading...
Searching...
No Matches
DifferentialEvolutionGA.h
Go to the documentation of this file.
1#ifndef DIFFERENTIAL_EVOLUTION_GA_H
2#define DIFFERENTIAL_EVOLUTION_GA_H
3
4#pragma once
5
6#include "core/Population.h"
8#include <iostream>
9#include <random>
10#include <vector>
11#include <fstream>
12#include <omp.h>
13#include <filesystem>
14#include <algorithm> // для std::clamp
15#include <thread>
16
18
19namespace galib {
20
21 template <typename GeneType = double>
22 class DifferentialEvolutionGA : public Algorithm<GeneType> {
23 private:
24 FitnessFunction<GeneType>& fitness_function_m;
25
26 double F_m; // differential weight [0, 2]
27 double CR_m; // crossover rate (probability) [0, 1]
28 std::size_t max_generations_m;
29 std::size_t threads_m;
30
31 void evaluatePopulation(Population<GeneType>& population) {
32 int pop_size = static_cast<int>(population.size());
33 #pragma omp parallel for schedule(dynamic)
34 for (int i = 0; i < pop_size; ++i) {
35 double score = fitness_function_m.evaluate(population[i].getGenotype());
36 population[i].setFitness(score);
37 }
38 }
39
40 public:
43 double f_weight,
44 double cr_rate,
45 std::size_t max_gen,
46 std::size_t threads = 1
47 ) : fitness_function_m(ff), F_m(f_weight), CR_m(cr_rate), max_generations_m(max_gen), threads_m(threads) {
48 if (threads_m == 0) {
49 threads_m = std::thread::hardware_concurrency() / 2;
50 }
51 omp_set_num_threads(static_cast<int>(threads_m));
52 }
53
54 void run(Population<GeneType>& population) override {
55 if (population.empty()) return;
56
57 std::size_t pop_size = population.size();
58 std::size_t num_genes = population.getNumGenes();
59
60 Population<GeneType> new_population(pop_size, num_genes);
61 evaluatePopulation(population);
62
63 std::random_device master_rd;
64 unsigned int master_seed = master_rd();
65
66 for (std::size_t generation_idx = 0; generation_idx < max_generations_m; ++generation_idx) {
67 this->notifyLoggers(generation_idx, population);
68
69 #pragma omp parallel
70 {
71 std::mt19937_64 tl_gen(master_seed + omp_get_thread_num() + generation_idx);
72 std::uniform_real_distribution<double> tl_dist(0.0, 1.0);
73 std::uniform_int_distribution<std::size_t> tl_int_dist(0, pop_size - 1);
74 std::uniform_int_distribution<std::size_t> tl_gene_dist(0, num_genes - 1);
75
76 #pragma omp for schedule(static)
77 for (int i = 0; i < static_cast<int>(pop_size); ++i) {
78
79 std::size_t r1, r2, r3;
80 do { r1 = tl_int_dist(tl_gen); } while (r1 == static_cast<std::size_t>(i));
81 do { r2 = tl_int_dist(tl_gen); } while (r2 == static_cast<std::size_t>(i) || r2 == r1);
82 do { r3 = tl_int_dist(tl_gen); } while (r3 == static_cast<std::size_t>(i) || r3 == r1 || r3 == r2);
83
84 const auto& target = population[i].getGenotype();
85 const auto& x_r1 = population[r1].getGenotype();
86 const auto& x_r2 = population[r2].getGenotype();
87 const auto& x_r3 = population[r3].getGenotype();
88
89 Individual<GeneType> trial_ind(num_genes);
90 auto& trial = trial_ind.getGenotype();
91
92 std::size_t j_rand = tl_gene_dist(tl_gen);
93
94 // mutation
95 if (num_genes >= 4) {
96 #pragma omp simd
97 for (std::size_t j = 0; j < num_genes; ++j) {
98 trial[j] = x_r1[j] + F_m * (x_r2[j] - x_r3[j]);
99 }
100 } else {
101 for (std::size_t j = 0; j < num_genes; ++j) {
102 trial[j] = x_r1[j] + F_m * (x_r2[j] - x_r3[j]);
103 }
104 }
105
106 // crossover
107 for (std::size_t j = 0; j < num_genes; ++j) {
108 if (tl_dist(tl_gen) <= CR_m || j == j_rand) {
109 trial[j] = std::clamp(trial[j], fitness_function_m.getLowerBound(j), fitness_function_m.getUpperBound(j));
110 } else {
111 trial[j] = target[j];
112 }
113 }
114
115 // selection
116 double trial_fitness = fitness_function_m.evaluate(trial);
117 trial_ind.setFitness(trial_fitness);
118
119 if (trial_fitness <= population[i].getFitness()) {
120 new_population[i] = std::move(trial_ind);
121 } else {
122 new_population[i] = population[i];
123 }
124 }
125 }
126
127 std::swap(population, new_population);
128 }
129
130 this->notifyLoggers(max_generations_m, population);
131 }
132 };
133}
134
135#endif // DIFFERENTIAL_EVOLUTION_GA_H
Abstract base class for all optimization algorithms.
Definition Algorithm.h:22
void notifyLoggers(std::size_t gen, const Population< GeneType > &pop)
Notifies all active loggers to record the current state.
Definition Algorithm.h:32
void run(Population< GeneType > &population) override
Executes the optimization process on the given population.
DifferentialEvolutionGA(FitnessFunction< GeneType > &ff, double f_weight, double cr_rate, std::size_t max_gen, std::size_t threads=1)
Abstract base class for objective functions to be minimized.
virtual GeneType getLowerBound(std::size_t dimension) const =0
Gets the lower bound for a specific dimension.
virtual GeneType getUpperBound(std::size_t dimension) const =0
Gets the upper bound for a specific dimension.
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
std::vector< GeneType > & getGenotype()
Returns a reference to the genotype vector.
Definition Individual.h:53
void setFitness(double new_fitness)
Sets a new fitness score.
Definition Individual.h:83
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
std::size_t size() const
Returns the total number of individuals in the population.
Definition Population.h:68