Merge branch 'dev'
This commit is contained in:
		
							
								
								
									
										210
									
								
								Breeder.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										210
									
								
								Breeder.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,210 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#include "BitEvolver/Random.h"
 | 
				
			||||||
 | 
					#include "BitEvolver/Chromosome.h"
 | 
				
			||||||
 | 
					#include "BitEvolver/Breeder.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					namespace BitEvolver
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						using std::cout;
 | 
				
			||||||
 | 
						using std::endl;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						Breeder::Breeder(std::shared_ptr<Random> _random)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->random = _random;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						std::shared_ptr<Chromosome> Breeder::Breed(
 | 
				
			||||||
 | 
							std::shared_ptr<Chromosome> mama,
 | 
				
			||||||
 | 
							std::shared_ptr<Chromosome> papa,
 | 
				
			||||||
 | 
							Enums::CrossoverType crossover_type,
 | 
				
			||||||
 | 
							Enums::CrossoverOrder crossover_order,
 | 
				
			||||||
 | 
							Enums::CrossoverBounds crossover_bounds,
 | 
				
			||||||
 | 
							double crossover_point,
 | 
				
			||||||
 | 
							double crossover_point_std,
 | 
				
			||||||
 | 
							double mutation_rate
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							std::shared_ptr<Chromosome>
 | 
				
			||||||
 | 
								parent_primary,
 | 
				
			||||||
 | 
								parent_secondary,
 | 
				
			||||||
 | 
								kiddo
 | 
				
			||||||
 | 
								;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//	Choose primary / secondary parents
 | 
				
			||||||
 | 
							switch( crossover_order )
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								case Enums::CrossoverOrder::MamaPapa:
 | 
				
			||||||
 | 
									parent_primary = mama;
 | 
				
			||||||
 | 
									parent_secondary = papa;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								case Enums::CrossoverOrder::ByFitness:
 | 
				
			||||||
 | 
									if ( mama->GetFitness() > papa->GetFitness() ) {
 | 
				
			||||||
 | 
										parent_primary = mama;
 | 
				
			||||||
 | 
										parent_secondary = papa;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									else{
 | 
				
			||||||
 | 
										parent_primary = papa;
 | 
				
			||||||
 | 
										parent_secondary = mama;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//	Directly copy the primary parent first
 | 
				
			||||||
 | 
							kiddo = std::shared_ptr<Chromosome>(new Chromosome(this->random, parent_primary->GetBitCount()));
 | 
				
			||||||
 | 
							*kiddo = *parent_primary;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//	Apply crossover with the secondary parent
 | 
				
			||||||
 | 
							this->ApplyCrossover(
 | 
				
			||||||
 | 
								kiddo, parent_secondary,
 | 
				
			||||||
 | 
								crossover_type, crossover_bounds, crossover_point, crossover_point_std
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//	Apply mutation
 | 
				
			||||||
 | 
							this->Mutate(kiddo, mutation_rate);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//	Reset kiddo's fitness
 | 
				
			||||||
 | 
							kiddo->ResetFitness();
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							return kiddo;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void Breeder::Mutate(std::shared_ptr<Chromosome> chromosome, double mutation_rate)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							int
 | 
				
			||||||
 | 
								i,
 | 
				
			||||||
 | 
								size
 | 
				
			||||||
 | 
								;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							size = chromosome->GetBitCount();
 | 
				
			||||||
 | 
							for ( i=0; i<size; i++ ) {
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								if ( this->random->RollBool(mutation_rate) ) {
 | 
				
			||||||
 | 
									chromosome->FlipBit(i);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							chromosome->ResetFitness();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						int Breeder::PickRandomCrossoverPoint(
 | 
				
			||||||
 | 
							std::shared_ptr<Chromosome> chromosome,
 | 
				
			||||||
 | 
							Enums::CrossoverBounds crossover_bounds,
 | 
				
			||||||
 | 
							double crossover_point,
 | 
				
			||||||
 | 
							double crossover_point_std
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							int crossover_point_index;
 | 
				
			||||||
 | 
							int bit_count;
 | 
				
			||||||
 | 
							double random_double;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							bit_count = chromosome->GetBitCount();
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
								Choose a double between [0.0,1.0] for the crossover point.
 | 
				
			||||||
 | 
								Use normal distribution, with the mean and std from the parameters.
 | 
				
			||||||
 | 
								That way, there is still randomness to the crossover point,
 | 
				
			||||||
 | 
									but it still generally sticks near the chosen point.
 | 
				
			||||||
 | 
							*/
 | 
				
			||||||
 | 
							random_double = this->random->GetNormal(crossover_point, crossover_point_std);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//	Apply to the actual int length
 | 
				
			||||||
 | 
							crossover_point_index = floor(random_double * bit_count);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//	Loop around to keep in bounds?
 | 
				
			||||||
 | 
							if ( crossover_bounds == Enums::CrossoverBounds::Wrap ) {
 | 
				
			||||||
 | 
								while ( crossover_point_index < 0 )
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									crossover_point_index += bit_count;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								while ( crossover_point_index >= bit_count)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									crossover_point_index -= bit_count;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else if ( crossover_bounds == Enums::CrossoverBounds::Clip ) {
 | 
				
			||||||
 | 
								if ( crossover_point_index < 0 ) {
 | 
				
			||||||
 | 
									crossover_point_index = 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else if ( crossover_point_index >= bit_count ) {
 | 
				
			||||||
 | 
									crossover_point_index = bit_count-1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else{
 | 
				
			||||||
 | 
								throw std::runtime_error("Breeder::PickRandomCrossoverPoint() - Invalid crossover_bounds");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							return crossover_point_index;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void Breeder::ApplyCrossover(
 | 
				
			||||||
 | 
							std::shared_ptr<Chromosome> kiddo,
 | 
				
			||||||
 | 
							std::shared_ptr<Chromosome> parent,
 | 
				
			||||||
 | 
							Enums::CrossoverType crossover_type,
 | 
				
			||||||
 | 
							Enums::CrossoverBounds crossover_bounds,
 | 
				
			||||||
 | 
							double crossover_point,
 | 
				
			||||||
 | 
							double crossover_point_std
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							int
 | 
				
			||||||
 | 
								bits_count,
 | 
				
			||||||
 | 
								crossover_point_index,
 | 
				
			||||||
 | 
								i
 | 
				
			||||||
 | 
								;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//	Only proceed if using sexual crossover
 | 
				
			||||||
 | 
							if (crossover_type != Enums::CrossoverType::Sexual) {
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//	For now, don't crossover unless the bit lengths are identical
 | 
				
			||||||
 | 
							bits_count = kiddo->GetBitCount();
 | 
				
			||||||
 | 
							if ( parent->GetBitCount() != bits_count ) {
 | 
				
			||||||
 | 
								throw std::runtime_error("Breeder::ApplyCrossover() - Parent incompatible with Kiddo (bit lengths don't match)");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//	Pick random crossover point
 | 
				
			||||||
 | 
							crossover_point_index = this->PickRandomCrossoverPoint(kiddo, crossover_bounds, crossover_point, crossover_point_std);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//	Begin copying the parent at the crossover point and beyond
 | 
				
			||||||
 | 
							//	(not before)
 | 
				
			||||||
 | 
							for ( i=crossover_point_index; i<bits_count; i++) {
 | 
				
			||||||
 | 
								kiddo->SetBit( i, parent->GetBit(i) );
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							kiddo->ResetFitness();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										57
									
								
								Breeder.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								Breeder.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					namespace BitEvolver
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						class Breeder
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							public:
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								Breeder(std::shared_ptr<class Random> _random);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								std::shared_ptr<class Chromosome> Breed(
 | 
				
			||||||
 | 
									std::shared_ptr<class Chromosome> mama,
 | 
				
			||||||
 | 
									std::shared_ptr<class Chromosome> papa,
 | 
				
			||||||
 | 
									Enums::CrossoverType crossover_type,
 | 
				
			||||||
 | 
									Enums::CrossoverOrder crossover_order,
 | 
				
			||||||
 | 
									Enums::CrossoverBounds crossover_bounds,
 | 
				
			||||||
 | 
									double crossover_point,
 | 
				
			||||||
 | 
									double crossover_point_std,
 | 
				
			||||||
 | 
									double mutation_rate
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								void Mutate(std::shared_ptr<class Chromosome> chromosome, double mutation_rate);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							private:
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								std::shared_ptr<class Random> random;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								int PickRandomCrossoverPoint(
 | 
				
			||||||
 | 
									std::shared_ptr<class Chromosome> chromosome,
 | 
				
			||||||
 | 
									Enums::CrossoverBounds crossover_bounds,
 | 
				
			||||||
 | 
									double crossover_point,
 | 
				
			||||||
 | 
									double crossover_point_std
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
								void ApplyCrossover(
 | 
				
			||||||
 | 
									std::shared_ptr<class Chromosome> kiddo,
 | 
				
			||||||
 | 
									std::shared_ptr<class Chromosome> parent,
 | 
				
			||||||
 | 
									Enums::CrossoverType crossover_type,
 | 
				
			||||||
 | 
									Enums::CrossoverBounds crossover_bounds,
 | 
				
			||||||
 | 
									double crossover_point,
 | 
				
			||||||
 | 
									double crossover_point_std
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										228
									
								
								Chromosome.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								Chromosome.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,228 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#include "BitEvolver/Chromosome.h"
 | 
				
			||||||
 | 
					#include "BitEvolver/Random.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					#include <mutex>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					namespace BitEvolver
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						using std::string;
 | 
				
			||||||
 | 
						using std::to_string;
 | 
				
			||||||
 | 
						using std::stringstream;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						Chromosome::Chromosome(std::shared_ptr<Random> _random, int _bits)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->random = _random;
 | 
				
			||||||
 | 
							this->SetBitCount(_bits);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->Reset();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void Chromosome::Reset()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->Randomize();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void Chromosome::Randomize()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							std::unique_lock<std::recursive_mutex> lock(this->modification_mutex);
 | 
				
			||||||
 | 
							int i;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->bits.clear();
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							for ( i=0; i<this->bits_count_desired; i++ ) {
 | 
				
			||||||
 | 
								this->bits.push_back(this->random->GetInt(0, 1));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void Chromosome::SetBitCount(int count)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							std::unique_lock<std::recursive_mutex> lock(this->modification_mutex);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->bits_count_desired = count;
 | 
				
			||||||
 | 
							this->Randomize();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						int Chromosome::GetBitCount()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return (int)this->bits.size();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void Chromosome::FlipBit(int index)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							std::unique_lock<std::recursive_mutex> lock(this->modification_mutex);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							if ( index >= (int)this->bits.size() ) {
 | 
				
			||||||
 | 
								throw std::runtime_error("Chromosome::FlipBit() - Tried to flip out of range bit index: " + to_string(index));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							if ( this->bits[index] ) {
 | 
				
			||||||
 | 
								this->bits[index] = false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else{
 | 
				
			||||||
 | 
								this->bits[index] = true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						bool Chromosome::GetBit(int index)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							std::unique_lock<std::recursive_mutex> lock(this->modification_mutex);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							if ( index >= (int)this->bits.size() ) {
 | 
				
			||||||
 | 
								throw std::runtime_error("Chromosome::GetBit() - Tried to access out of bounds bit");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							return this->bits[index];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void Chromosome::SetBit(int index, bool b)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							std::unique_lock<std::recursive_mutex> lock(this->modification_mutex);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							if ( index >= (int)this->bits.size() ) {
 | 
				
			||||||
 | 
								throw std::runtime_error("Chromosome::GetBit() - Tried to access out of bounds bit");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->bits[index] = b;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void Chromosome::ResetFitness()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->SetFitness(0.0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void Chromosome::SetFitness(double d)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->fitness = d;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void Chromosome::AdjustFitness(double d)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->fitness += d;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						double Chromosome::GetFitness()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							return this->fitness;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void Chromosome::ResetError()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->ResetFitness();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void Chromosome::SetError(double e)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->SetFitness(-e);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void Chromosome::AdjustError(double e)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->AdjustFitness(-e);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						double Chromosome::GetError()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							return -this->GetFitness();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						string Chromosome::ToString()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							std::unique_lock<std::recursive_mutex> lock(this->modification_mutex);
 | 
				
			||||||
 | 
							stringstream s;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							for ( bool b : this->bits ) {
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								if ( b ) {
 | 
				
			||||||
 | 
									s << "1";
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else{
 | 
				
			||||||
 | 
									s << "0";
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							return s.str();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						const Chromosome& Chromosome::operator=(const Chromosome& other)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							std::unique_lock<std::recursive_mutex> lock1(this->modification_mutex);
 | 
				
			||||||
 | 
							int i;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->random = other.random;
 | 
				
			||||||
 | 
							this->bits = other.bits;
 | 
				
			||||||
 | 
							this->bits_count_desired = other.bits_count_desired;
 | 
				
			||||||
 | 
							this->fitness = other.fitness;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//	Copy the bits!
 | 
				
			||||||
 | 
							this->bits.clear();
 | 
				
			||||||
 | 
							for ( i=0; i<(int)other.bits.size(); i++ ) {
 | 
				
			||||||
 | 
								this->bits.push_back(other.bits[i]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							return *this;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										83
									
								
								Chromosome.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								Chromosome.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,83 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#include "BitEvolver/Includes.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					#include <mutex>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					namespace BitEvolver
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						class Chromosome
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							public:
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								Chromosome(std::shared_ptr<class Random> _random, int _bits);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								void Reset();
 | 
				
			||||||
 | 
								void Randomize();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								void SetBitCount(int count);
 | 
				
			||||||
 | 
								int GetBitCount();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								void FlipBit(int index);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								bool GetBit(int index);
 | 
				
			||||||
 | 
								void SetBit(int index, bool b);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								void ResetFitness();
 | 
				
			||||||
 | 
								void SetFitness(double d);
 | 
				
			||||||
 | 
								void AdjustFitness(double d);
 | 
				
			||||||
 | 
								double GetFitness();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								/**
 | 
				
			||||||
 | 
									Error is just inverted fitness
 | 
				
			||||||
 | 
								*/
 | 
				
			||||||
 | 
								void ResetError();
 | 
				
			||||||
 | 
								void SetError(double e);
 | 
				
			||||||
 | 
								void AdjustError(double e);
 | 
				
			||||||
 | 
								double GetError();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								std::string ToString();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								const Chromosome& operator=(const Chromosome& other);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							private:
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//	Random number generator
 | 
				
			||||||
 | 
								std::shared_ptr<class Random> random;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								std::vector<bool> bits;
 | 
				
			||||||
 | 
								int bits_count_desired;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//	Fitness
 | 
				
			||||||
 | 
								double fitness;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//	Mutexes
 | 
				
			||||||
 | 
								std::recursive_mutex modification_mutex;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								Defines.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								Defines.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					#ifndef BITEVOLVER_DEFINES_H
 | 
				
			||||||
 | 
					#define BITEVOLVER_DEFINES_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//	Nada for now
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										47
									
								
								Enums.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								Enums.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					#ifndef BITEVOLVER_ENUMS_H
 | 
				
			||||||
 | 
					#define BITEVOLVER_ENUMS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					namespace BitEvolver
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						namespace Enums
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							enum class CrossoverType
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								None,
 | 
				
			||||||
 | 
								Sexual
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							enum class CrossoverOrder
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								MamaPapa,
 | 
				
			||||||
 | 
								ByFitness
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							enum class CrossoverBounds
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								Clip,
 | 
				
			||||||
 | 
								Wrap
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							enum class ElitismType
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								None,
 | 
				
			||||||
 | 
								Rate,
 | 
				
			||||||
 | 
								Absolute
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										14
									
								
								ForwardDeclarations.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								ForwardDeclarations.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					#ifndef BITEVOLVER_FORWARD_DECLARATIONS_H
 | 
				
			||||||
 | 
					#define BITEVOLVER_FORWARD_DECLARATIONS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					namespace BitEvolver
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						class Population;
 | 
				
			||||||
 | 
						class Breeder;
 | 
				
			||||||
 | 
						class Chromosome;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										13
									
								
								Includes.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								Includes.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					#ifndef BITEVOLVER_INCLUDES_H
 | 
				
			||||||
 | 
					#define BITEVOLVER_INCLUDES_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#include "BitEvolver/Defines.h"
 | 
				
			||||||
 | 
					#include "BitEvolver/Enums.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										136
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										136
									
								
								Makefile
									
									
									
									
									
								
							@@ -1 +1,137 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					#	Custom functions
 | 
				
			||||||
 | 
					define say
 | 
				
			||||||
 | 
						$(info [BitEvolver] $1)
 | 
				
			||||||
 | 
					endef
 | 
				
			||||||
 | 
					define error
 | 
				
			||||||
 | 
						$(error [BitEvolver] $1)
 | 
				
			||||||
 | 
					endef
 | 
				
			||||||
 | 
					define die
 | 
				
			||||||
 | 
						$(call error,$1)
 | 
				
			||||||
 | 
						$(exit 1)
 | 
				
			||||||
 | 
					endef
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#	Demand BUILD_DIR and BIN_DIR
 | 
				
			||||||
 | 
					ifeq ($(BUILD_DIR),)
 | 
				
			||||||
 | 
					$(call die,Please provide BUILD_DIR)
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					ifeq ($(BIN_DIR),)
 | 
				
			||||||
 | 
					$(call die,Please provide BIN_DIR)
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 | 
					CC=g++
 | 
				
			||||||
 | 
					CFLAGS= -c -std=c++11 -Wall -I..
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					OBJECT_PREFIX=BitEvolver_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					default:	default-say
 | 
				
			||||||
 | 
					default:	release
 | 
				
			||||||
 | 
					default:
 | 
				
			||||||
 | 
						$(call say,Default target finished)
 | 
				
			||||||
 | 
					default-say:
 | 
				
			||||||
 | 
						$(call say,Using default target: release)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					release:	release-say
 | 
				
			||||||
 | 
					release:	CFLAGS+= -O2
 | 
				
			||||||
 | 
					release:	build-objects
 | 
				
			||||||
 | 
					release:
 | 
				
			||||||
 | 
						$(call say,Done building RELEASE)
 | 
				
			||||||
 | 
					release-say:
 | 
				
			||||||
 | 
						$(call say,Building RELEASE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					debug:		debug-say
 | 
				
			||||||
 | 
					debug:		CFLAGS+= -g -g3
 | 
				
			||||||
 | 
					debug:		build-objects
 | 
				
			||||||
 | 
					debug:
 | 
				
			||||||
 | 
						$(call say,Done building DEBUG)
 | 
				
			||||||
 | 
					debug-say:
 | 
				
			||||||
 | 
						$(call say,Building DEBUG)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					build-objects:	\
 | 
				
			||||||
 | 
									$(BUILD_DIR)/$(OBJECT_PREFIX)Random.o \
 | 
				
			||||||
 | 
									$(BUILD_DIR)/$(OBJECT_PREFIX)Population.o \
 | 
				
			||||||
 | 
									$(BUILD_DIR)/$(OBJECT_PREFIX)Breeder.o \
 | 
				
			||||||
 | 
									$(BUILD_DIR)/$(OBJECT_PREFIX)RouletteWheel.o \
 | 
				
			||||||
 | 
									$(BUILD_DIR)/$(OBJECT_PREFIX)Chromosome.o
 | 
				
			||||||
 | 
						$(call say,Done building objects)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#	Population.o
 | 
				
			||||||
 | 
					$(BUILD_DIR)/$(OBJECT_PREFIX)Population.o:	\
 | 
				
			||||||
 | 
																Population.h \
 | 
				
			||||||
 | 
																Population.cpp \
 | 
				
			||||||
 | 
																Defines.h Enums.h Includes.h \
 | 
				
			||||||
 | 
																Random.h \
 | 
				
			||||||
 | 
																Chromosome.h
 | 
				
			||||||
 | 
						$(CC) -o $@ \
 | 
				
			||||||
 | 
							Population.cpp \
 | 
				
			||||||
 | 
							$(CFLAGS)
 | 
				
			||||||
 | 
						$(call say,Built $@)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#	Breeder.o
 | 
				
			||||||
 | 
					$(BUILD_DIR)/$(OBJECT_PREFIX)Breeder.o:	\
 | 
				
			||||||
 | 
																Breeder.h \
 | 
				
			||||||
 | 
																Breeder.cpp \
 | 
				
			||||||
 | 
																Defines.h Enums.h Includes.h \
 | 
				
			||||||
 | 
																Random.h \
 | 
				
			||||||
 | 
																Chromosome.h
 | 
				
			||||||
 | 
						$(CC) -o $@ \
 | 
				
			||||||
 | 
							Breeder.cpp \
 | 
				
			||||||
 | 
							$(CFLAGS)
 | 
				
			||||||
 | 
						$(call say,Built $@)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#	RouletteWheel.o
 | 
				
			||||||
 | 
					$(BUILD_DIR)/$(OBJECT_PREFIX)RouletteWheel.o:	\
 | 
				
			||||||
 | 
																RouletteWheel.h \
 | 
				
			||||||
 | 
																RouletteWheel.cpp \
 | 
				
			||||||
 | 
																Defines.h Enums.h Includes.h \
 | 
				
			||||||
 | 
																Random.h
 | 
				
			||||||
 | 
						$(CC) -o $@ \
 | 
				
			||||||
 | 
							RouletteWheel.cpp \
 | 
				
			||||||
 | 
							$(CFLAGS)
 | 
				
			||||||
 | 
						$(call say,Built $@)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#	Chromosome.o
 | 
				
			||||||
 | 
					$(BUILD_DIR)/$(OBJECT_PREFIX)Chromosome.o:	\
 | 
				
			||||||
 | 
																Chromosome.h \
 | 
				
			||||||
 | 
																Chromosome.cpp \
 | 
				
			||||||
 | 
																Defines.h Enums.h Includes.h \
 | 
				
			||||||
 | 
																Random.h
 | 
				
			||||||
 | 
						$(CC) -o $@ \
 | 
				
			||||||
 | 
							Chromosome.cpp \
 | 
				
			||||||
 | 
							$(CFLAGS)
 | 
				
			||||||
 | 
						$(call say,Built $@)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#	Random.o
 | 
				
			||||||
 | 
					$(BUILD_DIR)/$(OBJECT_PREFIX)Random.o:	\
 | 
				
			||||||
 | 
																Random.h \
 | 
				
			||||||
 | 
																Random.cpp \
 | 
				
			||||||
 | 
																Defines.h Enums.h Includes.h
 | 
				
			||||||
 | 
						$(CC) -o $@ \
 | 
				
			||||||
 | 
							Random.cpp \
 | 
				
			||||||
 | 
							$(CFLAGS)
 | 
				
			||||||
 | 
						$(call say,Built $@)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										793
									
								
								Population.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										793
									
								
								Population.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,793 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#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;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										178
									
								
								Population.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								Population.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,178 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#include "BitEvolver/Includes.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					#include <mutex>
 | 
				
			||||||
 | 
					#include <functional>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					namespace BitEvolver
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						class Population
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							public:
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								Population();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								void Reset();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								void ClearPopulation();
 | 
				
			||||||
 | 
								void InitRandomPopulation(int _population_size, int _bit_length);
 | 
				
			||||||
 | 
								void RandomizePopulation(int _bit_length);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								void PopulationChanged();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								std::vector<std::shared_ptr<class Chromosome>> GetChromosomes();
 | 
				
			||||||
 | 
								void GetChromosomes(std::shared_ptr<std::vector<std::shared_ptr<class Chromosome>>> _chromosomes);
 | 
				
			||||||
 | 
								std::shared_ptr<class Chromosome> GetChampion();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								double GetAverageFitness();
 | 
				
			||||||
 | 
								double GetAverageFitness(std::vector<std::shared_ptr<class Chromosome>> _chromosomes);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								void SetCrossoverType(Enums::CrossoverType t);
 | 
				
			||||||
 | 
								Enums::CrossoverType GetCrossoverType();
 | 
				
			||||||
 | 
								void SetCrossoverOrder(Enums::CrossoverOrder o);
 | 
				
			||||||
 | 
								Enums::CrossoverOrder GetCrossoverOrder();
 | 
				
			||||||
 | 
								void SetCrossoverBounds(Enums::CrossoverBounds b);
 | 
				
			||||||
 | 
								Enums::CrossoverBounds GetCrossoverBounds();
 | 
				
			||||||
 | 
								void SetCrossoverPoint(double p);
 | 
				
			||||||
 | 
								double GetCrossoverPoint();
 | 
				
			||||||
 | 
								void SetCrossoverPointStandardDeviation(double std);
 | 
				
			||||||
 | 
								double GetCrossoverPointStandardDeviation();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								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);
 | 
				
			||||||
 | 
								void EvaluateError(std::function<double(std::shared_ptr<Chromosome>)> evaluation_callback);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								void Evolve();
 | 
				
			||||||
 | 
								int GetEvolutionNumber();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								void PrintPopulation();
 | 
				
			||||||
 | 
								void PrintPopulation(std::vector<std::shared_ptr<class Chromosome>> _chromosomes);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//	Constants
 | 
				
			||||||
 | 
								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 Enums::CrossoverOrder	DEFAULT_CROSSOVER_ORDER = 		Enums::CrossoverOrder::MamaPapa;
 | 
				
			||||||
 | 
								const static Enums::CrossoverBounds	DEFAULT_CROSSOVER_BOUNDS =		Enums::CrossoverBounds::Wrap;
 | 
				
			||||||
 | 
								constexpr static double				DEFAULT_CROSSOVER_POINT =		0.7;
 | 
				
			||||||
 | 
								constexpr static double				DEFAULT_CROSSOVER_POINT_STD =	0.25;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							private:
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								std::shared_ptr<class Random> random;
 | 
				
			||||||
 | 
								std::shared_ptr<class Breeder> breeder;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								std::vector<std::shared_ptr<class Chromosome>> chromosomes;
 | 
				
			||||||
 | 
								int population_size;
 | 
				
			||||||
 | 
								bool population_needs_sorting;
 | 
				
			||||||
 | 
								int evolution_number;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								Enums::CrossoverType crossover_type;
 | 
				
			||||||
 | 
								Enums::CrossoverOrder crossover_order;
 | 
				
			||||||
 | 
								Enums::CrossoverBounds crossover_bounds;
 | 
				
			||||||
 | 
								double crossover_point;
 | 
				
			||||||
 | 
								double crossover_point_std;
 | 
				
			||||||
 | 
								double mutation_rate;
 | 
				
			||||||
 | 
								Enums::ElitismType elitism_type;
 | 
				
			||||||
 | 
								double elitism_rate;
 | 
				
			||||||
 | 
								int elitism_count;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								std::shared_ptr<class RouletteWheel> roulette_wheel;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								std::recursive_mutex
 | 
				
			||||||
 | 
									population_modification_mutex,
 | 
				
			||||||
 | 
									breed_mutex,
 | 
				
			||||||
 | 
									evaluate_fitness_mutex,
 | 
				
			||||||
 | 
									copy_chromosomes_mutex
 | 
				
			||||||
 | 
									;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								void InitRandomGenerator();
 | 
				
			||||||
 | 
								void InitRouletteWheel();
 | 
				
			||||||
 | 
								void InitBreeder();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								void EnsureSortedPopulation();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								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,
 | 
				
			||||||
 | 
									std::function<double(std::shared_ptr<Chromosome>)> evaluation_callback
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
								void EvaluateError_Thread(
 | 
				
			||||||
 | 
									std::shared_ptr<std::vector<std::shared_ptr<Chromosome>>> _chromosomes,
 | 
				
			||||||
 | 
									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();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								int GetThreadCountSuggestion();
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										86
									
								
								Random.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								Random.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#include "BitEvolver/Random.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#include <random>
 | 
				
			||||||
 | 
					#include <chrono>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					namespace BitEvolver
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						Random::Random()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->InitializeGenerators();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						int Random::GetInt(int min, int max)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							std::uniform_int_distribution<int> distribution(min, max);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							int the_int = distribution(this->generator_mersenne_twister);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							return the_int;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						double Random::GetDouble(double min, double max)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							std::uniform_real_distribution<double> distribution(min, max);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							double the_double = distribution(this->generator_mersenne_twister);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							return the_double;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						double Random::GetNormal(double mean, double standard_deviation)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							std::normal_distribution<double> distribution(mean, standard_deviation);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							double d = distribution(this->generator_mersenne_twister);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							return d;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						bool Random::RollBool(double chance)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							double d = this->GetDouble(0, 1);
 | 
				
			||||||
 | 
							if ( d <= chance ) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void Random::InitializeGenerators()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//	Mostly taken from
 | 
				
			||||||
 | 
							//	http://www.cplusplus.com/reference/random/mersenne_twister_engine/seed/
 | 
				
			||||||
 | 
							typedef std::chrono::high_resolution_clock myclock;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							myclock::time_point beginning = myclock::now();
 | 
				
			||||||
 | 
							myclock::duration d = myclock::now() - beginning;
 | 
				
			||||||
 | 
							unsigned seed = d.count();
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//	Seed our internal generator
 | 
				
			||||||
 | 
							this->generator_mersenne_twister.seed(seed);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										41
									
								
								Random.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								Random.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#include <random>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					namespace BitEvolver
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						class Random
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							public:
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								Random();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								int GetInt(int min, int max);
 | 
				
			||||||
 | 
								double GetDouble(double min, double max);
 | 
				
			||||||
 | 
								double GetNormal(double mean, double standard_deviation);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								bool RollBool(double chance);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							private:
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								std::mt19937_64 generator_mersenne_twister;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								void InitializeGenerators();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
							
								
								
									
										271
									
								
								RouletteWheel.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										271
									
								
								RouletteWheel.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,271 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#include "BitEvolver/Random.h"
 | 
				
			||||||
 | 
					#include "BitEvolver/RouletteWheel.h"
 | 
				
			||||||
 | 
					#include "BitEvolver/Chromosome.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					#include <mutex>
 | 
				
			||||||
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					namespace BitEvolver
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						using std::cout;
 | 
				
			||||||
 | 
						using std::endl;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						RouletteWheel::RouletteWheel()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->Instantiate();
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->Reset();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void RouletteWheel::Reset()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->ClearChromosomes();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void RouletteWheel::ClearChromosomes()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							std::unique_lock<std::recursive_mutex> lock(this->chromosomes_mutex);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->chromosomes.clear();
 | 
				
			||||||
 | 
							this->ChromosomesChanged();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void RouletteWheel::SetChromosomes(std::vector<std::shared_ptr<Chromosome>> _chromosomes)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							std::unique_lock<std::recursive_mutex> lock(this->chromosomes_mutex);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->ClearChromosomes();
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->chromosomes = _chromosomes;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->ChromosomesChanged();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void RouletteWheel::AddChromosome(std::shared_ptr<Chromosome> _chromosome)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							std::unique_lock<std::recursive_mutex> lock(this->chromosomes_mutex);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->chromosomes.push_back(_chromosome);
 | 
				
			||||||
 | 
							this->ChromosomesChanged();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void RouletteWheel::AddChromosomes(std::vector<std::shared_ptr<Chromosome>> _chromosomes)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							std::unique_lock<std::recursive_mutex> lock(this->chromosomes_mutex);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							for ( std::shared_ptr<Chromosome> _chromosome  : _chromosomes ) {
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								this->chromosomes.push_back(_chromosome);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->ChromosomesChanged();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						std::shared_ptr<Chromosome> RouletteWheel::Spin()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							std::unique_lock<std::recursive_mutex> lock(this->chromosomes_mutex);
 | 
				
			||||||
 | 
							double
 | 
				
			||||||
 | 
								range_min, range_max,
 | 
				
			||||||
 | 
								spin
 | 
				
			||||||
 | 
								;
 | 
				
			||||||
 | 
							size_t i;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->PopulateSlots();
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							if ( !this->wheel_slots.size() ) {
 | 
				
			||||||
 | 
								return nullptr;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//	Spin a random number in our range
 | 
				
			||||||
 | 
							range_min = this->wheel_slots[0].first;
 | 
				
			||||||
 | 
							range_max = this->wheel_slots[this->wheel_slots.size()-1].first;
 | 
				
			||||||
 | 
							spin = this->random->GetDouble(range_min, range_max);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//	Find the corresponding chromosome
 | 
				
			||||||
 | 
							for ( i=0; i<this->wheel_slots.size(); i++ ) {
 | 
				
			||||||
 | 
								if ( this->wheel_slots[i].first >= spin ) {
 | 
				
			||||||
 | 
									return this->wheel_slots[i].second;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//	By default, return the first one I guess
 | 
				
			||||||
 | 
							return this->wheel_slots[0].second;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void RouletteWheel::Instantiate()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->random = std::shared_ptr<Random>(
 | 
				
			||||||
 | 
								new Random()
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						std::vector<std::pair<double, std::shared_ptr<Chromosome>>> RouletteWheel::GetNormalizedChromosomeFitness()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							std::unique_lock<std::recursive_mutex> lock(this->chromosomes_mutex);
 | 
				
			||||||
 | 
							std::vector< std::pair< double, std::shared_ptr<Chromosome> > > pairs;
 | 
				
			||||||
 | 
							std::pair< double, std::shared_ptr<Chromosome> > pair;
 | 
				
			||||||
 | 
							double
 | 
				
			||||||
 | 
								fitness, fitness_low, fitness_high
 | 
				
			||||||
 | 
								;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							if ( !this->chromosomes.size() ) {
 | 
				
			||||||
 | 
								return pairs;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//	Locate lowest and highest fitness
 | 
				
			||||||
 | 
							fitness_low = fitness_high = this->chromosomes[0]->GetFitness();
 | 
				
			||||||
 | 
							for ( std::shared_ptr<Chromosome> chromosome : this->chromosomes ) {
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								fitness = chromosome->GetFitness();
 | 
				
			||||||
 | 
								if ( fitness > fitness_high ) {
 | 
				
			||||||
 | 
									fitness_high = fitness;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if ( fitness < fitness_low ) {
 | 
				
			||||||
 | 
									fitness_low = fitness;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//	Generate normalized pairs
 | 
				
			||||||
 | 
							for ( std::shared_ptr<Chromosome> chromosome : this->chromosomes ) {
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								pair.first = chromosome->GetFitness() - fitness_low;
 | 
				
			||||||
 | 
								pair.first *= pair.first; //	Square to enhance the difference a little
 | 
				
			||||||
 | 
								pair.second = chromosome;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								pairs.push_back(pair);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								//cout << "[" << pair.first << "]" << chromosome->ToString() << endl;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							return pairs;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void RouletteWheel::SortChromosomes()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							std::unique_lock<std::recursive_mutex> lock(this->chromosomes_mutex);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							if ( !this->chromosomes_need_sorting ) {
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							std::sort(
 | 
				
			||||||
 | 
								this->chromosomes.begin(),
 | 
				
			||||||
 | 
								this->chromosomes.end(),
 | 
				
			||||||
 | 
								[]( const std::shared_ptr<Chromosome>& left, const std::shared_ptr<Chromosome>& right ) -> bool
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									//
 | 
				
			||||||
 | 
									if ( left->GetFitness() > right->GetFitness() ) {
 | 
				
			||||||
 | 
										return true;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->chromosomes_need_sorting = false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void RouletteWheel::PopulateSlots()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							std::unique_lock<std::recursive_mutex> lock(this->chromosomes_mutex);
 | 
				
			||||||
 | 
							std::vector<std::pair<double, std::shared_ptr<Chromosome>>> chromosomes_normalized_fitness;
 | 
				
			||||||
 | 
							std::pair<double,std::shared_ptr<Chromosome>> wheel_slot;
 | 
				
			||||||
 | 
							double
 | 
				
			||||||
 | 
								slot_begin_value
 | 
				
			||||||
 | 
								;
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							if ( !this->slots_need_population ) {
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->SortChromosomes();
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->wheel_slots.clear();
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							slot_begin_value = 0;
 | 
				
			||||||
 | 
							chromosomes_normalized_fitness = this->GetNormalizedChromosomeFitness();
 | 
				
			||||||
 | 
							for ( std::pair<double, std::shared_ptr<Chromosome>> pair: chromosomes_normalized_fitness ) {
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								wheel_slot.first = pair.first + slot_begin_value;
 | 
				
			||||||
 | 
								wheel_slot.second = pair.second;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								this->wheel_slots.push_back(wheel_slot);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								slot_begin_value += pair.first;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->slots_need_population = false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						void RouletteWheel::ChromosomesChanged()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							this->chromosomes_need_sorting = true;
 | 
				
			||||||
 | 
							this->slots_need_population = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										68
									
								
								RouletteWheel.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								RouletteWheel.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					#include <mutex>
 | 
				
			||||||
 | 
					#include <memory>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					namespace BitEvolver
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						//
 | 
				
			||||||
 | 
						class RouletteWheel
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							public:
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								RouletteWheel();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								void Reset();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								void ClearChromosomes();
 | 
				
			||||||
 | 
								void SetChromosomes(std::vector<std::shared_ptr<class Chromosome>> _chromosomes);
 | 
				
			||||||
 | 
								void AddChromosome(std::shared_ptr<class Chromosome> _chromosome);
 | 
				
			||||||
 | 
								void AddChromosomes(std::vector<std::shared_ptr<class Chromosome>> _chromosomes);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								std::shared_ptr<Chromosome> Spin();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							//
 | 
				
			||||||
 | 
							private:
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								std::shared_ptr<class Random> random;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								std::vector<std::shared_ptr<class Chromosome>> chromosomes;
 | 
				
			||||||
 | 
								std::recursive_mutex chromosomes_mutex;
 | 
				
			||||||
 | 
								bool chromosomes_need_sorting;
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								std::vector<std::pair<double,std::shared_ptr<class Chromosome>>> wheel_slots;
 | 
				
			||||||
 | 
								bool slots_need_population;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								void Instantiate();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								std::vector<std::pair<double, std::shared_ptr<class Chromosome>>> GetNormalizedChromosomeFitness();
 | 
				
			||||||
 | 
								void SortChromosomes();
 | 
				
			||||||
 | 
								void PopulateSlots();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								//
 | 
				
			||||||
 | 
								void ChromosomesChanged();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Reference in New Issue
	
	Block a user