From 62ab4f9a16c125345b4e801c14f7221b28d70b13 Mon Sep 17 00:00:00 2001 From: Mike Date: Sat, 14 Apr 2018 19:58:13 -0700 Subject: [PATCH] New crossover features: Order, Bounds, Standard deviation --- Breeder.cpp | 107 +++++++++++++++++++++++++++++++++++-------------- Breeder.h | 16 ++++++-- Enums.h | 16 ++++++++ Population.cpp | 62 ++++++++++++++++++++++++---- Population.h | 31 +++++++++----- 5 files changed, 182 insertions(+), 50 deletions(-) diff --git a/Breeder.cpp b/Breeder.cpp index b4f91b0..1a35347 100644 --- a/Breeder.cpp +++ b/Breeder.cpp @@ -29,23 +29,51 @@ namespace BitEvolver std::shared_ptr mama, std::shared_ptr papa, Enums::CrossoverType crossover_type, - double crossover_rate, + Enums::CrossoverOrder crossover_order, + Enums::CrossoverBounds crossover_bounds, + double crossover_point, + double crossover_point_std, double mutation_rate ) { // - std::shared_ptr kiddo; - int bit_length; + std::shared_ptr + parent_primary, + parent_secondary, + kiddo + ; - // - bit_length = mama->GetBitCount(); + // 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 mama - kiddo = std::shared_ptr(new Chromosome(this->random, bit_length)); - *kiddo = *mama; + // Directly copy the primary parent first + kiddo = std::shared_ptr(new Chromosome(this->random, parent_primary->GetBitCount())); + *kiddo = *parent_primary; - // Apply crossover - this->ApplyCrossover(kiddo, papa, crossover_type, crossover_rate); + // 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); @@ -80,39 +108,56 @@ namespace BitEvolver } // - int Breeder::PickRandomCrossoverPoint(std::shared_ptr chromosome, double crossover_rate) + int Breeder::PickRandomCrossoverPoint( + std::shared_ptr chromosome, + Enums::CrossoverBounds crossover_bounds, + double crossover_point, + double crossover_point_std + ) { // - double crossover_point_double; - int crossover_point; + 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 to the default point, - and 1.0 as the std. + 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 default + but it still generally sticks near the chosen point. */ - crossover_point_double = this->random->GetNormal(crossover_rate, 1.0); + random_double = this->random->GetNormal(crossover_point, crossover_point_std); // Apply to the actual int length - crossover_point = crossover_point_double * bit_count; + crossover_point_index = floor(random_double * bit_count); - // Loop around to keep in bounds - while ( crossover_point < 0 ) - { - crossover_point += 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; + } } - while ( crossover_point >= bit_count) - { - crossover_point -= 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; + return crossover_point_index; } // @@ -120,13 +165,15 @@ namespace BitEvolver std::shared_ptr kiddo, std::shared_ptr parent, Enums::CrossoverType crossover_type, - double crossover_rate + Enums::CrossoverBounds crossover_bounds, + double crossover_point, + double crossover_point_std ) { // int bits_count, - crossover_point, + crossover_point_index, i ; @@ -142,11 +189,11 @@ namespace BitEvolver } // Pick random crossover point - crossover_point = this->PickRandomCrossoverPoint(kiddo, crossover_rate); + 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; iSetBit( i, parent->GetBit(i) ); } diff --git a/Breeder.h b/Breeder.h index 40f4ed1..0b6b4fb 100644 --- a/Breeder.h +++ b/Breeder.h @@ -21,7 +21,10 @@ namespace BitEvolver std::shared_ptr mama, std::shared_ptr papa, Enums::CrossoverType crossover_type, - double crossover_rate, + Enums::CrossoverOrder crossover_order, + Enums::CrossoverBounds crossover_bounds, + double crossover_point, + double crossover_point_std, double mutation_rate ); @@ -35,12 +38,19 @@ namespace BitEvolver std::shared_ptr random; // - int PickRandomCrossoverPoint(std::shared_ptr chromosome, double crossover_rate); + int PickRandomCrossoverPoint( + std::shared_ptr chromosome, + Enums::CrossoverBounds crossover_bounds, + double crossover_point, + double crossover_point_std + ); void ApplyCrossover( std::shared_ptr kiddo, std::shared_ptr parent, Enums::CrossoverType crossover_type, - double crossover_rate + Enums::CrossoverBounds crossover_bounds, + double crossover_point, + double crossover_point_std ); }; }; diff --git a/Enums.h b/Enums.h index 0d524db..bf3410c 100644 --- a/Enums.h +++ b/Enums.h @@ -16,6 +16,22 @@ namespace BitEvolver Sexual }; + // + enum class CrossoverOrder + { + // + MamaPapa, + ByFitness + }; + + // + enum class CrossoverBounds + { + // + Clip, + Wrap + }; + // enum class ElitismType { diff --git a/Population.cpp b/Population.cpp index 5b58b64..85d82b7 100644 --- a/Population.cpp +++ b/Population.cpp @@ -56,7 +56,12 @@ namespace BitEvolver // 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); // @@ -165,6 +170,48 @@ namespace BitEvolver 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) { @@ -180,17 +227,17 @@ namespace BitEvolver } // - void Population::SetCrossoverType(Enums::CrossoverType t) + void Population::SetCrossoverPointStandardDeviation(double std) { // - this->crossover_type = t; + this->crossover_point_std = std; } // - Enums::CrossoverType Population::GetCrossoverType() + double Population::GetCrossoverPointStandardDeviation() { // - return this->crossover_type; + return this->crossover_point_std; } // @@ -709,15 +756,14 @@ namespace BitEvolver mama = this->roulette_wheel->Spin(); papa = this->roulette_wheel->Spin(); - // - //cout << "Roulette Wheel (mama): " << mama->ToString() << endl; - //cout << "Roulette Wheel (papa): " << papa->ToString() << endl; - // 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 ); diff --git a/Population.h b/Population.h index ca60a63..e6ab36b 100644 --- a/Population.h +++ b/Population.h @@ -48,10 +48,17 @@ namespace BitEvolver double GetAverageFitness(std::vector> _chromosomes); // - void SetCrossoverPoint(double p); - double GetCrossoverPoint(); 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(); @@ -76,14 +83,17 @@ namespace BitEvolver void PrintPopulation(std::vector> _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 int DEFAULT_POPULATION_SIZE = 100; + const static Enums::ElitismType DEFAULT_ELITISM_TYPE = Enums::ElitismType::Rate; + constexpr static double DEFAULT_ELITISM_RATE = 0.01; + const static int DEFAULT_ELITISM_COUNT = 1; + constexpr static double DEFAULT_MUTATION_RATE = 0.01; // - const static Enums::CrossoverType DEFAULT_CROSSOVER_TYPE = Enums::CrossoverType::Sexual; - const static int DEFAULT_CROSSOVER_POINT = 0.7; + 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: @@ -100,7 +110,10 @@ namespace BitEvolver // 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;