Elitism and CopyChromosomes()

This commit is contained in:
Mike 2018-04-14 08:33:25 -07:00
parent 7db4140bdd
commit b2f164f464
3 changed files with 229 additions and 15 deletions

View File

@ -15,6 +15,15 @@ namespace BitEvolver
None,
Sexual
};
//
enum class ElitismType
{
//
None,
Rate,
Absolute
};
};
};

View File

@ -17,12 +17,16 @@
#include <algorithm>
#include <thread>
#include <functional>
#include <string>
#include <sstream>
//
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<double(std::shared_ptr<Chromosome>)> evaluation_callback)
{
@ -299,11 +350,6 @@ namespace BitEvolver
new std::vector<std::shared_ptr<Chromosome>>()
);
// 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<std::vector<std::shared_ptr<Chromosome>>> population_new, int size)
{
//
std::shared_ptr<RouletteWheel> wheel;
std::vector<std::shared_ptr<std::thread>> threads;
std::shared_ptr<std::thread> 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<thread_count; i++) {
thread = std::shared_ptr<std::thread>(
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<std::vector<std::shared_ptr<Chromosome>>> population_new)
{
//
std::unique_lock<std::recursive_mutex> lock(this->population_modification_mutex);
std::shared_ptr<std::vector<std::shared_ptr<Chromosome>>> elites;
std::vector<std::shared_ptr<std::thread>> threads;
std::shared_ptr<std::thread> thread;
int
elites_count,
i
;
// Determine how many elites to copy
elites_count = this->DetermineEliteCount();
elites = std::shared_ptr<std::vector<std::shared_ptr<Chromosome>>>(
new std::vector<std::shared_ptr<Chromosome>>()
);
// First, copy over just the pointers
for ( i=0; i<elites_count && i<(int)this->chromosomes.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<std::vector<std::shared_ptr<Chromosome>>> _chromosomes,
@ -522,6 +628,75 @@ namespace BitEvolver
}
}
//
void Population::CopyChromosomes(
std::shared_ptr<std::vector<std::shared_ptr<Chromosome>>> _chromosomes_source,
std::shared_ptr<std::vector<std::shared_ptr<Chromosome>>> _chromosomes_destination
)
{
//
std::vector<std::shared_ptr<std::thread>> threads;
std::shared_ptr<std::thread> thread;
int
threads_count,
i
;
// Spawn threads
threads_count = this->GetThreadCountSuggestion();
for ( i=0; i<threads_count; i++) {
//
thread = std::shared_ptr<std::thread>(
new std::thread(&Population::CopyChromosomes_Thread, this, _chromosomes_source, _chromosomes_destination)
);
threads.push_back(thread);
}
// Wait for threads to finish
for ( i=0; i<threads_count; i++ ) {
threads[i]->join();
}
}
//
void Population::CopyChromosomes_Thread(
std::shared_ptr<std::vector<std::shared_ptr<Chromosome>>> _chromosomes_source,
std::shared_ptr<std::vector<std::shared_ptr<Chromosome>>> _chromosomes_destination
)
{
//
std::shared_ptr<Chromosome>
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<Chromosome>(
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<Chromosome> Population::BreedChild()
{

View File

@ -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<double(std::shared_ptr<Chromosome>)> evaluation_callback);
@ -69,8 +76,11 @@ namespace BitEvolver
void PrintPopulation(std::vector<std::shared_ptr<class Chromosome>> _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<std::shared_ptr<class Chromosome>> 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<class RouletteWheel> 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<std::vector<std::shared_ptr<Chromosome>>> population_new, int size);
void BreedNewPopulation_Thread(std::shared_ptr<std::vector<std::shared_ptr<Chromosome>>> population_new, int size);
//
int DetermineEliteCount();
void SeedPopulationWithElites(std::shared_ptr<std::vector<std::shared_ptr<Chromosome>>> population_new);
//
void EvaluateFitness_Thread(
std::shared_ptr<std::vector<std::shared_ptr<Chromosome>>> _chromosomes,
@ -123,6 +143,16 @@ namespace BitEvolver
std::function<double(std::shared_ptr<Chromosome>)> evaluation_callback
);
//
void CopyChromosomes(
std::shared_ptr<std::vector<std::shared_ptr<Chromosome>>> _chromosomes_source,
std::shared_ptr<std::vector<std::shared_ptr<Chromosome>>> _chromosomes_destination
);
void CopyChromosomes_Thread(
std::shared_ptr<std::vector<std::shared_ptr<Chromosome>>> _chromosomes_source,
std::shared_ptr<std::vector<std::shared_ptr<Chromosome>>> _chromosomes_destination
);
//
std::shared_ptr<Chromosome> BreedChild();