New crossover features: Order, Bounds, Standard deviation

This commit is contained in:
Mike 2018-04-14 19:58:13 -07:00
parent cb0f81b3e1
commit 62ab4f9a16
5 changed files with 182 additions and 50 deletions

View File

@ -29,23 +29,51 @@ namespace BitEvolver
std::shared_ptr<Chromosome> mama, std::shared_ptr<Chromosome> mama,
std::shared_ptr<Chromosome> papa, std::shared_ptr<Chromosome> papa,
Enums::CrossoverType crossover_type, 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 double mutation_rate
) )
{ {
// //
std::shared_ptr<Chromosome> kiddo; std::shared_ptr<Chromosome>
int bit_length; parent_primary,
parent_secondary,
kiddo
;
// // Choose primary / secondary parents
bit_length = mama->GetBitCount(); 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 // Directly copy the primary parent first
kiddo = std::shared_ptr<Chromosome>(new Chromosome(this->random, bit_length)); kiddo = std::shared_ptr<Chromosome>(new Chromosome(this->random, parent_primary->GetBitCount()));
*kiddo = *mama; *kiddo = *parent_primary;
// Apply crossover // Apply crossover with the secondary parent
this->ApplyCrossover(kiddo, papa, crossover_type, crossover_rate); this->ApplyCrossover(
kiddo, parent_secondary,
crossover_type, crossover_bounds, crossover_point, crossover_point_std
);
// Apply mutation // Apply mutation
this->Mutate(kiddo, mutation_rate); this->Mutate(kiddo, mutation_rate);
@ -80,39 +108,56 @@ namespace BitEvolver
} }
// //
int Breeder::PickRandomCrossoverPoint(std::shared_ptr<Chromosome> chromosome, double crossover_rate) int Breeder::PickRandomCrossoverPoint(
std::shared_ptr<Chromosome> chromosome,
Enums::CrossoverBounds crossover_bounds,
double crossover_point,
double crossover_point_std
)
{ {
// //
double crossover_point_double; int crossover_point_index;
int crossover_point;
int bit_count; int bit_count;
double random_double;
// //
bit_count = chromosome->GetBitCount(); bit_count = chromosome->GetBitCount();
/** /**
Choose a double between [0.0,1.0] for the crossover point. Choose a double between [0.0,1.0] for the crossover point.
Use normal distribution, with the mean to the default point, Use normal distribution, with the mean and std from the parameters.
and 1.0 as the std.
That way, there is still randomness to the crossover point, 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 // 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 // Loop around to keep in bounds?
while ( crossover_point < 0 ) if ( crossover_bounds == Enums::CrossoverBounds::Wrap ) {
{ while ( crossover_point_index < 0 )
crossover_point += bit_count; {
crossover_point_index += bit_count;
}
while ( crossover_point_index >= bit_count)
{
crossover_point_index -= bit_count;
}
} }
while ( crossover_point >= bit_count) else if ( crossover_bounds == Enums::CrossoverBounds::Clip ) {
{ if ( crossover_point_index < 0 ) {
crossover_point -= bit_count; 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<Chromosome> kiddo, std::shared_ptr<Chromosome> kiddo,
std::shared_ptr<Chromosome> parent, std::shared_ptr<Chromosome> parent,
Enums::CrossoverType crossover_type, Enums::CrossoverType crossover_type,
double crossover_rate Enums::CrossoverBounds crossover_bounds,
double crossover_point,
double crossover_point_std
) )
{ {
// //
int int
bits_count, bits_count,
crossover_point, crossover_point_index,
i i
; ;
@ -142,11 +189,11 @@ namespace BitEvolver
} }
// Pick random crossover point // 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 // Begin copying the parent at the crossover point and beyond
// (not before) // (not before)
for ( i=crossover_point; i<bits_count; i++) { for ( i=crossover_point_index; i<bits_count; i++) {
kiddo->SetBit( i, parent->GetBit(i) ); kiddo->SetBit( i, parent->GetBit(i) );
} }

View File

@ -21,7 +21,10 @@ namespace BitEvolver
std::shared_ptr<class Chromosome> mama, std::shared_ptr<class Chromosome> mama,
std::shared_ptr<class Chromosome> papa, std::shared_ptr<class Chromosome> papa,
Enums::CrossoverType crossover_type, 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 double mutation_rate
); );
@ -35,12 +38,19 @@ namespace BitEvolver
std::shared_ptr<class Random> random; std::shared_ptr<class Random> random;
// //
int PickRandomCrossoverPoint(std::shared_ptr<class Chromosome> chromosome, double crossover_rate); int PickRandomCrossoverPoint(
std::shared_ptr<class Chromosome> chromosome,
Enums::CrossoverBounds crossover_bounds,
double crossover_point,
double crossover_point_std
);
void ApplyCrossover( void ApplyCrossover(
std::shared_ptr<class Chromosome> kiddo, std::shared_ptr<class Chromosome> kiddo,
std::shared_ptr<class Chromosome> parent, std::shared_ptr<class Chromosome> parent,
Enums::CrossoverType crossover_type, Enums::CrossoverType crossover_type,
double crossover_rate Enums::CrossoverBounds crossover_bounds,
double crossover_point,
double crossover_point_std
); );
}; };
}; };

16
Enums.h
View File

@ -16,6 +16,22 @@ namespace BitEvolver
Sexual Sexual
}; };
//
enum class CrossoverOrder
{
//
MamaPapa,
ByFitness
};
//
enum class CrossoverBounds
{
//
Clip,
Wrap
};
// //
enum class ElitismType enum class ElitismType
{ {

View File

@ -56,7 +56,12 @@ namespace BitEvolver
// //
this->SetCrossoverType(Population::DEFAULT_CROSSOVER_TYPE); 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->SetCrossoverPoint(Population::DEFAULT_CROSSOVER_POINT);
this->SetCrossoverPointStandardDeviation(Population::DEFAULT_CROSSOVER_POINT_STD);
//
this->SetMutationRate(Population::DEFAULT_MUTATION_RATE); this->SetMutationRate(Population::DEFAULT_MUTATION_RATE);
// //
@ -165,6 +170,48 @@ namespace BitEvolver
return fitness_average; 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) 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(); mama = this->roulette_wheel->Spin();
papa = 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( kiddo = this->breeder->Breed(
mama, papa, mama, papa,
this->crossover_type, this->crossover_type,
this->crossover_order,
this->crossover_bounds,
this->crossover_point, this->crossover_point,
this->crossover_point_std,
this->mutation_rate this->mutation_rate
); );

View File

@ -48,10 +48,17 @@ namespace BitEvolver
double GetAverageFitness(std::vector<std::shared_ptr<class Chromosome>> _chromosomes); double GetAverageFitness(std::vector<std::shared_ptr<class Chromosome>> _chromosomes);
// //
void SetCrossoverPoint(double p);
double GetCrossoverPoint();
void SetCrossoverType(Enums::CrossoverType t); void SetCrossoverType(Enums::CrossoverType t);
Enums::CrossoverType GetCrossoverType(); 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); void SetMutationRate(double r);
double GetMutationRate(); double GetMutationRate();
@ -76,14 +83,17 @@ namespace BitEvolver
void PrintPopulation(std::vector<std::shared_ptr<class Chromosome>> _chromosomes); void PrintPopulation(std::vector<std::shared_ptr<class Chromosome>> _chromosomes);
// Constants // Constants
const static int DEFAULT_POPULATION_SIZE = 100; const static int DEFAULT_POPULATION_SIZE = 100;
const static Enums::ElitismType DEFAULT_ELITISM_TYPE = Enums::ElitismType::Rate; const static Enums::ElitismType DEFAULT_ELITISM_TYPE = Enums::ElitismType::Rate;
constexpr static double DEFAULT_ELITISM_RATE = 0.01; constexpr static double DEFAULT_ELITISM_RATE = 0.01;
const static int DEFAULT_ELITISM_COUNT = 1; const static int DEFAULT_ELITISM_COUNT = 1;
constexpr static double DEFAULT_MUTATION_RATE = 0.01; constexpr static double DEFAULT_MUTATION_RATE = 0.01;
// //
const static Enums::CrossoverType DEFAULT_CROSSOVER_TYPE = Enums::CrossoverType::Sexual; const static Enums::CrossoverType DEFAULT_CROSSOVER_TYPE = Enums::CrossoverType::Sexual;
const static int DEFAULT_CROSSOVER_POINT = 0.7; 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: private:
@ -100,7 +110,10 @@ namespace BitEvolver
// //
Enums::CrossoverType crossover_type; Enums::CrossoverType crossover_type;
Enums::CrossoverOrder crossover_order;
Enums::CrossoverBounds crossover_bounds;
double crossover_point; double crossover_point;
double crossover_point_std;
double mutation_rate; double mutation_rate;
Enums::ElitismType elitism_type; Enums::ElitismType elitism_type;
double elitism_rate; double elitism_rate;