Expand description
§evolve
A generic, composable genetic algorithm framework for Rust.
evolve provides the building blocks to assemble genetic algorithms from reusable,
type-safe components. Operators are composed using combinators — chain them into
pipelines, weight them probabilistically, or repeat them to fill a population —
all with zero-cost abstractions.
§Features
- Fully generic over genome type, fitness type, RNG, and fitness comparator
- Built-in operators for selection, crossover, and mutation
- Composable combinators for structuring the flow of the algorithm
MaximizeandMinimizefitness comparators out of the box- Closures work as fitness evaluators and comparators via blanket trait impls
Collectortrait for customizable run results (timing, fitness history, or your own)Experimentrunner for batch trials with configurable collectors- No dependencies beyond
rand(optionalpooledfor parallel execution)
§Quick Start
The simplest way to get started is to use Random initialization,
a MaxGenerations termination condition, and
Fill with a mutation operator:
use evolve::{
algorithm::EvolutionaryAlgorithm,
fitness::Maximize,
initialization::Random,
operators::sequential::combinator::Fill,
operators::sequential::mutation::RandomReset,
termination::MaxGenerations,
};
use std::num::NonZero;
let mut ga = EvolutionaryAlgorithm::new(
Random::new(),
MaxGenerations::new(100),
|args: &[u32; 2]| args[0] as usize + args[1] as usize,
Fill::from_population_size(RandomReset::new()),
NonZero::new(500).unwrap(),
rand::rng(),
Maximize,
);
let result = ga.run();
let fe = |args: &[u32; 2]| args[0] as usize + args[1] as usize;
let best = result.population().best(&fe, &Maximize);
println!("Best genome: {:?}, fitness: {:?}", best.genome(), best.fitness(&fe));§Composing Operators
The real power of evolve comes from composing operators using combinators.
A typical genetic algorithm pipeline selects parents, crosses them over, and
mutates the offspring:
use evolve::{
algorithm::EvolutionaryAlgorithm,
fitness::Maximize,
initialization::Random,
operators::sequential::combinator::{Combine, Fill, Pipeline},
operators::sequential::crossover::SinglePoint,
operators::sequential::mutation::RandomReset,
operators::sequential::selection::Tournament,
termination::MaxGenerations,
};
use std::num::NonZero;
// Select two parents → crossover → mutate, repeated until the population is full
let operators = Fill::from_population_size(Pipeline::new((
Combine::new((
Tournament::new(NonZero::new(3).unwrap()),
Tournament::new(NonZero::new(3).unwrap()),
)),
SinglePoint::new(),
RandomReset::new(),
)));
let mut ga = EvolutionaryAlgorithm::new(
Random::new(),
MaxGenerations::new(200),
|g: &[u8; 8]| g.iter().map(|x| *x as u32).sum::<u32>(),
operators,
NonZero::new(100).unwrap(),
rand::rng(),
Maximize,
);
let result = ga.run();§Weighted Operator Selection
Use Weighted to probabilistically choose
between different operators each time:
use evolve::operators::sequential::combinator::{Fill, Weighted};
use evolve::operators::sequential::mutation::RandomReset;
use evolve::operators::sequential::crossover::SinglePoint;
use std::num::NonZero;
// 75% chance of mutation, 25% chance of crossover
let operators = Fill::from_population_size(Weighted::new((
(RandomReset::<u8>::new(), NonZero::new(3u16).unwrap()),
(SinglePoint::<u8>::new(), NonZero::new(1u16).unwrap()),
)));§Custom Fitness
Any closure Fn(&G) -> F works as a FitnessEvaluator,
and any closure Fn(&F, &F) -> bool works as a FitnessComparator:
use evolve::{
algorithm::EvolutionaryAlgorithm,
initialization::Random,
operators::sequential::combinator::Fill,
operators::sequential::mutation::RandomReset,
termination::MaxGenerations,
};
use std::num::NonZero;
// Custom comparator: prefer fitness values closer to 100
let mut ga = EvolutionaryAlgorithm::new(
Random::new(),
MaxGenerations::new(100),
|g: &[u8; 2]| (g[0] as i32 + g[1] as i32 - 100).abs(),
Fill::from_population_size(RandomReset::new()),
NonZero::new(200).unwrap(),
rand::rng(),
|a: &i32, b: &i32| a < b, // lower distance is better
);
let result = ga.run();§Custom Operators
Implement GeneticOperator to define your own:
use evolve::{
core::{context::Context, offspring::Offspring, state::State},
operators::GeneticOperator,
};
struct MyOperator;
impl<G, F, Fe, R, C> GeneticOperator<G, F, Fe, R, C> for MyOperator {
fn apply(&self, state: &State<G, F>, ctx: &mut Context<Fe, R, C>) -> Offspring<G, F> {
todo!()
}
}§Parallel Execution
Enable the parallel feature to distribute operator work across multiple threads.
This adds an optional dependency on pooled.
[dependencies]
evolve = { version = "0.1.0", features = ["parallel"] }Parallel versions of mutation, crossover, and combinators are available under
operators::parallel (requires the parallel feature).
§Grammatical Evolution
The crate supports Grammatical Evolution (GE) via the grammar and phenotype modules.
GE evolves variable-length integer codon sequences (Vec<u8>) that are mapped through a
context-free grammar to produce executable programs.
Grammar<T>provides runtime grammar construction, or use thegrammar!proc-macro fromevolve-derivefor zero-cost compile-time grammars.GeFitnesswraps the codon→phenotype→fitness pipeline automatically, handling grammar mapping and builder invocation.Bytecode<T>and theInstructiontrait provide a built-in stack-machine execution engine for evolved programs.- Variable-length genome operators are included:
RangedRandomfor initialization,SegmentDuplicationandSegmentDeletionfor structural mutation.
Modules§
- algorithm
- Algorithm runners.
- collector
- Collectors for gathering results from algorithm runs.
- core
- Core types that make up the genetic algorithm.
- experiment
- Experiment runner for executing multiple independent trials.
- fitness
- Fitness evaluation and comparison.
- grammar
- Grammar representation and builder for grammatical evolution.
- initialization
- Population initialization strategies.
- operators
- Genetic operators.
- phenotype
- Phenotype building during grammar mapping.
- random
- Random value generation for genomes and genes.
- termination
- Termination conditions for the algorithm.
Macros§
- grammar
- Generates a zero-cost grammar with compile-time dispatch.