radiate-selectors 1.3.0

Selection strategies for the Radiate genetic algorithm library.
Documentation
use radiate_core::{
    Chromosome, Objective, Optimize, Phenotype, Select, math::norm, pareto, random_provider,
};

#[derive(Debug, Clone, Default)]
pub struct StochasticUniversalSamplingSelector;

impl StochasticUniversalSamplingSelector {
    pub fn new() -> Self {
        StochasticUniversalSamplingSelector
    }
}

impl<C: Chromosome> Select<C> for StochasticUniversalSamplingSelector {
    fn select(
        &self,
        population: &[Phenotype<C>],
        objective: &Objective,
        count: usize,
    ) -> Vec<usize> {
        let fitness_values = match objective {
            Objective::Single(opt) => {
                let mut weights = population
                    .iter()
                    .filter_map(|p| p.score())
                    .filter_map(|score| score.first())
                    .collect::<Vec<f32>>();

                norm::scale_l1(&mut weights);

                if let Optimize::Minimize = opt {
                    weights.reverse();
                }

                weights
            }
            Objective::Multi(_) => {
                let scores = population
                    .iter()
                    .filter_map(|p| p.score())
                    .collect::<Vec<_>>();
                let mut weights = pareto::weights(&scores, objective);

                norm::scale_l1(&mut weights);

                weights
            }
        };

        let fitness_total = fitness_values.iter().sum::<f32>();
        let point_distance = fitness_total / count as f32;
        let start_point = random_provider::range(0.0..point_distance);

        let mut pointers = Vec::with_capacity(count);
        let mut current_point = start_point;

        for _ in 0..count {
            let mut index = 0;
            let mut fitness_sum = fitness_values[index];
            while fitness_sum < current_point && index < fitness_values.len() - 1 {
                index += 1;
                fitness_sum += fitness_values[index];
            }
            pointers.push(index);
            current_point += point_distance;
        }

        pointers
    }
}