34 #ifndef MC2LIB_SIMPLEGA_HPP_ 35 #define MC2LIB_SIMPLEGA_HPP_ 44 #include <unordered_set> 69 template <
class URNG,
class GenomeT,
class C,
bool one_point =
false,
72 const GenomeT& mate2,
float mutation_rate,
74 assert(!mate1.get().empty());
75 assert(!mate2.get().empty());
77 std::uniform_int_distribution<std::size_t> dist1(0, mate1.get().size() - 1);
78 std::uniform_int_distribution<std::size_t> dist2(0, mate2.get().size() - 1);
80 const std::size_t cut1 = dist1(urng);
81 const std::size_t cut2 = one_point ? cut1 : dist2(urng);
84 auto cut_and_splice = [](
const GenomeT& a,
const GenomeT& b,
85 std::size_t cut_a, std::size_t cut_b) {
86 auto result = a.get();
87 auto ita = result.begin();
88 std::advance(ita, cut_a);
89 result.erase(ita, result.end());
90 auto itb = b.get().begin();
91 std::advance(itb, cut_b);
92 result.insert(result.end(), itb, b.get().end());
93 return GenomeT(a, b, result);
97 GenomeT child1 = cut_and_splice(mate1, mate2, cut1, cut2);
98 if (child1.get().size()) {
99 child1.Mutate(mutation_rate);
100 container->push_back(std::move(child1));
105 GenomeT child2 = cut_and_splice(mate2, mate1, cut2, cut1);
106 if (child2.get().size()) {
107 child2.Mutate(mutation_rate);
108 container->push_back(std::move(child2));
145 explicit Genome(Container g) : genome_(std::move(g)) {}
154 const Container&
get()
const {
return genome_; }
172 return Fitness() > rhs.
Fitness();
180 virtual void Mutate(
float rate) = 0;
187 virtual float Fitness()
const = 0;
195 virtual operator float()
const {
return Fitness(); }
200 virtual operator std::string()
const {
201 std::ostringstream oss;
204 for (
const auto& v : genome_) {
205 oss << (first ?
"" :
", ") << v;
225 template <
class GenomeT>
235 explicit GenePool(std::size_t target_population_size = 80,
236 float mutation_rate = 0.02f)
237 : target_population_size_(target_population_size),
238 mutation_rate_(mutation_rate),
241 if (mutation_rate_ > 1.0f) {
242 mutation_rate_ = 1.0f;
243 }
else if (mutation_rate_ < 0.0f) {
244 mutation_rate_ = 0.0f;
248 population_.resize(target_population_size_);
251 explicit GenePool(Population population,
float mutation_rate = 0.02f)
252 : target_population_size_(population.size()),
253 mutation_rate_(mutation_rate),
255 population_(std::move(population)) {}
257 explicit GenePool(Selection selection,
float mutation_rate = 0.02f)
258 : target_population_size_(selection.size()),
259 mutation_rate_(mutation_rate),
261 for (
const auto& gptr : selection) {
262 population_.push_back(*gptr);
266 operator std::string()
const {
267 std::ostringstream oss;
271 for (
const auto& genome : population_) {
272 oss << (first ?
"" :
", ") << static_cast<std::string>(genome);
280 const Population&
get()
const {
return population_; }
282 Population*
get_ptr() {
return &population_; }
287 mutation_rate_ = mutation_rate;
294 std::size_t
steps()
const {
return steps_; }
298 for (
const auto& g : population_) {
299 result += g.Fitness();
301 return result / population_.size();
305 return std::max_element(population_.begin(), population_.end())->Fitness();
309 return std::min_element(population_.begin(), population_.end())->Fitness();
315 void Sort() { population_.Sort(); }
318 return *std::min_element(population_.begin(), population_.end());
326 result.reserve(population_.size());
327 for (GenomeT& g : population_) {
328 result.push_back(&g);
336 template <
class URNG,
class DIST>
337 Selection
SelectDist(URNG& urng, DIST& dist, std::size_t count) {
338 assert(population_.size() >= count);
340 std::unordered_set<std::size_t> used;
342 result.reserve(count);
344 while (result.size() < count) {
345 std::size_t idx = dist(urng);
346 if (used.find(idx) != used.end()) {
350 auto it = population_.begin();
351 std::advance(it, idx);
352 result.push_back(&(*it));
363 template <
class URNG>
365 std::discrete_distribution<std::size_t> dist(population_.begin(),
367 return SelectDist(urng, dist, count);
374 template <
class URNG>
376 std::uniform_int_distribution<std::size_t> dist(0, population_.size() - 1);
377 return SelectDist(urng, dist, count);
384 std::sort(v->begin(), v->end(), [](
const GenomeT* lhs,
const GenomeT* rhs) {
385 return (*lhs) < (*rhs);
396 template <
class URNG,
class CrossoverMutateFunc>
397 void Step(URNG& urng, CrossoverMutateFunc crossover_mutate,
398 const Selection& selection, std::size_t mates, std::size_t keep = 0,
399 std::size_t mate1_stride = 1, std::size_t mate2_stride = 1) {
400 assert(selection.size() >= mates);
401 assert(selection.size() >= keep);
403 std::size_t replace = selection.size() - keep;
406 const std::size_t target_population_size =
407 target_population_size_ + replace;
410 for (std::size_t i = 0; i < mates; i += mate1_stride) {
411 const auto mate1 = selection[i];
414 for (std::size_t j = i + 1; j < mates; j += mate2_stride) {
415 const auto mate2 = selection[j];
417 crossover_mutate(urng, *mate1, *mate2, mutation_rate_, &population_);
419 if (population_.size() >= target_population_size) {
427 auto selection_start = selection.begin();
428 std::advance(selection_start, keep);
430 for (
auto it = population_.begin();
431 it != population_.end() && replace > 0;) {
432 const GenomeT* val = &(*it);
433 auto match = std::find(selection_start, selection.end(), val);
435 if (match != selection.end()) {
436 if (match == selection_start) {
440 it = population_.erase(it);
447 assert(population_.size() >= target_population_size_);
Helper to manages and evolve a populates.
Definition: simplega.hpp:226
Selection SelectRoulette(URNG &urng, std::size_t count)
Definition: simplega.hpp:364
Container genome_
Raw genome of individual genes of T.
Definition: simplega.hpp:216
void SelectionSort(Selection *v)
Definition: simplega.hpp:383
std::vector< T > Container
Definition: simplega.hpp:131
std::size_t target_population_size_
Definition: simplega.hpp:455
Simple Genome interface.
Definition: simplega.hpp:129
void set_mutation_rate(float mutation_rate)
Definition: simplega.hpp:286
Container * get_ptr()
Modifiable genome accessor.
Definition: simplega.hpp:161
std::list< GenomeT > Population
Definition: simplega.hpp:232
Selection SelectAll()
Definition: simplega.hpp:324
GenePool(std::size_t target_population_size=80, float mutation_rate=0.02f)
Definition: simplega.hpp:235
virtual ~Genome()
Definition: simplega.hpp:147
Population population_
Definition: simplega.hpp:458
float mutation_rate() const
Definition: simplega.hpp:284
virtual bool operator<(const Genome &rhs) const
Less than comparison operator.
Definition: simplega.hpp:171
float mutation_rate_
Definition: simplega.hpp:456
void Step(URNG &urng, CrossoverMutateFunc crossover_mutate, const Selection &selection, std::size_t mates, std::size_t keep=0, std::size_t mate1_stride=1, std::size_t mate2_stride=1)
Definition: simplega.hpp:397
Selection SelectUniform(URNG &urng, std::size_t count)
Definition: simplega.hpp:375
std::size_t target_population_size() const
Definition: simplega.hpp:290
std::size_t steps() const
Definition: simplega.hpp:294
void CutSpliceMutate(URNG &urng, const GenomeT &mate1, const GenomeT &mate2, float mutation_rate, C *container)
Definition: simplega.hpp:71
float BestFitness() const
Definition: simplega.hpp:308
std::vector< GenomeT * > Selection
Definition: simplega.hpp:233
Genome(Container g)
Converting constructor.
Definition: simplega.hpp:145
Genome()
Default constructor.
Definition: simplega.hpp:138
GenePool(Selection selection, float mutation_rate=0.02f)
Definition: simplega.hpp:257
GenePool(Population population, float mutation_rate=0.02f)
Definition: simplega.hpp:251
void Sort()
Definition: simplega.hpp:315
std::size_t steps_
Definition: simplega.hpp:457
Population * get_ptr()
Definition: simplega.hpp:282
Selection SelectDist(URNG &urng, DIST &dist, std::size_t count)
Definition: simplega.hpp:337
virtual float Fitness() const =0
Fitness accessor.
float WorstFitness() const
Definition: simplega.hpp:304
const GenomeT & SelectBest() const
Definition: simplega.hpp:317
std::size_t population_size() const
Definition: simplega.hpp:292
float AverageFitness() const
Definition: simplega.hpp:296