Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

258 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

neat

github crates.io docs.rs

Implementation of the NEAT algorithm using genetic-rs.

Features

  • serde - Implements Serialize and Deserialize on most of the types in this crate.

Do you like this crate and want to support it? If so, leave a ⭐

How To Use

The NeuralNetwork<I, O> struct is the main type exported by this crate. The I is the number of input neurons, and O is the number of output neurons. It implements GenerateRandom, RandomlyMutable, Mitosis, and Crossover, with a lot of customizability. This means that you can use it standalone as your organism's entire genome:

use neat::*;

fn fitness(net: &NeuralNetwork<5, 6>) -> f32 {
    // ideally you'd test multiple times for consistency,
    // but this is just a simple example.
    // it's also generally good practice to normalize your inputs between -1..1,
    // but NEAT is usually flexible enough to still work anyways
    let inputs = [1.0, 2.0, 3.0, 4.0, 5.0];
    let outputs = net.predict(inputs);

    // simple fitness: sum of outputs
    // you should replace this with a real fitness test
    outputs.iter().sum()
}

fn main() {
    let mut rng = rand::rng();
    let mut sim = GeneticSim::new(
        Vec::gen_random(&mut rng, 100),
        FitnessEliminator::new_without_observer(fitness),
        CrossoverRepopulator::new(0.25, ReproductionSettings::default()),
    );

    sim.perform_generations(100);
}

Or just a part of a more complex genome:

use neat::*;

#[derive(Clone, Debug)]
struct PhysicalStats {
    strength: f32,
    speed: f32,
    // ...
}

// ... implement `RandomlyMutable`, `GenerateRandom`, `Crossover`, `Default`, etc.

#[derive(Clone, Debug, GenerateRandom, RandomlyMutable, Mitosis, Crossover)]
#[randmut(create_context(name = MyGenomeMutate, derive(Default, Clone, Debug)))]
#[mitosis(create_context(name = MyGenomeReproduce, derive(Default, Clone, Debug)))]
#[crossover(with_context = MyGenomeReproduce)]
struct MyGenome {
    brain: NeuralNetwork<4, 2>,
    stats: PhysicalStats,
}

fn fitness(genome: &MyGenome) -> f32 {
    let inputs = [1.0, 2.0, 3.0, 4.0];
    let outputs = genome.brain.predict(inputs);
    // fitness uses both brain output and stats
    outputs.iter().sum::<f32>() + genome.stats.strength + genome.stats.speed
}

// main is the exact same as before
fn main() {
    let mut rng = rand::rng();
    let mut sim = GeneticSim::new(
        Vec::gen_random(&mut rng, 100),
        FitnessEliminator::new_without_observer(fitness),
        CrossoverRepopulator::new(0.25, MyGenomeReproduce::default()),
    );

    sim.perform_generations(100);
}

If you want more in-depth examples, look at the examples. You can also check out the genetic-rs docs to see what other options you have to customize your genetic simulation.

License

This crate falls under the MIT license

About

A crate implementing NeuroEvolution of Augmenting Topologies

Resources

Contributing

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages