794 řádky
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			794 řádky
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
 | |
| 
 | |
| //
 | |
| #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 <memory>
 | |
| #include <vector>
 | |
| #include <mutex>
 | |
| #include <iostream>
 | |
| #include <algorithm>
 | |
| #include <thread>
 | |
| #include <functional>
 | |
| #include <string>
 | |
| #include <sstream>
 | |
| 
 | |
| 
 | |
| //
 | |
| 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> chromosome;
 | |
| 		int i;
 | |
| 		
 | |
| 		//
 | |
| 		this->ClearPopulation();
 | |
| 		for ( i=0; i<this->population_size; i++ ) {
 | |
| 			
 | |
| 			//
 | |
| 			chromosome = std::shared_ptr<Chromosome>(
 | |
| 				new Chromosome( this->random, _bit_length )
 | |
| 			);
 | |
| 			this->chromosomes.push_back(chromosome);
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	//
 | |
| 	void Population::PopulationChanged()
 | |
| 	{
 | |
| 		//
 | |
| 		this->population_needs_sorting = true;
 | |
| 	}
 | |
| 	
 | |
| 	//
 | |
| 	std::vector<std::shared_ptr<Chromosome>> Population::GetChromosomes()
 | |
| 	{
 | |
| 		return this->chromosomes;
 | |
| 	}
 | |
| 	
 | |
| 	//
 | |
| 	void Population::GetChromosomes(std::shared_ptr<std::vector<std::shared_ptr<Chromosome>>> _chromosomes)
 | |
| 	{
 | |
| 		//
 | |
| 		_chromosomes->clear();
 | |
| 		for ( std::shared_ptr<Chromosome> chromosome : this->chromosomes) {
 | |
| 			_chromosomes->push_back(chromosome);
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	//
 | |
| 	std::shared_ptr<Chromosome> 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<std::shared_ptr<Chromosome>> _chromosomes)
 | |
| 	{
 | |
| 		//
 | |
| 		double fitness_sum;
 | |
| 		double fitness_average;
 | |
| 		
 | |
| 		//
 | |
| 		fitness_sum = 0;
 | |
| 		for ( std::shared_ptr<Chromosome> 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<double(std::shared_ptr<Chromosome>)> evaluation_callback)
 | |
| 	{
 | |
| 		//
 | |
| 		std::shared_ptr<std::vector<std::shared_ptr<Chromosome>>> _chromosomes_copy;
 | |
| 		std::vector<std::shared_ptr<std::thread>> threads;
 | |
| 		std::shared_ptr<std::thread> thread;
 | |
| 		int
 | |
| 			threads_count,
 | |
| 			i
 | |
| 			;
 | |
| 		
 | |
| 		//	Make a new vector containing all current chromosomes
 | |
| 		this->population_modification_mutex.lock();
 | |
| 		_chromosomes_copy = std::shared_ptr<std::vector<std::shared_ptr<Chromosome>>>(
 | |
| 			new std::vector<std::shared_ptr<Chromosome>>()
 | |
| 		);
 | |
| 		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<threads_count; i++) {
 | |
| 			
 | |
| 			//
 | |
| 			thread = std::shared_ptr<std::thread>(
 | |
| 				new std::thread(&Population::EvaluateFitness_Thread, this, _chromosomes_copy, evaluation_callback)
 | |
| 			);
 | |
| 			threads.push_back(thread);
 | |
| 		}
 | |
| 		
 | |
| 		//	Wait for threads to finish
 | |
| 		for ( i=0; i<threads_count; i++ ) {
 | |
| 			threads[i]->join();
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	//
 | |
| 	void Population::EvaluateError(std::function<double(std::shared_ptr<Chromosome>)> evaluation_callback)
 | |
| 	{
 | |
| 		//
 | |
| 		std::shared_ptr<std::vector<std::shared_ptr<Chromosome>>> _chromosomes_copy;
 | |
| 		std::vector<std::shared_ptr<std::thread>> threads;
 | |
| 		std::shared_ptr<std::thread> thread;
 | |
| 		int
 | |
| 			threads_count,
 | |
| 			i
 | |
| 			;
 | |
| 		
 | |
| 		//	Make a new vector containing all current chromosomes
 | |
| 		this->population_modification_mutex.lock();
 | |
| 		_chromosomes_copy = std::shared_ptr<std::vector<std::shared_ptr<Chromosome>>>(
 | |
| 			new std::vector<std::shared_ptr<Chromosome>>()
 | |
| 		);
 | |
| 		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<threads_count; i++) {
 | |
| 			
 | |
| 			//
 | |
| 			thread = std::shared_ptr<std::thread>(
 | |
| 				new std::thread(&Population::EvaluateError_Thread, this, _chromosomes_copy, evaluation_callback)
 | |
| 			);
 | |
| 			threads.push_back(thread);
 | |
| 		}
 | |
| 		
 | |
| 		//	Wait for threads to finish
 | |
| 		for ( i=0; i<threads_count; i++ ) {
 | |
| 			threads[i]->join();
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	//
 | |
| 	void Population::Evolve()
 | |
| 	{
 | |
| 		//
 | |
| 		std::shared_ptr<std::vector< std::shared_ptr<Chromosome> > > population_new;
 | |
| 		
 | |
| 		//
 | |
| 		if ( this->chromosomes.size() == 0 ) {
 | |
| 			return;
 | |
| 		}
 | |
| 		
 | |
| 		//
 | |
| 		this->EnsureSortedPopulation();
 | |
| 		
 | |
| 		//
 | |
| 		population_new = std::shared_ptr<
 | |
| 			std::vector<
 | |
| 				std::shared_ptr<Chromosome>
 | |
| 			>
 | |
| 		>(
 | |
| 			new std::vector<std::shared_ptr<Chromosome>>()
 | |
| 		);
 | |
| 		
 | |
| 		//	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<std::shared_ptr<Chromosome>> _chromosomes)
 | |
| 	{
 | |
| 		//
 | |
| 		for ( std::shared_ptr<Chromosome> chromosome : chromosomes ) {
 | |
| 			cout << chromosome->ToString() << endl;
 | |
| 		}
 | |
| 		cout << "Average Fitness --> " << this->GetAverageFitness(_chromosomes) << endl;
 | |
| 	}
 | |
| 	
 | |
| 	//
 | |
| 	void Population::InitRandomGenerator()
 | |
| 	{
 | |
| 		//
 | |
| 		this->random = std::shared_ptr<Random>(
 | |
| 			new Random()
 | |
| 		);
 | |
| 	}
 | |
| 	
 | |
| 	//
 | |
| 	void Population::InitRouletteWheel()
 | |
| 	{
 | |
| 		//
 | |
| 		this->roulette_wheel = std::shared_ptr<RouletteWheel>(
 | |
| 			new RouletteWheel()
 | |
| 		);
 | |
| 	}
 | |
| 	
 | |
| 	//
 | |
| 	void Population::InitBreeder()
 | |
| 	{
 | |
| 		//
 | |
| 		if ( !this->random ) {
 | |
| 			throw std::runtime_error("Population::InitBreeder() - Should come after InitRandomGenerator()");
 | |
| 		}
 | |
| 		
 | |
| 		//
 | |
| 		this->breeder = std::shared_ptr<Breeder>(
 | |
| 			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<Chromosome>& left, std::shared_ptr<Chromosome>& right ) -> bool
 | |
| 			{
 | |
| 				//
 | |
| 				if ( left->GetFitness() > right->GetFitness() ) {
 | |
| 					return true;
 | |
| 				}
 | |
| 				
 | |
| 				return false;
 | |
| 			}
 | |
| 		);
 | |
| 		
 | |
| 		//
 | |
| 		this->population_needs_sorting = false;
 | |
| 	}
 | |
| 	
 | |
| 	//
 | |
| 	void Population::BreedNewPopulation(std::shared_ptr<std::vector<std::shared_ptr<Chromosome>>> population_new, int size)
 | |
| 	{
 | |
| 		//
 | |
| 		std::vector<std::shared_ptr<std::thread>> threads;
 | |
| 		std::shared_ptr<std::thread> 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<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();
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	//
 | |
| 	void Population::BreedNewPopulation_Thread(std::shared_ptr<std::vector<std::shared_ptr<Chromosome>>> population_new, int size)
 | |
| 	{
 | |
| 		//
 | |
| 		std::shared_ptr<Chromosome> 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<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,
 | |
| 		std::function<double(std::shared_ptr<Chromosome>)> evaluation_callback
 | |
| 	)
 | |
| 	{
 | |
| 		//
 | |
| 		std::shared_ptr<Chromosome> 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<std::vector<std::shared_ptr<Chromosome>>> _chromosomes,
 | |
| 		std::function<double(std::shared_ptr<Chromosome>)> evaluation_callback
 | |
| 	)
 | |
| 	{
 | |
| 		//
 | |
| 		std::shared_ptr<Chromosome> 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<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()
 | |
| 	{
 | |
| 		//
 | |
| 		std::shared_ptr<Chromosome>
 | |
| 			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;
 | |
| 	}
 | |
| };
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 |