1414//! High values converge faster, but risk losing good solutions. Low values have poor exploration
1515//! and risk of premature convergence
1616//!
17- //! Normally the crossover adds children to the popluation, thus increasing the population_size
18- //! above the target_population_size. Selection will reduce this again in the next generation
17+ //! As crossover adds offspring (with age zero) it is also the responsibility of the crossover to
18+ //! increment the age of the parents. This is done because the definition of "offspring" is "age
19+ //! zero". So this should be done in-sync and is therefore not a generational loop concern of Evolve.
20+ //!
21+ //! Normally the crossover adds children to the population, thus increasing the population_size
22+ //! above the target_population_size. Selection will reduce this again in the next generation.
1923mod clone;
2024mod multi_gene;
2125mod multi_point;
@@ -79,7 +83,9 @@ pub type CrossoverAllele<C> = <<C as Crossover>::Genotype as Genotype>::Allele;
7983/// let selected_population_size =
8084/// (existing_population_size as f32 * self.selection_rate).ceil() as usize;
8185///
82- /// // Important!!! Append offspring as recycled clones from parents (will crossover later)
86+ /// // Important!!! Increment age, as the old offspring now become parents
87+ /// state.population.increment_age();
88+ /// // Important!!! Append offspring as recycled clones from parents (will reset age and crossover later)
8389/// // Use population's methods for safe chromosome recycling
8490/// state.population.extend_from_within(selected_population_size);
8591///
@@ -97,7 +103,7 @@ pub type CrossoverAllele<C> = <<C as Crossover>::Genotype as Genotype>::Allele;
97103/// std::mem::swap(&mut offspring1.genes[even_index], &mut offspring2.genes[even_index]);
98104/// // MultiRangeGenotype specific methods are available if needed
99105/// }
100- /// // Important!!! Remember to reset the chromosome metadata after manipulation
106+ /// // Important!!! Remember to reset the chromosome metadata after manipulation (also resets age)
101107/// offspring1.reset_metadata(genotype.genes_hashing);
102108/// offspring2.reset_metadata(genotype.genes_hashing);
103109/// }
@@ -118,6 +124,15 @@ pub type CrossoverAllele<C> = <<C as Crossover>::Genotype as Genotype>::Allele;
118124pub trait Crossover : Clone + Send + Sync + std:: fmt:: Debug {
119125 type Genotype : EvolveGenotype ;
120126
127+ fn before (
128+ & mut self ,
129+ _genotype : & Self :: Genotype ,
130+ _state : & mut EvolveState < Self :: Genotype > ,
131+ _config : & EvolveConfig ,
132+ ) {
133+ // Default no-op implementation
134+ }
135+
121136 fn call < R : Rng , SR : StrategyReporter < Genotype = Self :: Genotype > > (
122137 & mut self ,
123138 genotype : & Self :: Genotype ,
@@ -127,6 +142,16 @@ pub trait Crossover: Clone + Send + Sync + std::fmt::Debug {
127142 rng : & mut R ,
128143 ) ;
129144
145+ /// Optionally update population cardinality after crossover, disabled by default
146+ fn after (
147+ & mut self ,
148+ _genotype : & Self :: Genotype ,
149+ _state : & mut EvolveState < Self :: Genotype > ,
150+ _config : & EvolveConfig ,
151+ ) {
152+ // state.update_population_cardinality(genotype, config);
153+ }
154+
130155 /// to guard against invalid Crossover strategies which break the internal consistency
131156 /// of the genes, unique genotypes can't simply exchange genes without gene duplication issues
132157 fn require_crossover_indexes ( & self ) -> bool {
0 commit comments