genevo 0.7.1

genevo provides building blocks to run simulations of optimization and search problems using genetic algorithms (GA). Execute genetic algorithm (GA) simulations in a customizable and extensible way.
Documentation
use crate::{
    genetic::Genotype,
    operator::{GeneticOperator, MutationOp},
    random::{random_index, Rng},
};
use rand::seq::SliceRandom;
use std::fmt::Debug;

#[derive(Clone, Debug, PartialEq)]
pub struct RandomValueMutator<G>
where
    G: Genotype + RandomGenomeMutation,
{
    mutation_rate: f64,
    min_value: <G as Genotype>::Dna,
    max_value: <G as Genotype>::Dna,
}

impl<G> RandomValueMutator<G>
where
    G: Genotype + RandomGenomeMutation,
{
    pub fn new(
        mutation_rate: f64,
        min_value: <G as Genotype>::Dna,
        max_value: <G as Genotype>::Dna,
    ) -> Self {
        RandomValueMutator {
            mutation_rate,
            min_value,
            max_value,
        }
    }
}

impl<G> GeneticOperator for RandomValueMutator<G>
where
    G: Genotype + RandomGenomeMutation,
{
    fn name() -> String {
        "Random-Value-Mutator".to_string()
    }
}

impl<G> MutationOp<G> for RandomValueMutator<G>
where
    G: Genotype + RandomGenomeMutation,
{
    fn mutate<R>(&self, genome: G, rng: &mut R) -> G
    where
        R: Rng + Sized,
    {
        RandomGenomeMutation::mutate_genome(
            genome,
            self.mutation_rate,
            &self.min_value,
            &self.max_value,
            rng,
        )
    }
}

pub trait RandomGenomeMutation: Genotype {
    type Dna: Clone;

    fn mutate_genome<R>(
        genome: Self,
        mutation_rate: f64,
        min_value: &<Self as Genotype>::Dna,
        max_value: &<Self as Genotype>::Dna,
        rng: &mut R,
    ) -> Self
    where
        R: Rng + Sized;
}

impl<V> RandomGenomeMutation for Vec<V>
where
    V: Clone + Debug + PartialEq + Send + Sync + RandomValueMutation,
{
    type Dna = V;

    fn mutate_genome<R>(
        genome: Self,
        mutation_rate: f64,
        min_value: &V,
        max_value: &V,
        rng: &mut R,
    ) -> Self
    where
        R: Rng + Sized,
    {
        let genome_length = genome.len();
        let num_mutations =
            ((genome_length as f64 * mutation_rate) + rng.gen::<f64>()).floor() as usize;
        let mut mutated = genome;
        for _ in 0..num_mutations {
            let index = random_index(rng, genome_length);
            mutated[index] = RandomValueMutation::random_mutated(
                mutated[index].clone(),
                min_value,
                max_value,
                rng,
            );
        }
        mutated
    }
}

#[cfg(feature = "fixedbitset")]
mod fixedbitset_random_genome_mutation {
    use super::{random_index, RandomGenomeMutation};
    use crate::genetic::Genotype;
    use fixedbitset::FixedBitSet;
    use rand::Rng;

    impl RandomGenomeMutation for FixedBitSet {
        type Dna = bool;

        fn mutate_genome<R>(
            genome: Self,
            mutation_rate: f64,
            _: &<Self as Genotype>::Dna,
            _: &<Self as Genotype>::Dna,
            rng: &mut R,
        ) -> Self
        where
            R: Rng + Sized,
        {
            let genome_length = genome.len();
            let num_mutations =
                ((genome_length as f64 * mutation_rate) + rng.gen::<f64>()).floor() as usize;
            let mut mutated = genome;
            for _ in 0..num_mutations {
                let bit = random_index(rng, genome_length);
                let value = rng.gen();
                mutated.set(bit, value);
            }
            mutated
        }
    }
}

#[cfg(feature = "smallvec")]
mod smallvec_random_genome_mutation {
    use super::{random_index, RandomGenomeMutation, RandomValueMutation};
    use rand::Rng;
    use smallvec::{Array, SmallVec};
    use std::fmt::Debug;

    impl<V, A> RandomGenomeMutation for SmallVec<A>
    where
        A: Array<Item = V> + Sync,
        V: Clone + Debug + PartialEq + Send + Sync + RandomValueMutation,
    {
        type Dna = V;

        fn mutate_genome<R>(
            genome: Self,
            mutation_rate: f64,
            min_value: &V,
            max_value: &V,
            rng: &mut R,
        ) -> Self
        where
            R: Rng + Sized,
        {
            let genome_length = genome.len();
            let num_mutations =
                ((genome_length as f64 * mutation_rate) + rng.gen::<f64>()).floor() as usize;
            let mut mutated = genome;
            for _ in 0..num_mutations {
                let index = random_index(rng, genome_length);
                mutated[index] = RandomValueMutation::random_mutated(
                    mutated[index].clone(),
                    min_value,
                    max_value,
                    rng,
                );
            }
            mutated
        }
    }
}

