Fast, parallel, extensible and adaptable genetic algorithms framework written in Rust

Overview

oxigen

Build Status Current Crates.io Version

Oxigen is a parallel genetic algorithm framework implemented in Rust. The name comes from the merge of OXIdación (Rust translated to Spanish) and GENetic.

The changes introduced in each version can be found in CHANGELOG.md.

To migrate between major version check the migration guide (MIGRATE.md).

Oxigen provides the following features:

  • Fast and parallel genetic algorithm implementation (it solves the N Queens problem for N=255 in few seconds). For benchmarks view benchmarks section of this file.
  • Customizable mutation and selection rates with constant, linear and quadratic functions according to generations built-in (you can implement your own functions via the MutationRate and SelectionRate traits).
  • Customizable age unfitness of individuals, with no unfitness, linear and quadratic unfitness with threshold according to generations of the individual built-in (you can implement your own age functions via the Age trait).
  • Accumulated Roulette, Tournaments and Cup built-in selection functions (you can implement your own selection functions via the Selection trait).
  • SingleCrossPoint, MultiCrossPoint and UniformCross built-in crossover functions (you can implement your own crossover function via the Crossover trait).
  • Many built-in survival pressure functions. You can implement your own survival pressure functions via the SurvivalPressure trait.
  • Niches built-in PopulationRefitness function. You can implement your own population refitness functions via the PopulationRefitness trait.
  • SolutionFound, Generation and Progress and more built-in stop criteria (you can implement your own stop criteria via the StopCriterion trait).
  • Genotype trait to define the genotype of your genetic algorithm. Whatever struct can implement the Genotype trait under the following restrictions:
    • It has a iter function that returns a use std::slice::Iter over its genes.
    • It has a into_iter function that consumes the individual and returns a use std::vec::IntoIter over its genes.
    • It has a from_iter function that set the genes from an iterator.
    • It implements Display, Clone, Send and Sync.
    • It has functions to generate a random individual, to mutate an individual, to get the fitness of an individual and to know if and individual is_solution of the problem.
  • Individual's fitness is cached to not do unnecessary recomputations (this can be disabled with .cache_fitness(false) if your fitness function is stochastic and so you need to recompute fitness in each generation).
  • Progress statistics can be configured to be printed every certain number of generations to a file.
  • Population individuals with their fitnesses can be configured to be printed every certain number of generations to a file.
  • Specific initial individuals can be inserted in the genetic algorithm execution.
  • Genetic executions can be resumed using the population of the last generation as initial population.
  • Coevolution is possible executing little genetic algorithm re-executions inside the fitness function.

Optional feature global_cache

The optional feature global_cache adds a HashMap saving the evaluation of each individual in the full execution.

This cache is useful when the evaluation of each individual is expensive, and it complements the individual-based cache already existing in previous versions (if an individual has been evaluated it is not reevaluated unless cache_fitness is false). In other words, this global cache saves the evaluation of new individuals that are equal to another individual that was evaluated before.

Note that the global cache is not always better, since if the fitness function is cheap the cost of getting and inserting into the cache can be more expensive than it. Take also into account the increase of RAM usage of the global cache.

To enable the global cache add the feature global_cache in the Cargo.toml of your project and set to true the cache_fitness (always true by default) and global_cache (true by default when the global_cache is enabled) properties of your GeneticExecution. Example of Cargo.toml:

[dependencies]
oxigen = { version="2.1", features=["global_cache"] }

Usage

In your Cargo.toml file add the oxigen dependency. Oxigen follows the semver specification for the names of the versions, so major version changes will never break the existent API and the last version should always be used. If a minimum version is required specify that minor version to include that version and all minor versions bigger than it.

[dependencies]
oxigen = "2"

To use oxigen use oxigen::prelude::* and call the run method over a GeneticExecution instance overwriting the default hyperparameters and functions following your needs:

let n_queens: u8 = std::env::args()
    .nth(1)
    .expect("Enter a number between 4 and 255 as argument")
    .parse()
    .expect("Enter a number between 4 and 255 as argument");

let progress_log = File::create("progress.csv").expect("Error creating progress log file");
let population_log = File::create("population.txt").expect("Error creating population log file");
let log2 = (f64::from(n_queens) * 4_f64).log2().ceil();

let population_size = 2_i32.pow(log2 as u32) as usize;

let (solutions, generation, progress) = GeneticExecution::<u8, QueensBoard>::new()
    .population_size(population_size)
    .genotype_size(n_queens as u8)
    .mutation_rate(Box::new(MutationRates::Linear(SlopeParams {
        start: f64::from(n_queens) / (8_f64 + 2_f64 * log2) / 100_f64,
        bound: 0.005,
        coefficient: -0.0002,
    })))
    .selection_rate(Box::new(SelectionRates::Linear(SlopeParams {
        start: log2 - 2_f64,
        bound: log2 / 1.5,
        coefficient: -0.0005,
    })))
    .select_function(Box::new(SelectionFunctions::Cup))
    .age_function(Box::new(AgeFunctions::Quadratic(
        AgeThreshold(50),
        AgeSlope(1_f64),
    )))
    .progress_log(20, progress_log)
    .population_log(2000, population_log)
    .run();

For a full example visit the nqueens-oxigen example.

For more information visit the documentation.

Resuming a previous execution

Since version 1.1.0, genetic algorithm executions return the population of the last generation and new genetic executions accept a initial population. This permits to resume previous executions and it also enables coevolution, since little genetic algorithm re-executions can be launched in the fitness function.

In the following example a execution with 10000 generations is launched and after it is resumed until finding a solution with different rates.

let n_queens: u8 = std::env::args()
    .nth(1)
    .expect("Enter a number between 4 and 255 as argument")
    .parse()
    .expect("Enter a number between 4 and 255 as argument");

let progress_log = File::create("progress.csv").expect("Error creating progress log file");
let population_log = File::create("population.txt").expect("Error creating population log file");
let log2 = (f64::from(n_queens) * 4_f64).log2().ceil();

let population_size = 2_i32.pow(log2 as u32) as usize;

let (_solutions, _generation, _progress, population) = GeneticExecution::<u8, QueensBoard>::new()
    .population_size(population_size)
    .genotype_size(n_queens as u8)
    .mutation_rate(Box::new(MutationRates::Linear(SlopeParams {
        start: f64::from(n_queens) / (8_f64 + 2_f64 * log2) / 100_f64,
        bound: 0.005,
        coefficient: -0.0002,
    })))
    .selection_rate(Box::new(SelectionRates::Linear(SlopeParams {
        start: log2 - 2_f64,
        bound: log2 / 1.5,
        coefficient: -0.0005,
    })))
    .select_function(Box::new(SelectionFunctions::Cup))
    .age_function(Box::new(AgeFunctions::Quadratic(
        AgeThreshold(50),
        AgeSlope(1_f64),
    )))
    .stop_criterion(Box::new(StopCriteria::Generation(10000)))
    .run();

let (solutions, generation, progress, _population) = GeneticExecution::<u8, QueensBoard>::new()
    .population_size(population_size)
    .genotype_size(n_queens as u8)
    .mutation_rate(Box::new(MutationRates::Linear(SlopeParams {
        start: f64::from(n_queens) / (8_f64 + 4_f64 * log2) / 100_f64,
        bound: 0.005,
        coefficient: -0.0002,
    })))
    .selection_rate(Box::new(SelectionRates::Linear(SlopeParams {
        start: log2 - 4_f64,
        bound: log2 / 1.5,
        coefficient: -0.0005,
    })))
    .select_function(Box::new(SelectionFunctions::Cup))
    .age_function(Box::new(AgeFunctions::Quadratic(
        AgeThreshold(50),
        AgeSlope(1_f64),
    )))
    .population(population)
    .progress_log(20, progress_log)
    .population_log(2000, population_log)
    .run();

Building

To build oxigen, use cargo like for any Rust project:

  • cargo build to build in debug mode.
  • cargo build --release to build with optimizations.

