genetic_algorithms 2.1.0

Library for solving genetic algorithm problems
Documentation

genetic_algorithms (v2.1.0)

Rust Unit Tests

Modular and concurrent Genetic Algorithms (GA) library for Rust featuring:

  • Clear abstractions (traits for genes, chromosomes, and configuration).
  • Composable operators (selection, crossover, mutation, survivor, extension).
  • Multi-threaded execution via rayon (fitness evaluation, reproduction, mutation in parallel).
  • Adaptive GA mode (dynamic crossover and mutation probabilities based on population performance).
  • Elitism support (preserve top N individuals across generations).
  • Extension strategies for population diversity control (mass extinction, genesis, degeneration, deduplication).
  • Population diversity metric tracked per generation.
  • Lifecycle reporter hooks (on_start, on_generation_complete, on_new_best, on_finish).
  • Compound stopping criteria (stagnation, convergence, time limit).
  • Cow for minimizing unnecessary DNA copies.
  • Optional visualization feature for PNG/SVG fitness and diversity charts.

Table of Contents

Documentation

Latest published docs: docs.rs/genetic_algorithms

Status & Key Changes 2.0.0

Main differences vs 1.x:

  • Crate version: 2.0.0 (update your Cargo.toml).
  • Structured error handling: all operators return Result<T, GaError> instead of panicking.
  • Parallelism via rayon replacing manual thread management.
  • GeneT::get_id() now returns i32 directly.
  • ChromosomeT::set_dna now uses Cow<'a, [Gene]> to avoid redundant copies.
  • Added Range<T> genotype alongside Binary (supports numeric ranges).
  • New operators: SinglePoint, Order (OX), BitFlip, Value, Creep, Gaussian mutations; SBX, BlendAlpha crossovers; Rank selection.
  • Elitism: with_elitism(n) preserves the top N individuals across generations.
  • Compound stopping criteria: stagnation detection, convergence threshold, time limit.
  • Per-generation statistics tracking via GenerationStats.
  • Adaptive probability helpers: aga_probability for crossover & mutation.
  • Expanded configuration: FixedFitness, logging levels (Off..Trace), configurable threads.
  • Internal benchmarks use Criterion 0.7 (pprof integration removed due to version conflict).

Features

Traits

  • GeneT:
    • Requires: Default + Clone + Send + Sync.
    • Key methods: new(), get_id() -> i32, set_id(i32).
  • ChromosomeT:
    • Associated: type Gene: GeneT.
    • Supports: get_dna(), set_dna(Cow<[Gene]>), set_gene(idx, gene), set_fitness_fn(...), calculate_fitness(), get_fitness(), set_fitness(f64), get_age(), set_age(i32).
    • Derived metric: get_fitness_distance(&fitness_target).
  • ConfigurationT: builder-style API for Ga / GaConfiguration.

Included Genotypes & Chromosomes

  • genotypes::Binary (boolean gene).
  • genotypes::Range<T> (values constrained to one or more (min,max) intervals).
  • genotypes::List<T> (values drawn from a finite symbolic alphabet).
  • chromosomes::Range<T> (chromosome built from Range<T> genes).
  • chromosomes::ListChromosome<T> (chromosome built from List<T> genes).
  • (Custom chromosomes can be added by implementing ChromosomeT).

Initializers

  • initializers::binary_random_initialization.
  • initializers::range_random_initialization.
  • initializers::list_random_initialization (for List<T> chromosomes, with repetition).
  • initializers::list_random_initialization_without_repetitions (permutation problems).
  • initializers::generic_random_initialization (takes allele slice, optional unique IDs).
  • initializers::generic_random_initialization_without_repetitions (no allele repetition).

Operators

  • Selection: Random, RouletteWheel, StochasticUniversalSampling, Tournament, Rank.
  • Crossover: Cycle, MultiPoint, Uniform, SinglePoint, Order (OX), Sbx (Simulated Binary), BlendAlpha (BLX-α).
  • Mutation: Swap, Inversion, Scramble, Value (Range), BitFlip (Binary), Creep (uniform perturbation), Gaussian (normal perturbation), ListValue (List).
  • Survivor: Fitness (keep best), Age (prefer younger / age-based pruning).
  • Extension: Noop, MassExtinction, MassGenesis, MassDegeneration, MassDeduplication.

Reporter

