From b2f164f4646b37cd7e560062a0fb3ead5898f6ce Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 14 Apr 2018 08:33:25 -0700 Subject: [PATCH] Elitism and CopyChromosomes() --- Enums.h | 9 +++ Population.cpp | 197 ++++++++++++++++++++++++++++++++++++++++++++++--- Population.h | 38 +++++++++- 3 files changed, 229 insertions(+), 15 deletions(-) diff --git a/Enums.h b/Enums.h index a3791c9..0d524db 100644 --- a/Enums.h +++ b/Enums.h @@ -15,6 +15,15 @@ namespace BitEvolver None, Sexual }; + + // + enum class ElitismType + { + // + None, + Rate, + Absolute + }; }; }; diff --git a/Population.cpp b/Population.cpp index ce01929..5b58b64 100644 --- a/Population.cpp +++ b/Population.cpp @@ -17,12 +17,16 @@ #include #include #include +#include +#include // namespace BitEvolver { // + using std::string; + using std::stringstream; using std::cout; using std::endl; @@ -45,6 +49,11 @@ namespace BitEvolver this->evolution_number = 0; this->population_size = Population::DEFAULT_POPULATION_SIZE; + // + this->SetElitismType(Population::DEFAULT_ELITISM_TYPE); + this->SetElitismRate(Population::DEFAULT_ELITISM_RATE); + this->SetElitismCount(Population::DEFAULT_ELITISM_COUNT); + // this->SetCrossoverType(Population::DEFAULT_CROSSOVER_TYPE); this->SetCrossoverPoint(Population::DEFAULT_CROSSOVER_POINT); @@ -198,6 +207,48 @@ namespace BitEvolver return this->mutation_rate; } + // + void Population::SetElitismType(Enums::ElitismType t) + { + // + this->elitism_type = t; + } + + // + Enums::ElitismType Population::GetElitismType() + { + // + return this->elitism_type; + } + + // + void Population::SetElitismRate(double r) + { + // + this->elitism_rate = r; + } + + // + double Population::GetElitismRate() + { + // + return this->elitism_rate; + } + + // + void Population::SetElitismCount(int c) + { + // + this->elitism_count = c; + } + + // + int Population::GetElitismCount() + { + // + return this->elitism_count; + } + // void Population::EvaluateFitness(std::function)> evaluation_callback) { @@ -299,11 +350,6 @@ namespace BitEvolver new std::vector>() ); - // Start the new population off with our champion, - // so the best score always carries over (elitism = 1 unit) - #warning "Elitism is only 1 right now" - population_new->push_back(this->chromosomes[0]); - // Breed the new population this->BreedNewPopulation(population_new, (int)this->chromosomes.size()); @@ -403,7 +449,6 @@ namespace BitEvolver void Population::BreedNewPopulation(std::shared_ptr>> population_new, int size) { // - std::shared_ptr wheel; std::vector> threads; std::shared_ptr thread; int @@ -414,21 +459,25 @@ namespace BitEvolver // First, populate the roulette wheel this->roulette_wheel->SetChromosomes(this->chromosomes); - // - thread_count = this->GetThreadCountSuggestion(); + // Next, seed the population with elites + this->SeedPopulationWithElites(population_new); - // + // Next, breed until we've reached our new size + thread_count = this->GetThreadCountSuggestion(); for ( i=0; i( new std::thread(&Population::BreedNewPopulation_Thread, this, population_new, size) ); threads.push_back(thread); } - - // for ( i=0; i<(int)threads.size(); i++) { threads[i]->join(); } + + // Finally, reset the fitness of the new population + for ( i=0; i<(int)population_new->size(); i++ ) { + population_new->at(i)->ResetFitness(); + } } // @@ -452,6 +501,63 @@ namespace BitEvolver } } + // + int Population::DetermineEliteCount() + { + // + int count; + + // + switch( this->elitism_type ) + { + // + default: + case Enums::ElitismType::None: + count = 0; + break; + + // + case Enums::ElitismType::Absolute: + count = this->elitism_count; + break; + + // + case Enums::ElitismType::Rate: + count = floor( this->chromosomes.size() * this->elitism_rate ); + break; + } + + return count; + } + + // + void Population::SeedPopulationWithElites(std::shared_ptr>> population_new) + { + // + std::unique_lock lock(this->population_modification_mutex); + std::shared_ptr>> elites; + std::vector> threads; + std::shared_ptr thread; + int + elites_count, + i + ; + + // Determine how many elites to copy + elites_count = this->DetermineEliteCount(); + elites = std::shared_ptr>>( + new std::vector>() + ); + + // First, copy over just the pointers + for ( i=0; ichromosomes.size(); i++) { + elites->push_back( this->chromosomes[i] ); + } + + // Then, make them full copies (uses threads) + this->CopyChromosomes(elites, population_new); + } + // void Population::EvaluateFitness_Thread( std::shared_ptr>> _chromosomes, @@ -522,6 +628,75 @@ namespace BitEvolver } } + // + void Population::CopyChromosomes( + std::shared_ptr>> _chromosomes_source, + std::shared_ptr>> _chromosomes_destination + ) + { + // + std::vector> threads; + std::shared_ptr thread; + int + threads_count, + i + ; + + // Spawn threads + threads_count = this->GetThreadCountSuggestion(); + for ( i=0; i( + new std::thread(&Population::CopyChromosomes_Thread, this, _chromosomes_source, _chromosomes_destination) + ); + threads.push_back(thread); + } + + // Wait for threads to finish + for ( i=0; ijoin(); + } + } + + // + void Population::CopyChromosomes_Thread( + std::shared_ptr>> _chromosomes_source, + std::shared_ptr>> _chromosomes_destination + ) + { + // + std::shared_ptr + chromosome_original, + chromosome_copied + ; + stringstream ss; + + // + while ( _chromosomes_destination->size() < _chromosomes_source->size() ) + { + // Grab the next slot + this->copy_chromosomes_mutex.lock(); + chromosome_original = nullptr; + chromosome_copied = nullptr; + if ( _chromosomes_destination->size() < _chromosomes_source->size() ) { + + // + chromosome_copied = std::shared_ptr( + new Chromosome(this->random, 0) + ); + _chromosomes_destination->push_back(chromosome_copied); + chromosome_original = _chromosomes_source->at(_chromosomes_destination->size()-1); + } + this->copy_chromosomes_mutex.unlock(); + + // Make a full copy of the original, outside the lock + if ( chromosome_copied && chromosome_original ) { + *chromosome_copied = *chromosome_original; + } + } + } + // std::shared_ptr Population::BreedChild() { diff --git a/Population.h b/Population.h index 776c492..ca60a63 100644 --- a/Population.h +++ b/Population.h @@ -55,6 +55,13 @@ namespace BitEvolver // void SetMutationRate(double r); double GetMutationRate(); + // + void SetElitismType(Enums::ElitismType t); + Enums::ElitismType GetElitismType(); + void SetElitismRate(double r); + double GetElitismRate(); + void SetElitismCount(int c); + int GetElitismCount(); // void EvaluateFitness(std::function)> evaluation_callback); @@ -69,8 +76,11 @@ namespace BitEvolver void PrintPopulation(std::vector> _chromosomes); // Constants - const static int DEFAULT_POPULATION_SIZE = 100; - const static int DEFAULT_MUTATION_RATE = 0.01; + const static int DEFAULT_POPULATION_SIZE = 100; + const static Enums::ElitismType DEFAULT_ELITISM_TYPE = Enums::ElitismType::Rate; + constexpr static double DEFAULT_ELITISM_RATE = 0.01; + const static int DEFAULT_ELITISM_COUNT = 1; + constexpr static double DEFAULT_MUTATION_RATE = 0.01; // const static Enums::CrossoverType DEFAULT_CROSSOVER_TYPE = Enums::CrossoverType::Sexual; const static int DEFAULT_CROSSOVER_POINT = 0.7; @@ -86,10 +96,15 @@ namespace BitEvolver std::vector> chromosomes; int population_size; bool population_needs_sorting; + int evolution_number; + + // Enums::CrossoverType crossover_type; double crossover_point; double mutation_rate; - int evolution_number; + Enums::ElitismType elitism_type; + double elitism_rate; + int elitism_count; // std::shared_ptr roulette_wheel; @@ -98,7 +113,8 @@ namespace BitEvolver std::recursive_mutex population_modification_mutex, breed_mutex, - evaluate_fitness_mutex + evaluate_fitness_mutex, + copy_chromosomes_mutex ; // @@ -113,6 +129,10 @@ namespace BitEvolver void BreedNewPopulation(std::shared_ptr>> population_new, int size); void BreedNewPopulation_Thread(std::shared_ptr>> population_new, int size); + // + int DetermineEliteCount(); + void SeedPopulationWithElites(std::shared_ptr>> population_new); + // void EvaluateFitness_Thread( std::shared_ptr>> _chromosomes, @@ -123,6 +143,16 @@ namespace BitEvolver std::function)> evaluation_callback ); + // + void CopyChromosomes( + std::shared_ptr>> _chromosomes_source, + std::shared_ptr>> _chromosomes_destination + ); + void CopyChromosomes_Thread( + std::shared_ptr>> _chromosomes_source, + std::shared_ptr>> _chromosomes_destination + ); + // std::shared_ptr BreedChild();