pub trait RandomValueMutation {
    fn random_mutated<R>(value: Self, min_value: &Self, max_value: &Self, rng: &mut R) -> Self
    where
        R: Rng + Sized;
}

macro_rules! impl_random_value_mutation {
    ($($t:ty),*) => {
        $(
            impl RandomValueMutation for $t {
                #[inline]
                fn random_mutated<R>(_: $t, min_value: &$t, max_value: &$t, rng: &mut R) -> $t
                    where R: Rng + Sized
                {
                    rng.gen_range(*min_value..*max_value)
                }
            }
        )*
    }
}

impl_random_value_mutation!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, f32, f64);

impl RandomValueMutation for bool {
    #[inline]
    fn random_mutated<R>(_value: bool, _min_value: &bool, _max_value: &bool, rng: &mut R) -> bool
    where
        R: Rng + Sized,
    {
        rng.gen_bool(0.5)
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct BreederValueMutator<G>
where
    G: Genotype + BreederGenomeMutation,
{
    mutation_rate: f64,
    mutation_range: <G as Genotype>::Dna,
    mutation_precision: u8,
    min_value: <G as Genotype>::Dna,
    max_value: <G as Genotype>::Dna,
}

impl<G> BreederValueMutator<G>
where
    G: Genotype + BreederGenomeMutation,
{
    pub fn new(
        mutation_rate: f64,
        mutation_range: <G as Genotype>::Dna,
        mutation_precision: u8,
        min_value: <G as Genotype>::Dna,
        max_value: <G as Genotype>::Dna,
    ) -> Self {
        BreederValueMutator {
            mutation_rate,
            mutation_range,
            mutation_precision,
            min_value,
            max_value,
        }
    }
}

impl<G> GeneticOperator for BreederValueMutator<G>
where
    G: Genotype + BreederGenomeMutation,
{
    fn name() -> String {
        "Breeder-Value-Mutator".to_string()
    }
}

impl<G> MutationOp<G> for BreederValueMutator<G>
where
    G: Genotype + BreederGenomeMutation,
{
    fn mutate<R>(&self, genome: G, rng: &mut R) -> G
    where
        R: Rng + Sized,
    {
        BreederGenomeMutation::mutate_genome(
            genome,
            self.mutation_rate,
            &self.mutation_range,
            self.mutation_precision,
            &self.min_value,
            &self.max_value,
            rng,
        )
    }
}

pub trait BreederGenomeMutation: Genotype {
    type Dna: Clone;

    fn mutate_genome<R>(
        genome: Self,
        mutation_rate: f64,
        range: &<Self as Genotype>::Dna,
        precision: u8,
        min_value: &<Self as Genotype>::Dna,
        max_value: &<Self as Genotype>::Dna,
        rng: &mut R,
    ) -> Self
    where
        R: Rng + Sized;
}

impl<V> BreederGenomeMutation for Vec<V>
where
    V: Clone
        + Debug
        + PartialEq
        + PartialOrd
        + Send
        + Sync
        + BreederValueMutation
        + RandomValueMutation,
{
    type Dna = V;

    fn mutate_genome<R>(
        genome: Vec<V>,
        mutation_rate: f64,
        range: &<Self as Genotype>::Dna,
        precision: u8,
        min_value: &<Self as Genotype>::Dna,
        max_value: &<Self as Genotype>::Dna,
        rng: &mut R,
    ) -> Vec<V>
    where
        R: Rng + Sized,
    {
        let genome_length = genome.len();
        let num_mutations =
            ((genome_length as f64 * mutation_rate) + rng.gen::<f64>()).floor() as usize;
        let mut mutated = genome;
        for _ in 0..num_mutations {
            let index = random_index(rng, genome_length);
            let sign = *[-1, 1].choose(rng).unwrap();
            let adjustment = if *[true, false].choose(rng).unwrap() {
                1. / (1i64 << precision) as f64
            } else {
                1.
            };
            let value_mut = BreederValueMutation::breeder_mutated(
                mutated[index].clone(),
                range,
                adjustment,
                sign,
            );
            if value_mut < *min_value {
                mutated[index] =
                    RandomValueMutation::random_mutated(value_mut, min_value, max_value, rng)
            } else if value_mut > *max_value {
                mutated[index] = max_value.clone();
            } else {
                mutated[index] = value_mut;
            }
        }
        mutated
    }
}

pub trait BreederValueMutation {
    fn breeder_mutated(value: Self, range: &Self, adjustment: f64, sign: i8) -> Self;
}

macro_rules! impl_breeder_mutation {
    ($($t:ty),*) => {
        $(
            #[allow(trivial_numeric_casts)]
            impl BreederValueMutation for $t {
                #[inline]
                fn breeder_mutated(value: $t, range: &$t, adjustment: f64, sign: i8) -> $t {
                    (value as f64 + *range as f64 * adjustment * sign as f64) as $t
                }
            }
        )*
    }
}

impl_breeder_mutation!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, f32, f64);