Attach a lifecycle observer to Ga via .with_reporter(Box::new(r)). Four hooks: on_start, on_generation_complete, on_new_best, on_finish. Zero overhead when no reporter is configured (stored as Option).

Built-in reporters:

  • reporter::NoopReporter — default, no-op.
  • reporter::SimpleReporter::new(n) — prints a progress line every N generations.
  • reporter::DurationReporter::new() — reports total elapsed time and per-generation average at finish.

Implement Reporter<U> to build custom observers.

Visualization

Optional feature flag. Add to Cargo.toml:

genetic_algorithms = { version = "2.1.0", features = ["visualization"] }

Three functions in genetic_algorithms::visualization:

// Fitness over generations (best, average, worst lines)
visualization::plot_fitness(&stats, "fitness.png")?;
visualization::plot_fitness(&stats, "fitness.svg")?;

// Diversity over generations
visualization::plot_diversity(&stats, "diversity.png")?;

// Fitness distribution for a generation (raw fitness values)
let fitness: Vec<f64> = population.iter().map(|c| c.fitness()).collect();
visualization::plot_histogram(&fitness, "distribution.png")?;

Format is determined by path extension (.png or .svg). All functions return Result<(), VisualizationError>.

GA Configuration

GaConfiguration (or the Ga builder) exposes:

  • Limits: problem_solving (Minimization | Maximization | FixedFitness), max_generations, fitness_target, population_size, genes_per_chromosome, needs_unique_ids, alleles_can_be_repeated.
  • Selection: number_of_couples, method.
  • Crossover: number_of_points (MultiPoint), probability_min / probability_max, method, sbx_eta (SBX distribution index), blend_alpha (BLX-α alpha parameter).
  • Mutation: probability_min / probability_max, method, step (Creep step size), sigma (Gaussian standard deviation).
  • Survivor: survivor.
  • Elitism: elitism_count — preserve the top N individuals unchanged across generations.
  • Extension: extension_configuration — optional diversity control strategies. Configure with with_extension_method(), with_extension_diversity_threshold(), with_extension_survival_rate(), with_extension_mutation_rounds(), with_extension_elite_count().
  • Stopping criteria: StoppingCriteria with stagnation_generations, convergence_threshold, max_duration_secs. The GA stops when any enabled criterion is met.
  • Infra: adaptive_ga, number_of_threads, log_level.
  • Progress (present but not yet wired): save_progress_configuration (future/experimental).

Adaptive GA

When adaptive_ga = true:

  • Crossover & mutation probabilities are recomputed per parent pair using relative fitness (f_max, f_avg).
  • You must set both probability_min and probability_max for crossover and mutation. When adaptive_ga = false:
  • If probability_max is absent, defaults to 1.0 (operator always applied).

Multithreading & Performance

  • with_threads(n) configures parallelism (internally uses rayon).
  • Selection, crossover, mutation, and fitness evaluation are parallelized each generation.
  • Cow prevents needless cloning of DNA vectors.

Quick Example

Minimal GA using Range<i32> chromosomes targeting fitness 0 (minimization):

use genetic_algorithms::ga::Ga;
use genetic_algorithms::traits::ConfigurationT;
use genetic_algorithms::configuration::ProblemSolving;
use genetic_algorithms::operations::{Selection, Crossover, Mutation, Survivor};
use genetic_algorithms::genotypes::Range as RangeGene;
use genetic_algorithms::initializers::range_random_initialization;
use genetic_algorithms::chromosomes::Range as RangeChromosome; // Chromosome type

fn fitness_fn(dna: &[RangeGene<i32>]) -> f64 { // Replace with domain logic
    dna.iter().map(|g| g.get_value() as f64).sum() // Simple example
}

let alleles = vec![RangeGene::new(0, vec![(0, 7)], 0)];
let alleles_clone = alleles.clone();
let mut ga = Ga::<RangeChromosome<i32>>::new();
let _population = ga
    .with_genes_per_chromosome(8)
    .with_population_size(100)
    .with_initialization_fn(move |genes, _, _| {
        range_random_initialization(genes, Some(&alleles_clone), Some(false))
    })
    .with_fitness_fn(fitness_fn)
    .with_selection_method(Selection::Tournament)
    .with_crossover_method(Crossover::Uniform)
    .with_mutation_method(Mutation::Swap)
    .with_survivor_method(Survivor::Fitness)
    .with_problem_solving(ProblemSolving::Minimization)
    .with_max_generations(500)
    .with_fitness_target(0.0)
    .with_threads(4)
    .run();

