|
|
@ -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; |
|
|
|
|
|
|
|
//
|
|
|
|
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<Chromosome>(new Chromosome(this->random, bit_length)); |
|
|
|
*kiddo = *mama; |
|
|
|
// Directly copy the primary parent first
|
|
|
|
kiddo = std::shared_ptr<Chromosome>(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> 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) ); |
|
|
|
} |
|
|
|
|
|
|
|