// #include "BitEvolver/Includes.h" #include "BitEvolver/Random.h" #include "BitEvolver/Population.h" #include "BitEvolver/Breeder.h" #include "BitEvolver/RouletteWheel.h" #include "BitEvolver/Chromosome.h" // #include #include #include #include #include #include #include #include #include // namespace BitEvolver { // using std::string; using std::stringstream; using std::cout; using std::endl; // Population::Population() { // this->InitRandomGenerator(); this->InitRouletteWheel(); this->InitBreeder(); // this->Reset(); } // void Population::Reset() { // 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->SetCrossoverOrder(Population::DEFAULT_CROSSOVER_ORDER); this->SetCrossoverBounds(Population::DEFAULT_CROSSOVER_BOUNDS); this->SetCrossoverPoint(Population::DEFAULT_CROSSOVER_POINT); this->SetCrossoverPointStandardDeviation(Population::DEFAULT_CROSSOVER_POINT_STD); // this->SetMutationRate(Population::DEFAULT_MUTATION_RATE); // this->RandomizePopulation(this->population_size); } // void Population::ClearPopulation() { // this->chromosomes.clear(); this->evolution_number = 0; } // void Population::InitRandomPopulation(int _population_size, int _bit_length) { // this->population_size = _population_size; // this->RandomizePopulation(_bit_length); } // void Population::RandomizePopulation(int _bit_length) { // std::shared_ptr chromosome; int i; // this->ClearPopulation(); for ( i=0; ipopulation_size; i++ ) { // chromosome = std::shared_ptr( new Chromosome( this->random, _bit_length ) ); this->chromosomes.push_back(chromosome); } } // void Population::PopulationChanged() { // this->population_needs_sorting = true; } // std::vector> Population::GetChromosomes() { return this->chromosomes; } // void Population::GetChromosomes(std::shared_ptr>> _chromosomes) { // _chromosomes->clear(); for ( std::shared_ptr chromosome : this->chromosomes) { _chromosomes->push_back(chromosome); } } // std::shared_ptr Population::GetChampion() { // this->EnsureSortedPopulation(); // if ( this->chromosomes.size() > 0 ) { return this->chromosomes[0]; } return nullptr; } // double Population::GetAverageFitness() { return this->GetAverageFitness(this->chromosomes); } // double Population::GetAverageFitness(std::vector> _chromosomes) { // double fitness_sum; double fitness_average; // fitness_sum = 0; for ( std::shared_ptr chromosome : _chromosomes ) { fitness_sum += chromosome->GetFitness(); } // fitness_average = 0; if ( _chromosomes.size() > 0 ) { fitness_average = fitness_sum / _chromosomes.size(); } return fitness_average; } // void Population::SetCrossoverType(Enums::CrossoverType t) { // this->crossover_type = t; } // Enums::CrossoverType Population::GetCrossoverType() { // return this->crossover_type; } // void Population::SetCrossoverOrder(Enums::CrossoverOrder o) { // this->crossover_order = o; } // Enums::CrossoverOrder Population::GetCrossoverOrder() { // return this->crossover_order; } // void Population::SetCrossoverBounds(Enums::CrossoverBounds b) { // this->crossover_bounds = b; } // Enums::CrossoverBounds Population::GetCrossoverBounds() { // return this->crossover_bounds; } // void Population::SetCrossoverPoint(double p) { // this->crossover_point = p; } // double Population::GetCrossoverPoint() { // return this->crossover_point; } // void Population::SetCrossoverPointStandardDeviation(double std) { // this->crossover_point_std = std; } // double Population::GetCrossoverPointStandardDeviation() { // return this->crossover_point_std; } // void Population::SetMutationRate(double r) { // this->mutation_rate = r; } // double Population::GetMutationRate() { // 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) { // std::shared_ptr>> _chromosomes_copy; std::vector> threads; std::shared_ptr thread; int threads_count, i ; // Make a new vector containing all current chromosomes this->population_modification_mutex.lock(); _chromosomes_copy = std::shared_ptr>>( new std::vector>() ); for ( i=0; i<(int)this->chromosomes.size(); i++ ) { _chromosomes_copy->push_back( this->chromosomes[i] ); } this->population_modification_mutex.unlock(); // Spawn threads threads_count = this->GetThreadCountSuggestion(); for ( i=0; i( new std::thread(&Population::EvaluateFitness_Thread, this, _chromosomes_copy, evaluation_callback) ); threads.push_back(thread); } // Wait for threads to finish for ( i=0; ijoin(); } } // void Population::EvaluateError(std::function)> evaluation_callback) { // std::shared_ptr>> _chromosomes_copy; std::vector> threads; std::shared_ptr thread; int threads_count, i ; // Make a new vector containing all current chromosomes this->population_modification_mutex.lock(); _chromosomes_copy = std::shared_ptr>>( new std::vector>() ); for ( i=0; i<(int)this->chromosomes.size(); i++ ) { _chromosomes_copy->push_back( this->chromosomes[i] ); } this->population_modification_mutex.unlock(); // Spawn threads threads_count = this->GetThreadCountSuggestion(); for ( i=0; i( new std::thread(&Population::EvaluateError_Thread, this, _chromosomes_copy, evaluation_callback) ); threads.push_back(thread); } // Wait for threads to finish for ( i=0; ijoin(); } } // void Population::Evolve() { // std::shared_ptr > > population_new; // if ( this->chromosomes.size() == 0 ) { return; } // this->EnsureSortedPopulation(); // population_new = std::shared_ptr< std::vector< std::shared_ptr > >( new std::vector>() ); // Breed the new population this->BreedNewPopulation(population_new, (int)this->chromosomes.size()); // Replace old population with the new this->chromosomes = *population_new; this->evolution_number++; // this->PopulationChanged(); } // int Population::GetEvolutionNumber() { return this->evolution_number; } // void Population::PrintPopulation() { // this->EnsureSortedPopulation(); this->PrintPopulation(this->chromosomes); } // void Population::PrintPopulation(std::vector> _chromosomes) { // for ( std::shared_ptr chromosome : chromosomes ) { cout << chromosome->ToString() << endl; } cout << "Average Fitness --> " << this->GetAverageFitness(_chromosomes) << endl; } // void Population::InitRandomGenerator() { // this->random = std::shared_ptr( new Random() ); } // void Population::InitRouletteWheel() { // this->roulette_wheel = std::shared_ptr( new RouletteWheel() ); } // void Population::InitBreeder() { // if ( !this->random ) { throw std::runtime_error("Population::InitBreeder() - Should come after InitRandomGenerator()"); } // this->breeder = std::shared_ptr( new Breeder( this->random ) ); } // void Population::EnsureSortedPopulation() { // if ( !this->population_needs_sorting ) { return; } // Yay std::sort std::sort( this->chromosomes.begin(), this->chromosomes.end(), []( std::shared_ptr& left, std::shared_ptr& right ) -> bool { // if ( left->GetFitness() > right->GetFitness() ) { return true; } return false; } ); // this->population_needs_sorting = false; } // void Population::BreedNewPopulation(std::shared_ptr>> population_new, int size) { // std::vector> threads; std::shared_ptr thread; int thread_count, i ; // First, populate the roulette wheel this->roulette_wheel->SetChromosomes(this->chromosomes); // 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(); } } // void Population::BreedNewPopulation_Thread(std::shared_ptr>> population_new, int size) { // std::shared_ptr kiddo; // while ( (int)population_new->size() < size ) { // kiddo = this->BreedChild(); // Mutexed this->breed_mutex.lock(); if ( (int)population_new->size() < size ) { population_new->push_back(kiddo); } this->breed_mutex.unlock(); } } // 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, std::function)> evaluation_callback ) { // std::shared_ptr chromosome; double fitness; // while (true) { // Grab a free chromosome this->evaluate_fitness_mutex.lock(); chromosome = nullptr; if ( _chromosomes->size() ) { chromosome = _chromosomes->at(_chromosomes->size()-1); _chromosomes->pop_back(); } this->evaluate_fitness_mutex.unlock(); // Call the evaluation callback if ( chromosome != nullptr ) { fitness = evaluation_callback(chromosome); chromosome->SetFitness(fitness); } // We're done if there was nothing to grab else{ break; } } } // void Population::EvaluateError_Thread( std::shared_ptr>> _chromosomes, std::function)> evaluation_callback ) { // std::shared_ptr chromosome; double error; // while (true) { // Grab a free chromosome this->evaluate_fitness_mutex.lock(); chromosome = nullptr; if ( _chromosomes->size() ) { chromosome = _chromosomes->at(_chromosomes->size()-1); _chromosomes->pop_back(); } this->evaluate_fitness_mutex.unlock(); // Call the evaluation callback if ( chromosome != nullptr ) { error = evaluation_callback(chromosome); chromosome->SetError(error); } // We're done if there was nothing to grab else{ break; } } } // 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() { // std::shared_ptr mama, papa, kiddo ; // Pick two parents mama = this->roulette_wheel->Spin(); papa = this->roulette_wheel->Spin(); // kiddo = this->breeder->Breed( mama, papa, this->crossover_type, this->crossover_order, this->crossover_bounds, this->crossover_point, this->crossover_point_std, this->mutation_rate ); return kiddo; } // int Population::GetThreadCountSuggestion() { // int thread_count; // thread_count = std::thread::hardware_concurrency(); return thread_count; } };