Due to a bug in cargo workspaces with optional features errors appear building from the root folder (see #12, #19), but building inside each project works flawlessly.

To run benchmarks, you will need a nightly Rust compiler. Uncomment the lines // #![feature(test)] and // mod benchmarks; from lib.rs and then benchmarks can be run using cargo bench --jobs 1 --all-features.

Benchmarks

The following benchmarks have been created to measure the genetic algorithm functions performance:

running 29 tests
test benchmarks::bench_cross_multi_point_255inds                                                           ... bench:     895,332 ns/iter (+/- 34,409)
test benchmarks::bench_cross_single_point_255inds                                                          ... bench:     227,517 ns/iter (+/- 4,802)
test benchmarks::bench_cross_uniform_255inds                                                               ... bench:     304,957 ns/iter (+/- 9,421)
test benchmarks::bench_distance_255                                                                        ... bench:      41,669 ns/iter (+/- 45)
test benchmarks::bench_fitness_1024inds                                                                    ... bench:      14,260 ns/iter (+/- 3,789)
test benchmarks::bench_fitness_age_1024inds                                                                ... bench:      32,495 ns/iter (+/- 5,705)
test benchmarks::bench_fitness_age_not_cached_1024inds                                                     ... bench:     581,263 ns/iter (+/- 3,988)
test benchmarks::bench_fitness_global_cache_1024inds                                                       ... bench:     343,314 ns/iter (+/- 25,763)
test benchmarks::bench_fitness_not_cached_1024inds                                                         ... bench:     554,870 ns/iter (+/- 32,916)
test benchmarks::bench_generation_run_tournaments_1024inds                                                 ... bench:   4,202,844 ns/iter (+/- 111,604)
test benchmarks::bench_get_fitnesses_1024inds                                                              ... bench:         777 ns/iter (+/- 17)
test benchmarks::bench_get_solutions_1024inds                                                              ... bench:       2,126 ns/iter (+/- 7)
test benchmarks::bench_mutation_1024inds                                                                   ... bench:   1,553,265 ns/iter (+/- 23,022)
test benchmarks::bench_refitness_niches_1024inds                                                           ... bench:      29,616 ns/iter (+/- 783)
test benchmarks::bench_refitness_none_1024inds                                                             ... bench:      29,756 ns/iter (+/- 3,576)
test benchmarks::bench_selection_cup_255inds                                                               ... bench:     357,611 ns/iter (+/- 37,254)
test benchmarks::bench_selection_roulette_256inds                                                          ... bench:     141,654 ns/iter (+/- 1,338)
test benchmarks::bench_selection_tournaments_256inds                                                       ... bench:     616,907 ns/iter (+/- 50,645)
test benchmarks::bench_survival_pressure_children_fight_most_similar_255inds                               ... bench:  17,748,382 ns/iter (+/- 762,602)
test benchmarks::bench_survival_pressure_children_fight_parents_255inds                                    ... bench:     139,405 ns/iter (+/- 2,267)
test benchmarks::bench_survival_pressure_children_replace_most_similar_255inds                             ... bench:  17,716,416 ns/iter (+/- 739,662)
test benchmarks::bench_survival_pressure_children_replace_parents_255inds                                  ... bench:     202,788 ns/iter (+/- 18,250)
test benchmarks::bench_survival_pressure_children_replace_parents_and_the_rest_most_similar_255inds        ... bench: 1,387,504,266 ns/iter (+/- 45,914,604)
test benchmarks::bench_survival_pressure_children_replace_parents_and_the_rest_random_most_similar_255inds ... bench:   9,389,378 ns/iter (+/- 1,224,136)
test benchmarks::bench_survival_pressure_competitive_overpopulation_255inds                                ... bench:  12,803,024 ns/iter (+/- 1,946,079)
test benchmarks::bench_survival_pressure_deterministic_overpopulation_255inds                              ... bench:     220,667 ns/iter (+/- 2,790)
test benchmarks::bench_survival_pressure_overpopulation_255inds                                            ... bench:  12,243,512 ns/iter (+/- 726,154)
test benchmarks::bench_survival_pressure_worst_255inds                                                     ... bench:      20,339 ns/iter (+/- 1,113)
test benchmarks::bench_update_progress_1024inds                                                            ... bench:       7,595 ns/iter (+/- 378)

These benchmarks have been executed in a Intel Core i7 6700K with 16 GB of DDR4 and a 1024 GB Samsung 970 Evo Plus NVMe SSD in ext4 format in Fedora 33 with Linux kernel 5.9.16.

The difference of performance among the different fitness benchmarks have the following explanations:

  • bench_fitness measures the performance of a cached execution without cleaning the fitnesses after each bench iteration. This cleaning was not done in previous versions of this README and so it was higher.
  • bench_mutation was very much faster in previous versions of this README because an error in the benchmark (empty population).
  • bench_fitness_age measures the performance with fitness cached in all bench iterations, so it is slightly slower.
  • Not cached benchmarks measure the performance of not cached executions, with 1 generation individuals in the last case, so the performance is similar but a bit slower for the benchmark that must apply age unfitness.
  • The children_fight_most_similar and children_replace_most_similar functions have to call the distance function c * p times, where c is the number of children and p is the size of the population (255 and 1024 respectively in the benchmarks).
  • The overpopulation and competitive_overpopulation functions are similar to children_replace_most_similar and children_fight_most_similar except to they are compared only with m individuals of the population (m is bigger than the number of children and smaller than the population size, 768 in the benchmarks). Therefore, 3/4 of the comparisons are done in these benchmarks compared to children_replace_most_similar and children_fight_most_similar.
  • children_replace_parents_and_the_rest_random_most_similar is similar to children_replace_parents but, after it, random individuals are chosen to fight against the most similar individual in the population until the population size is the original population size. This means between 0 and 254 times random choosing and distance computation over the entire population in function of the repeated parents in each generation.
  • children_replace_parents_and_the_rest_most_similar is like the previous function but it searches the pairs of most similar individuals in the population, which means p2 distance function calls (220 in the benchmark).

Contributing

Contributions are absolutely, positively welcome and encouraged! Contributions come in many forms. You could:

  1. Submit a feature request or bug report as an issue.
  2. Ask for improved documentation as an issue.
  3. Comment on issues that require feedback.
  4. Contribute code via pull requests.

We aim to keep Oxigen's code quality at the highest level. This means that any code you contribute must be:

  • Commented: Public items must be commented.
  • Documented: Exposed items must have rustdoc comments with examples, if applicable.
  • Styled: Your code should be rustfmt'd when possible.
  • Simple: Your code should accomplish its task as simply and idiomatically as possible.
  • Tested: You should add (and pass) convincing tests for any functionality you add when it is possible.
  • Focused: Your code should do what it's supposed to do and nothing more.

Note that unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Oxigen by you shall be licensed under Mozilla Public License 2.0.

Reference

Pozo, Martín "Oxigen: Fast, parallel, extensible and adaptable genetic algorithms framework written in Rust".

Bibtex

@misc{
  title={Oxigen: Fast, parallel, extensible and adaptable genetic algorithms framework written in Rust},
  author={Pozo, Martín},
  howpublised = "\url{https://github.com/Martin1887/oxigen}"
}

License

Oxigen is licensed under Mozilla Public License 2.0.

Comments
  • Feature/partially matched uniform cx

    Feature/partially matched uniform cx

    An implementation of "uniform partially matched crossover". An example is given in this paper in section 4.4.4. Useful for problems such as traveling salesman and genotypes that require uniquely-labeled genes 0 through N to remain present in the chromosome following crossover. An example of the problem having such a crossover alleviates:

    Parent 1: [1,2,3,4,5] Parent 2: [5,4,3,2,1]

    Single point crossover after the 2nd index

    Child 1: [5,4,3,4,5] Child 2: [1,2,3,2,1]

    If you imagine the genes as stops along a route, the resulting genotypes are no longer valid because 2 locations are skipped in each child representation. This is the problem that partially-matched crossover is meant to alleviate; it's an element-preserving operation.

    opened by aneksteind 7
  • Individuals from shorter iterators

    Individuals from shorter iterators

    Why at a certain point the optimizer starts to generate individuals with a minor number of elements? Is it intended behavior? How can this effect be counteracted? Thanks!

    opened by garro95 6
  • Introduce a GeneticExecutionBuilder

    Introduce a GeneticExecutionBuilder

    I like the way a new GeneticExecution object is built. According to the Rust Guidelines, although, there should be another object, called ...Builder, that provides such an API. The builder methods could take &mut Builder and return the reference, thus being more flexible, while only the final method, that build the actual object, would take the ownership. On the final type, methods that have the name of a field should be getters for that field instead.

    opened by garro95 4
  • `Uniform::new called with `low >= high`

    `Uniform::new called with `low >= high`

    Describe the bug Oxigen fails to create the next generation of individuals.

    To Reproduce I'm not sure how to reproduce it with a simple use case, but I can reproduce it systematically with a small variation to the orbit_design_ga project. Specifically, if my genome is only one gene long, this problem shows up. Two or more genes, and it doesn't happen.

    I understand/expect that the information I provide is not enough to fix. Hence, can you explain to me in which cases the following line from crossover.rs would fail:

    let cross_point = SmallRng::from_entropy().sample(Uniform::from(1..ind_size));
    

    I'm guessing that ind_size is zero, but I don't know what would cause it to be zero.

    Thanks for your help

    Stack trace

         Running `target/debug/orbit_design_ga`
    Fitness: 2000
    Fitness: 2001
    Fitness: 2001
    Fitness: 2001
    Fitness: 2000
    Fitness: 2001
    Fitness: 2000
    Fitness: 2001
    Fitness: 0
    Fitness: 0
    Fitness: 0
    Fitness: 2000
    Fitness: 2001
    Fitness: 2000
    Fitness: 2001
    Fitness: 2001
    thread 'main' panicked at 'Uniform::new called with `low >= high`', /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/rand-0.7.3/src/distributions/uniform.rs:477:1
    stack backtrace:
       0: std::panicking::begin_panic
                 at /home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:519:12
       1: <rand::distributions::uniform::UniformInt<usize> as rand::distributions::uniform::UniformSampler>::new
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/rand-0.7.3/src/distributions/uniform.rs:379:17
       2: rand::distributions::uniform::Uniform<X>::new
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/rand-0.7.3/src/distributions/uniform.rs:172:17
       3: <rand::distributions::uniform::Uniform<X> as core::convert::From<core::ops::range::Range<X>>>::from
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/rand-0.7.3/src/distributions/uniform.rs:272:9
       4: <oxigen::crossover::CrossoverFunctions as oxigen::crossover::Crossover<T,G>>::cross
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/oxigen-2.2.0/src/crossover.rs:31:67
       5: oxigen::GeneticExecution<T,Ind>::cross::{{closure}}
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/oxigen-2.2.0/src/lib.rs:639:40
       6: core::ops::function::impls::<impl core::ops::function::Fn<A> for &F>::call
                 at /home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:237:13
       7: <rayon::iter::map_with::MapWithFolder<C,U,F> as rayon::iter::plumbing::Folder<T>>::consume_iter::with::{{closure}}
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.0/src/iter/map_with.rs:317:22
       8: core::iter::adapters::map::map_fold::{{closure}}
                 at /home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/adapters/map.rs:80:28
       9: core::iter::traits::iterator::Iterator::fold
                 at /home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:2023:21
      10: <core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::fold
                 at /home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/adapters/map.rs:120:9
      11: core::iter::traits::iterator::Iterator::for_each
                 at /home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:678:9
      12: <rayon::iter::noop::NoopConsumer as rayon::iter::plumbing::Folder<T>>::consume_iter
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.0/src/iter/noop.rs:34:9
      13: <rayon::iter::map_with::MapWithFolder<C,U,F> as rayon::iter::plumbing::Folder<T>>::consume_iter
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.0/src/iter/map_with.rs:322:25
      14: rayon::iter::plumbing::Producer::fold_with
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.0/src/iter/plumbing/mod.rs:110:9
      15: rayon::iter::plumbing::bridge_producer_consumer::helper
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.0/src/iter/plumbing/mod.rs:438:13
      16: rayon::iter::plumbing::bridge_producer_consumer
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.0/src/iter/plumbing/mod.rs:397:12
      17: <rayon::iter::plumbing::bridge::Callback<C> as rayon::iter::plumbing::ProducerCallback<I>>::callback
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.0/src/iter/plumbing/mod.rs:373:13
      18: <rayon::range::Iter<usize> as rayon::iter::IndexedParallelIterator>::with_producer
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.0/src/range.rs:112:17
      19: rayon::iter::plumbing::bridge
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.0/src/iter/plumbing/mod.rs:357:12
      20: <rayon::range::Iter<usize> as rayon::iter::ParallelIterator>::drive_unindexed
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.0/src/range.rs:88:17
      21: <rayon::iter::map_with::MapWith<I,T,F> as rayon::iter::ParallelIterator>::drive_unindexed
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.0/src/iter/map_with.rs:53:9
      22: rayon::iter::from_par_iter::<impl rayon::iter::FromParallelIterator<()> for ()>::from_par_iter
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.0/src/iter/from_par_iter.rs:226:9
      23: rayon::iter::ParallelIterator::collect
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.0/src/iter/mod.rs:1973:9
      24: rayon::iter::ParallelIterator::for_each_with
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/rayon-1.5.0/src/iter/mod.rs:400:9
      25: oxigen::GeneticExecution<T,Ind>::cross
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/oxigen-2.2.0/src/lib.rs:626:9
      26: oxigen::GeneticExecution<T,Ind>::run_loop
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/oxigen-2.2.0/src/lib.rs:345:36
      27: oxigen::GeneticExecution<T,Ind>::run
                 at /home/chris/.cargo/registry/src/github.com-1ecc6299db9ec823/oxigen-2.2.0/src/lib.rs:311:49
      28: orbit_design_ga::main
                 at ./src/main.rs:32:9
      29: core::ops::function::FnOnce::call_once
                 at /home/chris/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:227:5
    note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
    
    opened by ChristopherRabotin 3
  • build error for nightly compiler

    build error for nightly compiler

    rustc 1.52.0-nightly (83b30a639 2021-02-20)

    Build with error message:

    error[E0046]: not all trait items implemented, missing: `GenotypeHash`, `hash`
      --> onemax-oxigen/src/main.rs:19:1
       |
    19 | impl Genotype<bool> for OneMax {
       | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `GenotypeHash`, `hash` in implementation
       |
       = help: implement the missing item: `type GenotypeHash = Type;`
       = help: implement the missing item: `fn hash(&self) -> <Self as oxigen::Genotype<T>>::GenotypeHash { todo!() }`
    
    error[E0046]: not all trait items implemented, missing: `GenotypeHash`, `hash`
      --> knapsack-oxigen/src/main.rs:52:1
       |
    52 | impl<'a> Genotype<bool> for Knapsack<'a> {
       | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `GenotypeHash`, `hash` in implementation
       |
       = help: implement the missing item: `type GenotypeHash = Type;`
       = help: implement the missing item: `fn hash(&self) -> <Self as oxigen::Genotype<T>>::GenotypeHash { todo!() }`
    
    error: aborting due to previous error
    
    For more information about this error, try `rustc --explain E0046`.
    error: could not compile `onemax-oxigen`
    
    To learn more, run the command again with --verbose.
    warning: build failed, waiting for other jobs to finish...
    error: aborting due to previous error
    
    For more information about this error, try `rustc --explain E0046`.
    error: build failed
    
    opened by chenyukang 3
  • Wrong comment for the fitness function in Knapsack example

    Wrong comment for the fitness function in Knapsack example

    Seems like a comment for the N Queen example instead.

    https://github.com/Martin1887/oxigen/blob/c39aee22424f5cf803a9224a08c0051479cf424a/knapsack-oxigen/src/main.rs#L79-L81

    opened by discosultan 2
  • Trouble building 3.0

    Trouble building 3.0

    I noticed that travis tends to build 3.0 just fine, so I wonder if I'm missing something here, perhaps the wrong rust version.

    When building 3.0 I get the following compilation error:

    error[E0046]: not all trait items implemented, missing: `GenotypeHash`, `hash`
      --> onemax-oxigen/src/main.rs:19:1
       |
    19 | impl Genotype<bool> for OneMax {
       | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `GenotypeHash`, `hash` in implementation
       |
       = help: implement the missing item: `type GenotypeHash = Type;`
       = help: implement the missing item: `fn hash(&self) -> <Self as oxigen::Genotype<T>>::GenotypeHash { unimplemented!() }`
    
    error[E0046]: not all trait items implemented, missing: `GenotypeHash`, `hash`
      --> knapsack-oxigen/src/main.rs:52:1
       |
    52 | impl<'a> Genotype<bool> for Knapsack<'a> {
       | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `GenotypeHash`, `hash` in implementation
       |
       = help: implement the missing item: `type GenotypeHash = Type;`
       = help: implement the missing item: `fn hash(&self) -> <Self as oxigen::Genotype<T>>::GenotypeHash { unimplemented!() }`
    
    error: aborting due to previous error
    
    For more information about this error, try `rustc --explain E0046`.
    error: could not compile `onemax-oxigen`.
    warning: build failed, waiting for other jobs to finish...
    error: aborting due to previous error
    
    For more information about this error, try `rustc --explain E0046`.
    error: could not compile `knapsack-oxigen`.
    warning: build failed, waiting for other jobs to finish...
    error: build failed
    

    I was under the impression that there was a default hash implementation for these items, so I'm unsure what could be causing the problem. Any idea?

    Thanks

    opened by aneksteind 2
  • Support for a reference environment

    Support for a reference environment

    Is your feature request related to a problem? Please describe. I am attempting to optimize for a graph-related problem and would like to create a genotype whose fitness function is calculated based on some reference graph, which ideally would be part of some read-only environment.

    It seems that, internally in oxigen/lib.rs, fitness is calculated for individuals generated with generate (see here), which can only take in a ProblemSize instance passed via genotype_size().

    So, either it appears that any fitness method I define cannot refer to the graph I wish to optimize against because that is decided at runtime or I must smuggle the graph in as part of the ProblemSize passed into the genotype_size() method. Is this the correct interpretation?

    In effect, ProblemSize is acting as the environment type and field. For example, it appears this is the case in the knap-sack example where the items are constructed (see here) and passed in as part of the problem size.

    Describe the solution you'd like Rename

    1. ProblemSize
    2. genotype_size(mut self, new_size: Ind::ProblemSize), and
    3. GeneticExecution.genotype_size

    to

    1. Environment
    2. set_environment(mut self, env: Ind::Environment), and
    3. GeneticExecution.environment, respectively

    Describe alternatives you've considered No alternatives considered.

    Additional context No additional context.

    opened by aneksteind 2
  • Extra example(s)

    Extra example(s)

    Would it be possible to provide more examples?

    I'd like to see how a more simple problem is tackled with oxigen, so to see how the mechanism works. Could this example (https://deap.readthedocs.io/en/master/examples/ga_onemax.html) be translated to oxigen?

    I really would like to help, but my Rust-knowledge is not good enough...

    Thanks in advance!

    opened by davidbe 2
  • Add standard formatting

    Add standard formatting

    Make the code style/formatting more standard to enable greater contributions. This is just a basic rustfmt.toml + a run of cargo fmt.

    Next step is travis or something similar, what are your thoughts about it ?

    opened by efugier 2
  • one max bug

    one max bug

    Hello,

    See below:

    error[E0046]: not all trait items implemented, missing: GenotypeHash, hash --> onemax-oxigen/src/main.rs:19:1 | 19 | impl Genotype for OneMax { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing GenotypeHash, hash in implementation | = help: implement the missing item: type GenotypeHash = Type; = help: implement the missing item: fn hash(&self) -> <Self as oxigen::Genotype<T>>::GenotypeHash { todo!() }

    error[E0046]: not all trait items implemented, missing: GenotypeHash, hash --> knapsack-oxigen/src/main.rs:52:1 | 52 | impl<'a> Genotype for Knapsack<'a> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing GenotypeHash, hash in implementation | = help: implement the missing item: type GenotypeHash = Type; = help: implement the missing item: fn hash(&self) -> <Self as oxigen::Genotype<T>>::GenotypeHash { todo!() }

    For more information about this error, try rustc --explain E0046. error: could not compile onemax-oxigen due to previous error warning: build failed, waiting for other jobs to finish... warning: panic message is not a string literal --> fd-oxigen/src/main.rs:220:25 | 220 | _ => panic!(format!("Incorrect index passed to n_values: {}", index)), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: #[warn(non_fmt_panics)] on by default = note: this usage of panic!() is deprecated; it will be a hard error in Rust 2021 = note: for more information, see https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html = note: the panic!() macro supports formatting, so there's no need for the format!() macro here help: remove the format!(..) macro call | 220 - _ => panic!(format!("Incorrect index passed to n_values: {}", index)), 220 + _ => panic!("Incorrect index passed to n_values: {}", index), |

    warning: fd-oxigen (bin "fd-oxigen") generated 1 warning error: build failed

    Thanks,

    Jianshu

    opened by jianshu93 1
  • feature request: polymorphic fitness types

    feature request: polymorphic fitness types

    Is your feature request related to a problem? Please describe.

    My use case involves very large numbers whose precision I'd like to maintain. Casting my BigInt type to an f64 causes a loss of information.

    Describe the solution you'd like

    Polymorphic fitness types, e.g. changing

    fn fitness(&self) -> f64
    

    to something like

    fn fitness(&self) -> S where
    S: std::ops::Add {
    ...
    }
    

    Describe alternatives you've considered Casting my big int type to f64 (which is my current fix)

    I'd be willing to help with this myself if it's of interest

    opened by aneksteind 1
  • Use traits instead of structs

    Use traits instead of structs

    The Genotype iter and into_iter methods should return a Type that implements the Iterator and IntoIterator traits and not the specific implementation of these traits for slices. This would improve usability of the framework

    opened by garro95 8
Releases(2.2.2)
  • 2.2.2(Feb 28, 2021)

    • Special case for single crosspoint and multicrosspoint with individuals of length 1 interchanging it with a random position of the other individual.
    • Interchange random positions in uniform cross instead of always even ones.
    Source code(tar.gz)
    Source code(zip)
  • 2.1.4(Feb 28, 2021)

    • Special case for single crosspoint and multicrosspoint with individuals of length 1 interchanging it with a random position of the other individual.
    • Interchange random positions in uniform cross instead of always even ones.
    Source code(tar.gz)
    Source code(zip)
  • 2.0.6(Feb 28, 2021)

    • Special case for single crosspoint and multicrosspoint with individuals of length 1 interchanging it with a random position of the other individual.
    • Interchange random positions in uniform cross instead of always even ones.
    Source code(tar.gz)
    Source code(zip)
  • 1.5.2(Feb 28, 2021)

    • Special case for single crosspoint and multicrosspoint with individuals of length 1 interchanging it with a random position of the other individual.
    • Interchange random positions in uniform cross instead of always even ones.
    Source code(tar.gz)
    Source code(zip)
  • 2.2.1(Feb 27, 2021)

  • 2.1.3(Feb 27, 2021)

  • 2.0.5(Feb 27, 2021)

  • 1.5.1(Feb 27, 2021)

  • 2.1.2(Jan 13, 2021)

  • 2.0.4(Jan 13, 2021)

  • 2.2.0(Jan 9, 2021)

    • Better population refitness taking into account the age effect but not the refitness of previous generations (in previous versions the original fitness was taken instead).
    • Fix niches formula: 1.0 - (d / sigma.0).powf(alfa.0) instead of (1.0 - (d / sigma.0)).powf(alfa.0).
    • Historical of solutions instead of checking only the current generation.
    • Improve performance of getting fitnesses and solutions using a normal iterator instead of a parallel one.
    Source code(tar.gz)
    Source code(zip)
  • 2.1.1(Jan 9, 2021)

  • 2.0.3(Jan 9, 2021)

  • 2.1.0(Jan 19, 2020)

  • 2.0.2(Oct 18, 2019)

  • 2.0.1(Oct 18, 2019)

    Do public ind and fitness attributes of IndWithFitness struct to do possible getting individual and its fitness at the end of the genetic algorithm execution.

    Source code(tar.gz)
    Source code(zip)
  • 2.0.0(Sep 28, 2019)

    • Oxigen 2 is more flexible because any struct with a Vec inside can implement Genotype. In 1 versions this was not possible because Genotype had to implement FromIterator. In 2 versions a from_iter function has been added instead.
    • Oxigen 2 fix the issue #3 ('Cuadratic' has been replaced by 'Quadratic' in built-in enums). This has not been fixed in 1 versions to not break the interface.
    • The fix function in Genotype returns a boolean to specify if the individual has been changed to recompute its fitness.
    • The number of solutions gotten in each generation is now the number of different solutions using the new distance function of Genotype.
    • The u16 type has been changed by usize in StopCriterion, MutationRate and SelectionRate traits.
    • PopulationRefitness trait has been added to optionally refit the individuals of the population comparing them to the other individuals. Niches built-in PopulationRefitness function has been added.
    • The SurvivalPressure trait has been redefined and now it kills the individuals instead of returning the indexes to remove. It also receives a list with the pairs of parents and children of the generation.
    • Many SurvivalPressure built-in functions have been added, like Overpouplation, CompetitiveOverpopulation, DeterministicOverpopulation, ChildrenFightParents, ChildrenFightMostsimilar, etc.
    • The two previous additions allow to search different solutions in different search space areas in order to avoid local suboptimal solutions and find different solutions.
    • Other minor improvements.
    Source code(tar.gz)
    Source code(zip)
  • 1.5.0(Aug 24, 2019)

  • 1.4.3(Jul 22, 2019)

  • 1.4.2(Jan 13, 2019)

  • 1.4.1(Jan 6, 2019)

  • 1.4.0(Jan 1, 2019)

  • 1.3.0(Dec 27, 2018)

    Fix empty finesses at the first generation sent to StopCriterion, MutationRate and SelectionRate.

    Add GenerationAndProgress, MaxFitness, MinFitness and AvgFitness built-in stop criteria.

    Source code(tar.gz)
    Source code(zip)
  • 1.2.1(Dec 27, 2018)

  • 1.2.0(Dec 26, 2018)

    A fix method has been added to Genotype to allow to repair individuals to satisfy restrictions.

    A SolutionsFound stop criterion has been added to specify the desired number of solutions.

    The Progress stop criterion has been fixed (always stopped at iteration 0).

    The populations output has been improved.

    Source code(tar.gz)
    Source code(zip)
  • 1.1.0(Aug 20, 2018)

  • 1.0.0(Aug 20, 2018)

Owner
Martín Pozo
Martín Pozo
A browser app that evolves vehicles using genetic algorithms, written in Rust and Bevy

Vehicle Evolver Deluxe This is a simulation that uses AI (to be specific: genetic algorithms) to try to build better and better vehicles. The vehicles

null 95 Dec 26, 2022
Execute genetic algorithm (GA) simulations in a customizable and extensible way.

genevo genevo provides building blocks to run simulations of optimization and search problems using genetic algorithms (GA). The vision for genevo is

Innoave 110 Dec 21, 2022
Genetic Algorithms Library

genx genx provides modular building blocks to run simulations of optimization and search problems using Genetic Algorithms (GA). The vision for genx i

Lakshya Singh 29 Aug 9, 2022
Example of a genetic algorithm in Rust and Python

Example of a genetic algorithm in Rust and Python Monkey typewriter Finding the phrase 'To be or not to be. That is the question.' Inspired by the exa

sotrh 2 Jan 27, 2022
Genetic Algorithm library in Rust

RsGenetic Summary and Features RsGenetic is a framework for executing genetic algorithms in Rust. It is designed to have a simple but modular API. Exa

Mathieu De Coster 74 Dec 27, 2022
nsga is an opinionated implementation of the NSGA-II (Non-dominated Sorting Genetic Algorithm)

nsga nsga is an opinionated implementation of the NSGA-II (Non-dominated Sorting Genetic Algorithm), a multi-objective genetic optimization algorithm.

Max Kuznetsov 8 Oct 1, 2022
This crate implements fast route planning algorithms in Rust.

This crate implements fast route planning algorithms in Rust. Algorithms Currently implemented: Contraction Hierarchies: The implementat

Payas Rajan 4 Aug 15, 2021
A tool used to evaluate the output of retrieval algorithms. Written in Rust.

Rusteval A tool used to evaluate the output of retrieval algorithms. Written in Rust. Building Install Rust with curl -sSf https://static.rust-lang.or

Giorgos Sfikas 17 Mar 22, 2022
Common data structures and algorithms for competitive programming in Rust

algorithm-rs algorithm-rs is common data structures and algorithms for competitive programming in Rust. Contents TBA How To Contribute Contributions a

Chris Ohk 16 Dec 21, 2022
zine/book about bitmap drawing algorithms and math with code examples in Rust

A Bitmapper's Companion - zine/book about bitmap drawing algorithms and math with code examples in Rust A small zine/book written in LaTeX. In progres

Manos Pitsidianakis 42 Nov 8, 2022
A Rust implementation the HOTP and TOTP Algorithms

xotp A Rust implementation the HOTP and TOTP Algorithms. HOTP was implemented in accordance with RFC4226 TOTP was implemented in accordance with RFC62

Tejas Mehta 3 Jan 21, 2022
This library provides implementations of many algorithms and data structures that are useful for bioinformatics.

This library provides implementations of many algorithms and data structures that are useful for bioinformatics. All provided implementations are rigorously tested via continuous integration.

Rust-Bio 1.2k Dec 26, 2022
darwin-rs, evolutionary algorithms with rust

darwin-rs This library allows you to write evolutionary algorithms (EA) using the Rust programming language. Written by Willi Kappler, License: MIT -

Willi Kappler 95 Jan 1, 2023
"Algorithms for approximate string matching" in Rust, with Python bindings.

ukkonen Implementation of a bounded Levenshtein distance by Esko Ukkonen in "Algorithms for approximate string matching" in Rust, with Python bindings

Ethan Smith 1 Dec 1, 2021
Algorithms implemented in Rust, explained.

Rusty Algorithms & Data Structures for Learners This repository presents Rust implementations of common algorithms and data structures, many of which

Tianyi Shi 327 Dec 19, 2022
Bandit Algorithms in Rust

Multi-armed bandit algorithms in Rust Cargo [dependencies] bandit = "0.12.3" Description and Scope This library currently only implements the annealin

Michael Bohn 30 Nov 24, 2022
Compare binary files using alignment algorithms

biodiff Compare binary files using alignment algorithms. What is this This is a tool for binary diffing. The tool is able to show two binary files sid

null 483 Dec 22, 2022
DSP algorithms for embedded. Often integer math.

This crate contains some tuned DSP algorithms for general and especially embedded use.

QUARTIQ 12 Nov 3, 2022