Skip to content

Commit 04c59b6

Browse files
committed
update docs
1 parent eb9065b commit 04c59b6

File tree

8 files changed

+55
-59
lines changed

8 files changed

+55
-59
lines changed

README.md

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ impl Fitness for CountTrue {
7373
// the search strategy
7474
let evolve = Evolve::builder()
7575
.with_genotype(genotype)
76-
.with_select(SelectElite::new(0.5, 0.02)) // sort the chromosomes by fitness to determine crossover order and drop excess population above target_population_size
77-
.with_crossover(CrossoverUniform::new(0.7, 0.8)) // crossover all individual genes between 2 chromosomes for offspring with 40% parent selection (60% do not produce offspring) and 80% chance of crossover (20% of parents just clone)
76+
.with_select(SelectElite::new(0.5, 0.02)) // sort the chromosomes by fitness to determine crossover order. Strive to replace 50% of the population with offspring. Allow 2% through the non-generational best chromosomes gate before selection and replacement
77+
.with_crossover(CrossoverUniform::new(0.7, 0.8)) // crossover all individual genes between 2 chromosomes for offspring with 70% parent selection (30% do not produce offspring) and 80% chance of crossover (20% of parents just clone)
7878
.with_mutate(MutateSingleGene::new(0.2)) // mutate offspring for a single gene with a 20% probability per chromosome
7979
.with_fitness(CountTrue) // count the number of true values in the chromosomes
8080
.with_fitness_ordering(FitnessOrdering::Maximize) // optional, default is Maximize, aim towards the most true values
@@ -137,32 +137,16 @@ For the Evolve strategy:
137137
sorting of some kind. This is relatively fast compared to the rest of the
138138
operations.
139139
* Crossover: the workhorse of internal parts. Crossover touches most genes each
140-
generation and clones up to the whole population to restore lost population
141-
size in selection. See performance tips below.
142-
It also calculates new genes hashes if enabled on the Genotype,
143-
which has a relatively high overhead on the main Evolve loop.
140+
generation and clones up to the whole population to produce offspring
141+
(depending on selection-rate). It also calculates
142+
new genes hashes if enabled on the Genotype, which has a relatively high
143+
overhead on the main Evolve loop.
144144
* Mutate: no considerations. It touches genes like crossover does, but should
145145
be used sparingly anyway; with low gene counts (<10%) and low probability (5-20%)
146146
* Fitness: can be anything. This fully depends on the user domain. Parallelize
147147
it using `with_par_fitness()` in the Builder. But beware that parallelization
148148
has it's own overhead and is not always faster.
149149

150-
**Performance Tips**
151-
* Small genes sizes
152-
* It seems that CrossoverMultiGene with `number_of_crossovers = genes_size / 2`
153-
and `allow_duplicates = true` is the best tradeoff between performance and
154-
effect. CrossoverUniform is an alias for the same approach, taking the
155-
genes_size from the genotype at runtime.
156-
* Restoring the population doesn't matter that much as the cloning is
157-
relatively less pronounced (but becomes more prominent for larger population
158-
sizes)
159-
* Large genes sizes
160-
* It seems that CrossoverMultiPoint with `number_of_crossovers = genes_size / 9`
161-
and `allow_duplicates = false` is the best tradeoff between performance and effect.
162-
* Restoring the population has considerable performance effects.
163-
Use a high selection_rate or even 100%, so there is little parent
164-
cloning. Explore non-Vec based genotypes like BitGenotype.
165-
166150
**GPU acceleration**
167151

168152
There are two genotypes where Genes (N) and Population (M) are a stored in single contiguous

src/extension/mass_degeneration.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::strategy::{StrategyAction, StrategyReporter, StrategyState};
55
use rand::Rng;
66
use std::time::Instant;
77

8-
/// Simulates a cambrian explosion. The controlling metric is fitness score cardinality in the
8+
/// Simulates a cambrian explosion. The controlling metric is population cardinality in the
99
/// population after selection. When this cardinality drops to the threshold, the full population
1010
/// is mutated the provided number of times, where the [Genotype](crate::genotype::Genotype)
1111
/// determines whether this is random, relative or scaled.

src/extension/mass_extinction.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@ use crate::strategy::{StrategyAction, StrategyReporter, StrategyState};
55
use rand::Rng;
66
use std::time::Instant;
77

8-
/// Simulates a cambrian explosion. The controlling metric is fitness score cardinality in the
8+
/// Simulates a cambrian explosion. The controlling metric is population cardinality in the
99
/// population after selection. When this cardinality drops to the threshold, the population is
1010
/// randomly reduced regardless of fitness using the survival_rate (fraction of population).
1111
///
12-
/// Ensure you have some population growth in select/crossover by setting the
13-
/// [Select](crate::select::Select) selection_rate > 0.5 in order for the population to recover
12+
/// Population will recover in the following generations
1413
#[derive(Debug, Clone)]
1514
pub struct MassExtinction {
1615
pub cardinality_threshold: usize,

src/extension/mass_genesis.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ use std::time::Instant;
99
/// A version of [MassExtinction](crate::extension::ExtensionMassExtinction), where only an adam
1010
/// and eve of current best chromosomes survive
1111
///
12-
/// Ensure you have some population growth in select/crossover by setting the
13-
/// [Select](crate::select::Select) selection_rate > 0.5 in order for the population to recover
12+
/// Population will recover in the following generations
1413
#[derive(Debug, Clone)]
1514
pub struct MassGenesis {
1615
pub cardinality_threshold: usize,

src/genotype/static_matrix.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ use std::ops::{Bound, Range, RangeBounds, RangeInclusive};
4444
///
4545
/// # Panics
4646
///
47-
/// Will panic if more chromosomes are instantiated than the population (M) allows.
47+
/// Will panic if more chromosomes are instantiated than the population (M) allows. M should
48+
/// account for the target_population_size and the crossover selection_rate which adds offspring on
49+
/// top of that.
4850
///
4951
/// # Example (f32):
5052
/// ```

src/lib.rs

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@
5050
//! // the search strategy
5151
//! let evolve = Evolve::builder()
5252
//! .with_genotype(genotype)
53-
//! .with_select(SelectElite::new(0.5, 0.02)) // sort the chromosomes by fitness to determine crossover order and drop excess population above target_population_size
54-
//! .with_crossover(CrossoverUniform::new(0.7, 0.8)) // crossover all individual genes between 2 chromosomes for offspring with 40% parent selection (60% do not produce offspring) and 80% chance of crossover (20% of parents just clone)
53+
//! .with_select(SelectElite::new(0.5, 0.02)) // sort the chromosomes by fitness to determine crossover order. Strive to replace 50% of the population with offspring. Allow 2% through the non-generational best chromosomes gate before selection and replacement
54+
//! .with_crossover(CrossoverUniform::new(0.7, 0.8)) // crossover all individual genes between 2 chromosomes for offspring with 70% parent selection (30% do not produce offspring) and 80% chance of crossover (20% of parents just clone)
5555
//! .with_mutate(MutateSingleGene::new(0.2)) // mutate offspring for a single gene with a 20% probability per chromosome
5656
//! .with_fitness(CountTrue) // count the number of true values in the chromosomes
5757
//! .with_fitness_ordering(FitnessOrdering::Maximize) // optional, default is Maximize, aim towards the most true values
@@ -118,34 +118,15 @@
118118
//! sorting of some kind. This is relatively fast compared to the rest of the
119119
//! operations.
120120
//! * [Crossover](crossover): the workhorse of internal parts. Crossover touches most genes each
121-
//! generation and clones up to the whole population to restore lost population size in selection.
122-
//! See performance tips below.
123-
//! It also calculates new genes hashes if enabled on the [Genotype](genotype), which has a
124-
//! relatively high overhead on the main Evolve loop.
121+
//! generation and clones up to the whole population to produce offspring (depending on
122+
//! selection-rate). It also calculates new genes hashes if enabled on the [Genotype](genotype),
123+
//! which has a relatively high overhead on the main Evolve loop.
125124
//! * [Mutate](mutate): no considerations. It touches genes like crossover does, but should
126125
//! be used sparingly anyway; with low gene counts (<10%) and low probability (5-20%)
127126
//! * [Fitness](fitness): can be anything. This fully depends on the user domain. Parallelize
128127
//! it using `with_par_fitness()` in the Builder. But beware that parallelization
129128
//! has it's own overhead and is not always faster.
130129
//!
131-
//! **Performance Tips**
132-
//!
133-
//! * Small genes sizes
134-
//! * It seems that [CrossoverMultiGene](crossover::CrossoverMultiGene) with
135-
//! `number_of_crossovers = genes_size / 2` and `allow_duplicates = true`
136-
//! is the best tradeoff between performance and effect.
137-
//! [CrossoverUniform](crossover::CrossoverUniform) is an alias for the same approach,
138-
//! taking the genes_size from the genotype at runtime.
139-
//! * Restoring the population doesn't matter that much as the cloning is relatively less
140-
//! pronounced (but becomes more prominent for larger population sizes)
141-
//! * Large genes sizes
142-
//! * It seems that [CrossoverMultiPoint](crossover::CrossoverMultiPoint) with
143-
//! `number_of_crossovers = genes_size / 9` and `allow_duplicates = false` is
144-
//! the best tradeoff between performance and effect.
145-
//! * Restoring the population has considerable performance effects. Use a high
146-
//! selection_rate or even 100%, so there is little parent cloning. Explore non-Vec based
147-
//! genotypes like [BitGenotype](genotype::BitGenotype).
148-
//!
149130
//! **GPU acceleration**
150131
//!
151132
//! There are two genotypes where Genes (N) and Population (M) are a stored in single contiguous

src/strategy.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@
4040
//! // the search strategy (superset), steps marked (E)volve, (H)illClimb and (P)ermutate
4141
//! let builder = StrategyBuilder::new()
4242
//! .with_genotype(genotype) // (E,H,P) the genotype
43-
//! .with_select(SelectElite::new(0.5, 0.02)) // (E) sort the chromosomes by fitness to determine crossover order and drop excess population above target_population_size
44-
//! .with_extension(ExtensionMassExtinction::new(10, 0.1)) // (E) optional builder step, simulate cambrian explosion by mass extinction, when fitness score cardinality drops to 10 after the selection, trim to 10% of population
45-
//! .with_crossover(CrossoverUniform::new(0.7, 0.8)) // (E) crossover all individual genes between 2 chromosomes for offspring with 40% parent selection (60% do not produce offspring) and 80% chance of crossover (20% of parents just clone)
43+
//! .with_select(SelectElite::new(0.5, 0.02)) // (E) sort the chromosomes by fitness to determine crossover order. Strive to replace 50% of the population with offspring. Allow 2% through the non-generational best chromosomes gate before selection and replacement
44+
//! .with_extension(ExtensionMassExtinction::new(10, 0.1)) // (E) optional builder step, simulate cambrian explosion by mass extinction, when population cardinality drops to 10 after the selection, trim to 10% of population
45+
//! .with_crossover(CrossoverUniform::new(0.7, 0.8)) // (E) crossover all individual genes between 2 chromosomes for offspring with 70% parent selection (30% do not produce offspring) and 80% chance of crossover (20% of parents just clone)
4646
//! .with_mutate(MutateSingleGene::new(0.2)) // (E) mutate offspring for a single gene with a 20% probability per chromosome
4747
//! .with_fitness(CountTrue) // (E,H,P) count the number of true values in the chromosomes
4848
//! .with_fitness_ordering(FitnessOrdering::Minimize) // (E,H,P) aim for the least true values

src/strategy/evolve.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,37 @@ pub enum EvolveVariant {
5353
/// * max_stale_generations: when the ultimate goal in terms of fitness score is unknown and one depends on some convergion
5454
/// threshold, or one wants a duration limitation next to the target_fitness_score
5555
///
56+
/// General Hyper-parameters:
57+
/// * `replacement_rate` (selection): the target fraction of the population which exists of
58+
/// children. Generational Replacement and Steady-State Replacement can both be
59+
/// modelled with this parameter by setting it respectively to 1.0 and 0.2-0.8.
60+
/// High values converge faster, but risk losing good solutions. Low values
61+
/// convergence slower. If there is a shortage of population after the ideal
62+
/// fraction, firstly remaining non-selected children and secondly remaining
63+
/// non-selected parents will be used to fill the shortage to avoid population
64+
/// collapse.
65+
/// * `elitism_rate` (selection): a non-generational elite gate, which ensures passing of the
66+
/// best chromosomes before selection and replacement takes place. Value should
67+
/// typically be very low, between 0.01 and 0.05. Relevant for
68+
/// `SelectTournament` where the best chromosome is not guaranteed to be
69+
/// selected for a tournament if the `population_size` is larger than the
70+
/// `target_population_size`
71+
/// * `selection_rate` (crossover): the fraction of parents which are selected for
72+
/// reproduction. This selection adds offspring to the population, the other
73+
/// parents do not. The population now grows by the added offspring, as the
74+
/// parents are not replaced yet. Value should typically be between 0.4 and
75+
/// 0.8. High values risk of premature convergence. Low values reduce diversity
76+
/// if overused.
77+
/// * `crossover_rate (or recombination-rate)` (crossover): the fraction of selected parents
78+
/// to crossover, the remaining parents just clone as offspring. Value should
79+
/// typically be between 0.5 and 0.8. High values converge faster, but risk
80+
/// losing good solutions. Low values have poor exploration and risk of
81+
/// premature convergence
82+
/// * `mutation_probability` (mutation): the fraction of offspring which gets mutated.
83+
/// Typically low, between 0.01 and 0.10. High values reduces convergence
84+
/// ability. Low have a risk of stagnation.
85+
///
86+
///
5687
/// There are optional mutation distance limitations for
5788
/// [RangeGenotype](crate::genotype::RangeGenotype) and
5889
/// [MultiRangeGenotype](crate::genotype::MultiRangeGenotype) chromosomes. Listed in descending
@@ -114,9 +145,9 @@ pub enum EvolveVariant {
114145
/// let evolve = Evolve::builder()
115146
/// .with_genotype(genotype)
116147
///
117-
/// .with_select(SelectElite::new(0.5, 0.02)) // sort the chromosomes by fitness to determine crossover order and drop excess population above target_population_size
118-
/// .with_extension(ExtensionMassExtinction::new(10, 0.1)) // optional builder step, simulate cambrian explosion by mass extinction, when fitness score cardinality drops to 10 after the selection, trim to 10% of population
119-
/// .with_crossover(CrossoverUniform::new(0.7, 0.8)) // crossover all individual genes between 2 chromosomes for offspring with 40% parent selection (60% do not produce offspring) and 80% chance of crossover (20% of parents just clone)
148+
/// .with_select(SelectElite::new(0.5, 0.02)) // sort the chromosomes by fitness to determine crossover order. Strive to replace 50% of the population with offspring. Allow 2% through the non-generational best chromosomes gate before selection and replacement
149+
/// .with_extension(ExtensionMassExtinction::new(10, 0.1)) // optional builder step, simulate cambrian explosion by mass extinction, when population cardinality drops to 10 after the selection, trim to 10% of population
150+
/// .with_crossover(CrossoverUniform::new(0.7, 0.8)) // crossover all individual genes between 2 chromosomes for offspring with 70% parent selection (30% do not produce offspring) and 80% chance of crossover (20% of parents just clone)
120151
/// .with_mutate(MutateSingleGene::new(0.2)) // mutate offspring for a single gene with a 20% probability per chromosome
121152
/// .with_fitness(CountTrue) // count the number of true values in the chromosomes
122153
/// .with_fitness_ordering(FitnessOrdering::Minimize) // aim for the least true values

0 commit comments

Comments
 (0)