GALib-Parallel
Header-only C++ library for parallel evolutionary algorithms
Loading...
Searching...
No Matches
StandardGACUDA.h
Go to the documentation of this file.
1#ifndef STANDARD_GA_CUDA_H
2#define STANDARD_GA_CUDA_H
3
4#pragma once
5
7#include "core/Population.h"
15
16#include <cstddef>
17#include <iostream>
18#include <memory>
19#include <vector>
20
21namespace galib {
22namespace cuda {
23
44template <typename GeneType = double>
45class StandardGACUDA : public Algorithm<GeneType> {
46public:
62 std::unique_ptr<Selection<GeneType>> sel,
63 std::unique_ptr<Mutation<GeneType>> mu,
64 std::unique_ptr<Crossover<GeneType>> cs,
65 double m_rate,
66 double c_rate,
67 std::size_t max_gen,
68 bool elitism = true
69 ) : fitness_function_m(ff),
70 selection_m(std::move(sel)),
71 mutation_m(std::move(mu)),
72 crossover_m(std::move(cs)),
73 mutation_rate_m(m_rate),
74 crossover_rate_m(c_rate),
75 max_generations_m(max_gen),
76 use_elitism_m(elitism) {}
77
90 void run(Population<GeneType>& population) override {
91 if (population.empty()) return;
92
93 const int pop_size = static_cast<int>(population.size());
94 const int dims = static_cast<int>(population.getNumGenes());
95
96 // Flatten Population<GeneType> → vector<float>
97 std::vector<float> h_genes(static_cast<std::size_t>(pop_size) * dims);
98 for (int i = 0; i < pop_size; ++i) {
99 const auto& g = population[i].getGenotype();
100 for (int j = 0; j < dims; ++j)
101 h_genes[static_cast<std::size_t>(i) * dims + j] = static_cast<float>(g[j]);
102 }
103
104 std::vector<float> h_fitness;
105
106 // Build params — fitness callback works for ANY FitnessFunction
108 params.pop_size = pop_size;
109 params.dims = dims;
110 params.max_generations = static_cast<int>(max_generations_m);
111 params.mutation_rate = static_cast<float>(mutation_rate_m);
112 params.crossover_rate = static_cast<float>(crossover_rate_m);
113 params.use_elitism = use_elitism_m;
114 // Extract tournament size from the actual operator if available
115 if (auto* ts = dynamic_cast<TournamentSelection<GeneType>*>(selection_m.get()))
116 params.tournament_size = static_cast<int>(ts->getTournamentSize());
117 else
118 params.tournament_size = 3;
119
120 // Extract sigma from the actual mutation operator if available
121 if (auto* gm = dynamic_cast<GaussianMutation<GeneType>*>(mutation_m.get()))
122 params.sigma = static_cast<float>(gm->getSigma());
123 else
124 params.sigma = 0.1f;
125
126 params.problem_name = fitness_function_m.name();
127
128 // CPU fallback: called for any function without a GPU kernel
129 params.fitness_callback = [this](const float* genes, int d) -> double {
130 std::vector<GeneType> phenotype(static_cast<std::size_t>(d));
131 for (int j = 0; j < d; ++j)
132 phenotype[static_cast<std::size_t>(j)] = static_cast<GeneType>(genes[j]);
133 return fitness_function_m.evaluate(phenotype);
134 };
135
136 // Progress — population lives on device during the run, so we print the
137 // GPU-reported best_fitness directly rather than routing through notifyLoggers
138 // (which would read the stale CPU population).
139 params.progress_callback = [this](int gen, double best_fitness) {
140 if ((gen + 1) % 50 == 0 || gen == 0) {
141 std::cout << "Generation " << (gen + 1)
142 << " | Best Fitness: " << best_fitness << std::endl;
143 }
144 };
145
146 if (!internal::runCUDAEvolution(params, h_genes, h_fitness)) {
147 std::cerr << "[GALib] CUDA evolution failed. Population unchanged.\n";
148 return;
149 }
150
151 // Write results back into Population<GeneType>
152 for (int i = 0; i < pop_size; ++i) {
153 auto& ind = population[static_cast<std::size_t>(i)];
154 auto& g = ind.getGenotype();
155 for (int j = 0; j < dims; ++j)
156 g[static_cast<std::size_t>(j)] =
157 static_cast<GeneType>(h_genes[static_cast<std::size_t>(i) * dims + j]);
158 ind.setFitness(static_cast<double>(h_fitness[static_cast<std::size_t>(i)]));
159 }
160 }
161
162private:
163 FitnessFunction<GeneType>& fitness_function_m;
164 std::unique_ptr<Selection<GeneType>> selection_m;
165 std::unique_ptr<Mutation<GeneType>> mutation_m;
166 std::unique_ptr<Crossover<GeneType>> crossover_m;
167
168 double mutation_rate_m;
169 double crossover_rate_m;
170 std::size_t max_generations_m;
171 bool use_elitism_m;
172
177 void evaluatePopulation(Population<GeneType>& population) {
178 int population_size = static_cast<int>(population.size());
179 #pragma omp parallel for schedule(dynamic)
180 for (int i = 0; i < population_size; ++i) {
181 double score = fitness_function_m.evaluate(population[i].getGenotype());
182 population[i].setFitness(score);
183 }
184 }
185};
186
187}
188}
189
190#endif // STANDARD_GA_CUDA_H
Abstract base class for all optimization algorithms.
Definition Algorithm.h:22
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.
Performs Gaussian mutation.
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
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
Performs k-way tournament selection.
Generational GA with the same interface as StandardGA, built for CUDA-enabled builds.
StandardGACUDA(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)
Constructs the algorithm with all required operators and parameters.
void run(Population< GeneType > &population) override
Runs the evolutionary optimisation loop.
bool runCUDAEvolution(CUDARunParams &params, std::vector< float > &h_genes, std::vector< float > &h_fitness)
Runs the full GA evolution loop on the GPU.
Parameters for a full GPU-accelerated evolution run.
float sigma
Gaussian mutation standard deviation.
std::function< double(const float *, int)> fitness_callback
std::function< void(int, double)> progress_callback