53 std::unique_ptr<LocalSelection<GeneType>> local_selection_m;
54 std::unique_ptr<Mutation<GeneType>> mutation_m;
55 std::unique_ptr<Crossover<GeneType>> crossover_m;
57 double mutation_rate_m;
58 double crossover_rate_m;
59 std::size_t max_generations_m;
60 std::size_t threads_m;
61 bool use_local_elitism_m;
67 static std::pair<std::size_t, std::size_t> inferGridShape(std::size_t population_size) {
68 if (population_size == 0) {
69 throw std::invalid_argument(
"Population size cannot be zero.");
72 std::size_t rows =
static_cast<std::size_t
>(std::sqrt(
static_cast<long double>(population_size)));
73 while (rows > 1 && population_size % rows != 0) {
77 return {rows, population_size / rows};
81 const std::size_t population_size = population.
size();
84 tbb::blocked_range<std::size_t>(0, population_size),
85 [&](
const tbb::blocked_range<std::size_t>& range) {
86 for (std::size_t i = range.begin(); i < range.end(); ++i) {
87 const double score = fitness_function_m.
evaluate(population[i].getGenotype());
88 population[i].setFitness(score);
99 thread_local static std::random_device rd;
100 thread_local static std::mt19937_64 gen(rd());
101 thread_local static std::uniform_real_distribution<double> dist(0.0, 1.0);
104 const Individual<GeneType>& neighbor = local_selection_m->select(population, row, col, rows_m, cols_m);
109 if (dist(gen) < crossover_rate_m) {
110 auto children = crossover_m->crossover(current, neighbor);
111 child1 = std::move(children.first);
112 child2 = std::move(children.second);
118 mutation_m->mutate(child1, mutation_rate_m);
119 mutation_m->mutate(child2, mutation_rate_m);
124 if (use_local_elitism_m) {
167 : fitness_function_m(ff),
168 local_selection_m(std::move(local_sel)),
169 mutation_m(std::move(mu)),
170 crossover_m(std::move(cs)),
171 mutation_rate_m(m_rate),
172 crossover_rate_m(c_rate),
173 max_generations_m(max_gen),
177 use_local_elitism_m(elitism) {}
191 if (population.
empty()) {
195 std::tie(rows_m, cols_m) = inferGridShape(population.
size());
198 std::unique_ptr<tbb::global_control> tbb_control;
201 tbb_control = std::make_unique<tbb::global_control>(
202 tbb::global_control::max_allowed_parallelism,
207 evaluatePopulation(population);
209 for (std::size_t generation_idx = 0; generation_idx < max_generations_m; ++generation_idx) {
213 tbb::blocked_range<std::size_t>(0, population.
size()),
214 [&](
const tbb::blocked_range<std::size_t>& range) {
215 for (std::size_t i = range.begin(); i < range.end(); ++i) {
216 const std::size_t row = i / cols_m;
217 const std::size_t col = i % cols_m;
219 new_population[i] = evolveCell(population, row, col);
224 std::swap(population, new_population);
CellularGA(FitnessFunction< GeneType > &ff, std::unique_ptr< LocalSelection< GeneType > > local_sel, std::unique_ptr< Mutation< GeneType > > mu, std::unique_ptr< Crossover< GeneType > > cs, double m_rate, double c_rate, std::size_t max_gen, std::size_t threads, bool elitism=false)
Constructs the cellular genetic algorithm with all required operators.