symbios-genetics 0.1.3

Sovereign biology engine for Quality-Diversity and Multi-Objective evolution.
Documentation

symbios-genetics

A battle-hardened evolutionary computation engine for Rust.

symbios-genetics is a trait-based library designed for Morphogenetic Engineering, Artificial Life, and Creative AI. Unlike general-purpose genetic libraries, it prioritizes correctness, reproducibility, and serialization above all else.

Algorithms

The library implements three distinct evolutionary strategies covering the spectrum of optimization needs:

Algorithm Type Best Use Case
SimpleGA Single-Objective Converging on a specific optimal solution (e.g., maximizing speed). Features Elitism and Tournament Selection.
NSGA-II Multi-Objective Finding the Pareto Front of trade-offs between conflicting goals (e.g., maximize strength AND minimize weight).
MAP-Elites Quality-Diversity Illuminating the search space. Finds the best solution for every possible niche (e.g., "fastest robot for every possible height").

Quick Start

Add to your Cargo.toml:

[dependencies]
symbios-genetics = "0.1.0"
serde = { version = "1.0", features = ["derive"] }
rand = "0.9"

Defining a Genome

Implement the Genotype trait for your data structure.

use rand::Rng;
use serde::{Deserialize, Serialize};
use symbios_genetics::Genotype;

#[derive(Clone, Serialize, Deserialize, Debug)]
struct MyDNA {
    value: f32,
}

impl Genotype for MyDNA {
    fn mutate<R: Rng>(&mut self, rng: &mut R, rate: f32) {
        if rng.random::<f32>() < rate {
            self.value += rng.random_range(-0.1..0.1);
        }
    }

    fn crossover<R: Rng>(&self, other: &Self, _rng: &mut R) -> Self {
        MyDNA {
            value: (self.value + other.value) / 2.0,
        }
    }
}

Defining an Evaluator

Implement Evaluator to bridge your genome to the engine. Returns a tuple of (Fitness, Objectives, Descriptor).

use symbios_genetics::Evaluator;

struct MyEvaluator;

impl Evaluator<MyDNA> for MyEvaluator {
    fn evaluate(&self, dna: &MyDNA) -> (f32, Vec<f32>, Vec<f32>) {
        // 1. Fitness (Scalar): Used by SimpleGA
        let fitness = -(dna.value - 42.0).abs(); 
        
        // 2. Objectives (Vector): Used by NSGA-II
        let objectives = vec![fitness, -dna.value]; 
        
        // 3. Descriptor (Vector): Used by MAP-Elites (Normalized 0.0-1.0)
        let descriptor = vec![dna.value.clamp(0.0, 100.0) / 100.0];
        
        (fitness, objectives, descriptor)
    }
}

Running Evolution

use symbios_genetics::{
    algorithms::simple::SimpleGA,
    Evolver,
};

fn main() {
    // 1. Initialize
    let initial_pop = (0..100).map(|_| MyDNA { value: 0.0 }).collect();
    
    // 2. Configure Engine (Pop, Mutation Rate, Elitism, Seed)
    let mut engine = SimpleGA::new(initial_pop, 0.1, 5, 12345);
    let evaluator = MyEvaluator;

    // 3. Evolve
    for _ in 0..100 {
        engine.step(&evaluator);
    }

    // 4. Inspect
    let best = &engine.population()[0];
    println!("Best DNA: {:?} (Fitness: {})", best.genotype, best.fitness);
}

Architecture

The Evolver Trait

All algorithms implement the Evolver<G> trait. This allows you to write simulation harnesses (e.g., a Bevy plugin) that are agnostic to the specific evolutionary strategy. You can hot-swap SimpleGA for MapElites without rewriting your game loop.

Parallelism

To enable parallel evaluation, ensure the parallel feature is enabled (default) and your Evaluator implements Send + Sync. The engine automatically dispatches evaluation tasks via rayon::par_iter.

symbios-genetics = { version = "0.1.0", features = ["parallel"] }

License

This project is licensed under the MIT License - see the LICENSE file for details.