Full Example (Range)

Includes adaptive GA and probabilities:

use genetic_algorithms::{ga::Ga, traits::ConfigurationT};
use genetic_algorithms::configuration::ProblemSolving;
use genetic_algorithms::operations::{Selection, Crossover, Mutation, Survivor};
use genetic_algorithms::genotypes::Range as RangeGene;
use genetic_algorithms::chromosomes::Range as RangeChromosome;
use genetic_algorithms::initializers::range_random_initialization;

fn fitness_fn(dna: &[RangeGene<i32>]) -> f64 {
    // Penalize greater values: minimization goal
    dna.iter().map(|g| g.get_value() as f64).sum()
}

let alleles = vec![RangeGene::new(0, vec![(0, 50)], 0)];
let alleles_clone = alleles.clone();
let mut ga = Ga::<RangeChromosome<i32>>::new();
let population = ga
    .with_adaptive_ga(true)
    .with_genes_per_chromosome(16)
    .with_population_size(200)
    .with_initialization_fn(move |genes, _, _| {
        range_random_initialization(genes, Some(&alleles_clone), Some(false))
    })
    .with_fitness_fn(fitness_fn)
    .with_selection_method(Selection::StochasticUniversalSampling)
    .with_crossover_method(Crossover::MultiPoint)
    .with_crossover_number_of_points(3)
    .with_crossover_probability_min(0.4)
    .with_crossover_probability_max(0.9)
    .with_mutation_method(Mutation::Inversion)
    .with_mutation_probability_min(0.05)
    .with_mutation_probability_max(0.3)
    .with_survivor_method(Survivor::Fitness)
    .with_problem_solving(ProblemSolving::Minimization)
    .with_max_generations(2000)
    .with_fitness_target(0.0)
    .with_threads(8)
    .with_logs(genetic_algorithms::configuration::LogLevel::Info)
    .run();

println!("Best fitness: {}", population.unwrap().best_chromosome.get_fitness());

Examples

Run any example directly with cargo run:

Example Domain Command
rastrigin Continuous optimization cargo run --example rastrigin
nsga2_zdt1 Multi-objective (NSGA-II) cargo run --example nsga2_zdt1
island_model Parallel / island model cargo run --example island_model
job_scheduling Permutation / scheduling cargo run --example job_scheduling
feature_selection Binary / adaptive GA cargo run --example feature_selection
niching Multimodal / niching cargo run --example niching
knapsack_binary Binary / combinatorial cargo run --example knapsack_binary
nqueens_range Constraint satisfaction cargo run --example nqueens_range
onemax_binary Binary / baseline cargo run --example onemax_binary
onemax_extension Binary / diversity control cargo run --example onemax_extension

Usage

Add to your Cargo.toml:

[dependencies]
genetic_algorithms = "2.1.0"

# Optional: enable PNG/SVG chart generation
# genetic_algorithms = { version = "2.1.0", features = ["visualization"] }

Development

Build

cargo build            # Debug build
cargo build --release  # Optimized release build

Run Tests

cargo test                              # Run all tests
cargo test --features serde             # Include serde tests
cargo test --features visualization     # Include visualization tests
cargo test -- --nocapture               # With visible stdout/stderr

Run Benchmarks

Benchmarks use Criterion and are located in benches/.

cargo bench                       # Run all benchmarks
cargo bench --bench crossover     # Run only crossover benchmarks
cargo bench --bench mutation      # Run only mutation benchmarks
cargo bench --bench selection     # Run only selection benchmarks
cargo bench --bench survivor      # Run only survivor benchmarks
cargo bench --no-run              # Only compile benchmarks (useful for CI)

Reports are generated in target/criterion/ and can be viewed in a browser.

Code Quality

cargo fmt --check   # Check formatting (no changes)
cargo fmt           # Auto-format code
cargo clippy        # Run linter

Roadmap / Notes

  • save_progress_configuration: fields present but not wired into the main loop yet (future: periodic population / best chromosome persistence).
  • Optional flamegraph profiling integration removed to avoid Criterion version conflicts.
  • For heavy fitness functions consider external profiling tools.

License

Apache-2.0. See LICENSE file.