radiate-rust 0.3.0

A Rust library for genetic algorithms and artificial evolution.
Documentation
use crate::engines::genome::genes::gene::Gene;
use crate::engines::genome::population::Population;
use crate::Optimize;
use rand::Rng;

pub trait Select<G, A> 
where
    G: Gene<G, A>
{
    fn select(&self, population: &Population<G, A>, optimize: &Optimize, count: usize) -> Population<G, A>;
}

#[allow(dead_code)]
pub enum Selector {
    Tournament(u8),
    Roulette,
    Rank,
    Elitism,
    Boltzmann(f32),
}

impl<G, A> Select<G, A> for Selector 
where
    G: Gene<G, A>
{
    #[inline]
    fn select(&self, population: &Population<G, A>, optimize: &Optimize, count: usize) -> Population<G, A> {
        match self {
            Selector::Tournament(size) => {
                let mut rng = rand::thread_rng();
                let mut selected = Vec::with_capacity(count);

                for _ in 0..count {
                    let mut tournament = Vec::with_capacity(*size as usize);
                    for _ in 0..*size {
                        let idx = rng.gen_range(0..population.len());
                        tournament.push(idx);
                    }

                    tournament.sort();

                    selected.push(population.get(tournament[0]).clone());
                }

                Population::from_vec(selected)
            }
            Selector::Roulette => {
                let mut selected = Vec::with_capacity(count);
                let mut fitness_values = Vec::with_capacity(population.len());
                let mut rng = rand::thread_rng();
                
                let total = population
                    .iter()
                    .map(|individual| match individual.score() {
                        Some(score) => score.as_float(),
                        None => 0.0,
                    })
                    .sum::<f32>();

                for individual in population.iter() {
                    let score = match individual.score() {
                        Some(score) => score.as_float(),
                        None => 0.0,
                    };

                    fitness_values.push(score / total);
                }

                if optimize == &Optimize::Minimize {
                    fitness_values.reverse();
                }

                let total_fitness = fitness_values.iter().sum::<f32>();

                for _ in 0..count {
                    let mut idx = rng.gen_range(0.0..total_fitness);

                    for i in 0..fitness_values.len() {
                        idx -= fitness_values[i];
                        if idx <= 0.0 {
                            selected.push(population.get(i).clone());
                            break;
                        }
                    }
                }

                Population::from_vec(selected)
            }
            Selector::Rank => {
                let mut selected = Vec::with_capacity(count);
                let mut rng = rand::thread_rng();

                let total_rank = (population.len() * (population.len() + 1)) as f32 / 2.0;

                for _ in 0..count {
                    let mut idx = rng.gen_range(0.0..total_rank);
                    let mut selected_idx = 0;
                    for individual in population.iter() {
                        idx -= (population.len() - selected_idx) as f32;
                        if idx <= 0.0 {
                            selected.push(individual.clone());
                            break;
                        }
                        selected_idx += 1;
                    }
                }

                Population::from_vec(selected)
            }
            Selector::Elitism => population
                .iter()
                .take(count)
                .map(|individual| individual.clone())
                .collect::<Population<G, A>>(),
            Selector::Boltzmann(temperature) => {
                let mut selected = Vec::with_capacity(count);
                let mut rng = rand::thread_rng();

                let mut min = population.get(0).score().as_ref().unwrap().as_float();
                let mut max = min;

                for individual in population.iter() {
                    let score = individual.score().as_ref().unwrap().as_float();
                    if score < min {
                        min = score;
                    }
                    if score > max {
                        max = score;
                    }
                }

                let diff = max - min;
                if diff == 0.0 {
                    return population
                        .iter()
                        .take(count)
                        .map(|individual| individual.clone())
                        .collect::<Population<G, A>>();
                }

                let mut result = Vec::with_capacity(population.len());
                for individual in population.iter() {
                    let score = individual.score().as_ref().unwrap().as_float();
                    let fitness = (score - min) / diff;
                    let value = (temperature * fitness).exp();

                    result.push(value);
                }

                let total_fitness = result.iter().sum::<f32>();
                for i in 0..result.len() {
                    result[i] /= total_fitness;
                }

                if optimize == &Optimize::Minimize {
                    result.reverse();
                }

                let total_fitness = result.iter().sum::<f32>();

                for _ in 0..count {
                    let mut idx = rng.gen_range(0.0..total_fitness);

                    for i in 0..result.len() {
                        idx -= result[i];
                        if idx <= 0.0 {
                            selected.push(population.get(i).clone());
                            break;
                        }
                    }
                }

                Population::from_vec(selected)
            }
        }
    }
}