GithubHelp home page GithubHelp logo

genetic-rs's Introduction

genetic-rs

github crates.io docs.rs

A small crate for quickstarting genetic algorithm projects.

How to Use

note: if you are interested in implementing NEAT with this, try out the neat crate

Features

First off, this crate comes with the builtin and genrand features by default. If you want to add the builtin crossover reproduction extension, you can do so by adding the crossover feature. If you want it to be parallelized, you can add the rayon feature. If you want your crossover to be speciated, you can add the speciation feature.

Once you have eveything imported as you wish, you can define your genome and impl the required traits:

#[derive(Clone, Debug)] // clone is currently a required derive for pruning nextgens.
struct MyGenome {
    field1: f32,
}

// required in all of the builtin functions as requirements of `DivsionReproduction` and `CrossoverReproduction`
impl RandomlyMutable for MyGenome {
    fn mutate(&mut self, rate: f32, rng: &mut impl rand::Rng) {
        self.field1 += rng.gen::<f32>() * rate;
    }
}

// required for `division_pruning_nextgen`.
impl DivsionReproduction for MyGenome {
    fn divide(&self, rng: &mut impl rand::Rng) -> Self {
        let mut child = self.clone();
        child.mutate(0.25, rng); // use a constant mutation rate when spawning children in pruning algorithms.
        child
    }
}

// required for the builtin pruning algorithms.
impl Prunable for MyGenome {
    fn despawn(self) {
        // unneccessary to implement this function, but it can be useful for debugging and cleaning up genomes.
        println!("{:?} died", self);
    }
}

// helper trait that allows us to use `Vec::gen_random` for the initial population.
impl GenerateRandom for MyGenome {
    fn gen_random(rng: &mut impl rand::Rng) -> Self {
        Self { field1: rng.gen() }
    }
}

Once you have a struct, you must create your fitness function:

fn my_fitness_fn(ent: &MyGenome) -> f32 {
    // this just means that the algorithm will try to create as big a number as possible due to fitness being directly taken from the field.
    // in a more complex genetic algorithm, you will want to utilize `ent` to test them and generate a reward.
    ent.field1
}

Once you have your reward function, you can create a GeneticSim object to manage and control the evolutionary steps:

fn main() {
    let mut rng = rand::thread_rng();
    let mut sim = GeneticSim::new(
        // you must provide a random starting population. 
        // size will be preserved in builtin nextgen fns, but it is not required to keep a constant size if you were to build your own nextgen function.
        // in this case, you do not need to specify a type for `Vec::gen_random` because of the input of `my_fitness_fn`.
        Vec::gen_random(&mut rng, 100),
        my_fitness_fn,
        division_pruning_nextgen,
    );
 
    // perform evolution (100 gens)
    for _ in 0..100 {
        sim.next_generation(); // in a genetic algorithm with state, such as a physics simulation, you'd want to do things with `sim.genomes` in between these calls
    }
 
    dbg!(sim.genomes);
}

That is the minimal code for a working pruning-based genetic algorithm. You can read the docs or check the examples for more complicated systems.

License

This project falls under the MIT license.

genetic-rs's People

Contributors

hypercodec avatar

Stargazers

 avatar

Watchers

 avatar

genetic-rs's Issues

Multithreading support

It is currently extremely difficult to pass GeneticSim between threads because it has Box<dyn Fn>. It should be changed to be threadsafe.

need better testing workflow

This current CI-CD does not test all features, so they keep breaking while rust-analyzer does not check them.

Rayon feature doesn't work

Compile errors when the rayon feature is included. Also, it is a good time to fix CI/CD and tests so that they can use features.

[TODO] Derive macros

Types that are composed of other types with reproductive traits can use derive

Ambiguous `spawn_child` function name

For cases where something may implement both DivisionReproduction and CrossoverReproduction, the user needs to manually disambiguate. It would be much easier to simply call them divide and crossover respectively.

Outdated documentation on built-in things

Some things still stay stuff about const generics and stuff, which is not really the reason extra features were cancelled anymore (especially now that those features are possible).

make README badges clickable

Currently, clicking the badges just takes the user to a new page with the image. Instead, maybe use a hyperlink to make it redirect to the actual page of the badge.

change lib.rs documentation

it should not just mimic the README, causes errors when mimicking changes between the two and is just an excuse to not write proper documentation for the crate.

Rename traits?

They aren't specifically functions anymore, so they probably shouldn't be ending with Fn. (although fitness might be able to stay the same, nextgenfn should probably change)

`neat` crate notice?

It might be useful to promote the neat crate so that people who find this crate don't need to implement their own NEAT algorithm just because they happened to not notice the other crate.

Plus it just gets more downloads on the neat crate.

Change entity terminology?

To avoid users making mistakes and thinking they should use their state-filled entities in the GeneticSim, all the docs and params referencing entities to be changed to something pertaining more to hereditary data terminology.

Potential nextgen layering support

I made a plotters nextgen in my neat crate example that would run another nextgen once it was done collecting the diagnostic data. It would be very nice if this could become a builtin feature or trait (maybe even with tuple layering support).

Macros might use imports that don't exist

Simply have to specify what's being imported in the final quote or use full path. Not an extremely urgent issue because everything is exported in prelude::* but will probably put in the next patch.

Non-owned example

Extension of #1, but essentially should do an example that uses builtin without the use of GeneticSim for an easier form of managing fitness in complex simulations.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.