33This file helps AI coding agents use this library correctly. It covers decision
44guidance, API reference, gotchas, and copy-paste templates.
55
6+ ** Read the Gotchas section before writing code.** Gotchas 1, 2, 3, and 7 cause
7+ compilation or runtime failures that are hard to debug after the fact.
8+
69## Quick Start
710
811``` rust
@@ -110,6 +113,22 @@ for diversity) or `CrossoverRejuvenate` (like Clone but optimized for less memor
110113| ` MutateSingleGeneDynamic ` | Auto-adjusts probability based on population cardinality. |
111114| ` MutateMultiGeneDynamic ` | Auto-adjusts probability based on cardinality. Multiple genes. |
112115
116+ ### If unsure, start here
117+
118+ For binary/list genotypes:
119+ ``` rust
120+ . with_select (SelectTournament :: new (0.5 , 0.02 , 4 ))
121+ . with_crossover (CrossoverUniform :: new (0.7 , 0.8 ))
122+ . with_mutate (MutateSingleGene :: new (0.2 ))
123+ ```
124+
125+ For unique genotypes (permutation problems):
126+ ``` rust
127+ . with_select (SelectTournament :: new (0.5 , 0.02 , 4 ))
128+ . with_crossover (CrossoverClone :: new (0.7 ))
129+ . with_mutate (MutateMultiGene :: new (2 , 0.2 ))
130+ ```
131+
113132## Constructor Parameter Reference
114133
115134### Select
@@ -195,6 +214,11 @@ MutateMultiGeneDynamic::new(
195214
196215### Extension (Evolve only, all optional)
197216
217+ Extensions should not be needed when hyperparameters are properly tuned. They are
218+ a fallback when the population keeps collapsing to clones despite reasonable
219+ mutation/selection settings. Escalation order: ` MassDegeneration ` (least
220+ disruptive) → ` MassDeduplication ` /` MassExtinction ` → ` MassGenesis ` (last resort).
221+
198222``` rust
199223ExtensionMassExtinction :: new (
200224 cardinality_threshold : usize , // Trigger when unique chromosomes drop below this.
@@ -226,6 +250,7 @@ ExtensionMassDeduplication::new(
226250Required:
227251- ` .with_genotype(genotype) ` — the search space
228252- ` .with_fitness(fitness) ` — the evaluation function
253+ - ` .with_target_population_size(n) ` — number of chromosomes (** defaults to 0, always set this** )
229254- ` .with_select(select) ` — parent selection strategy
230255- ` .with_crossover(crossover) ` — how parents combine
231256- ` .with_mutate(mutate) ` — how offspring are varied
@@ -237,7 +262,6 @@ Ending conditions (at least one required):
237262- ` .with_max_generations(n) ` — stop after n total generations
238263
239264Optional:
240- - ` .with_target_population_size(n) ` — number of chromosomes (default: 0, must set)
241265- ` .with_fitness_ordering(FitnessOrdering::Minimize) ` — default is Maximize
242266- ` .with_par_fitness(true) ` — parallelize fitness calculation
243267- ` .with_fitness_cache(size) ` — LRU cache for expensive fitness
@@ -256,7 +280,9 @@ Required:
256280- At least ONE ending condition
257281
258282Optional:
259- - ` .with_variant(HillClimbVariant::SteepestAscent) ` — default is Stochastic
283+ - ` .with_variant(HillClimbVariant::SteepestAscent) ` — default is Stochastic.
284+ Stochastic: fast, one random neighbor per generation, good for large genomes.
285+ SteepestAscent: evaluates all neighbors, finds best improvement, slow for large genomes.
260286- ` .with_fitness_ordering(FitnessOrdering::Minimize) ` — default is Maximize
261287- ` .with_par_fitness(true) ` — parallelize fitness calculation
262288- ` .with_fitness_cache(size) ` — LRU cache for expensive fitness
@@ -319,6 +345,30 @@ let (best, _all_runs) = Evolve::builder()
319345 . unwrap ();
320346```
321347
348+ Both ` .call() ` and ` .build() ` return ` Result<_, TryFromEvolveBuilderError> ` .
349+ Builder validation catches: missing required fields, incompatible genotype +
350+ crossover combinations, and missing ending conditions. The error message includes
351+ an actionable fix suggestion.
352+
353+ ### Common mistakes
354+
355+ ``` rust
356+ // WRONG: UniqueGenotype + CrossoverUniform = RUNTIME PANIC
357+ // FIX: Use CrossoverClone or CrossoverRejuvenate
358+
359+ // WRONG: No ending condition = COMPILE/BUILD ERROR
360+ // FIX: Add .with_max_stale_generations(1000)
361+
362+ // WRONG: target_population_size not set (defaults to 0) = SILENT FAILURE
363+ // FIX: Add .with_target_population_size(100)
364+
365+ // WRONG: Fitness returns f64 = TYPE ERROR
366+ // FIX: Return Some((score / precision) as FitnessValue)
367+
368+ // WRONG: MutateSingleGene(0.2) with 1000+ float genes = DIVERSITY COLLAPSE
369+ // FIX: Use MutateMultiGene with higher mutation count, see Troubleshooting
370+ ```
371+
322372HillClimb also supports ` .call_repeatedly(n) ` and ` .call_par_repeatedly(n) ` .
323373
324374## Retrieving Results
@@ -364,35 +414,49 @@ For simple fitness functions, just ignore the mutability. When using
364414
365415## Copy-Paste Templates
366416
367- ### Binary Optimization (Knapsack-style )
417+ ### Binary Optimization (Knapsack)
368418
369419``` rust
370420use genetic_algorithm :: strategy :: evolve :: prelude :: * ;
371421
422+ const ITEMS : [(isize , isize ); 10 ] = [
423+ // (value, weight)
424+ (60 , 10 ), (100 , 20 ), (120 , 30 ), (80 , 15 ), (50 , 10 ),
425+ (90 , 25 ), (70 , 18 ), (40 , 8 ), (110 , 22 ), (65 , 12 ),
426+ ];
427+ const MAX_WEIGHT : isize = 80 ;
428+
372429#[derive(Clone , Debug )]
373- struct MyFitness ;
374- impl Fitness for MyFitness {
430+ struct KnapsackFitness ;
431+ impl Fitness for KnapsackFitness {
375432 type Genotype = BinaryGenotype ;
376433 fn calculate_for_chromosome (
377434 & mut self ,
378435 chromosome : & FitnessChromosome <Self >,
379436 _genotype : & FitnessGenotype <Self >,
380437 ) -> Option <FitnessValue > {
381- Some (chromosome . genes. iter (). filter (|&& v | v ). count () as FitnessValue )
438+ let (total_value , total_weight ) = chromosome . genes. iter (). enumerate ()
439+ . filter (| (_ , & included )| included )
440+ . fold ((0 , 0 ), | (v , w ), (i , _ )| (v + ITEMS [i ]. 0 , w + ITEMS [i ]. 1 ));
441+ if total_weight > MAX_WEIGHT {
442+ Some (total_value - (total_weight - MAX_WEIGHT ) * 10 ) // penalty
443+ } else {
444+ Some (total_value )
445+ }
382446 }
383447}
384448
385449fn main () {
386450 let genotype = BinaryGenotype :: builder ()
387- . with_genes_size (100 )
451+ . with_genes_size (ITEMS . len () )
388452 . build ()
389453 . unwrap ();
390454
391455 let evolve = Evolve :: builder ()
392456 . with_genotype (genotype )
393457 . with_target_population_size (100 )
394458 . with_max_stale_generations (100 )
395- . with_fitness (MyFitness )
459+ . with_fitness (KnapsackFitness )
396460 . with_select (SelectTournament :: new (0.5 , 0.02 , 4 ))
397461 . with_crossover (CrossoverUniform :: new (0.7 , 0.8 ))
398462 . with_mutate (MutateSingleGene :: new (0.2 ))
0 commit comments