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> 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<Chromosome> kiddo;
int bit_length;
std::shared_ptr<Chromosome>
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;
// Directly copy the mama
kiddo = std::shared_ptr<Chromosome>(new Chromosome(this->random, bit_length));
*kiddo = *mama;
//
case Enums::CrossoverOrder::ByFitness:
if ( mama->GetFitness() > papa->GetFitness() ) {
parent_primary = mama;
parent_secondary = papa;
}
else{
parent_primary = papa;
parent_secondary = mama;
}
break;
}
// Apply crossover
this->ApplyCrossover(kiddo, papa, crossover_type, crossover_rate);
// 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);
@ -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;
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<Chromosome> kiddo,
std::shared_ptr<Chromosome> 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; i<bits_count; i++) {
for ( i=crossover_point_index; i<bits_count; 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> 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<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(
std::shared_ptr<class Chromosome> kiddo,
std::shared_ptr<class Chromosome> parent,
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
};
//
enum class CrossoverOrder
{
//
MamaPapa,
ByFitness
};
//
enum class CrossoverBounds
{
//
Clip,
Wrap
};
//
enum class ElitismType
{

View File

@ -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
);

View File

@ -48,10 +48,17 @@ namespace BitEvolver
double GetAverageFitness(std::vector<std::shared_ptr<class Chromosome>> _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<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 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;