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) {
63 threads_m = std::thread::hardware_concurrency() / 2;
65 omp_set_num_threads(
static_cast<int>(threads_m));
69 if (population.
empty()) {
return; }
71 std::size_t population_size = population.
size();
76 evaluatePopulation(population);
78 for (std::size_t generation_idx = 0; generation_idx < max_generations_m; ++generation_idx) {
81 std::size_t elitism_offset = 0;
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);
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);
104 new_population[i] = parent1;
105 if (i + 1 < population_size) {
106 new_population[i + 1] = parent2;
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);
116 std::swap(population, new_population);
117 evaluatePopulation(population);
120 if (!this->
console_logger_m && ((generation_idx + 1) % 50 == 0 || generation_idx == 0)) {
121 std::cout <<
"Generation " << (generation_idx + 1)