<commit_before>/// A genetic algorithm in Rust
/// Copyright (C) 2015  <NAME>

use std::cmp::{Eq, PartialEq, Ordering, PartialOrd};
use std::mem;
use rand::Rng;
use rand::distributions::{IndependentSample, Range};

/// Schwefel's Evolutionary Computation benchmark [problem][]
/// Evaluated on the hypercube with x_i in [-500, 500] and dim(x) = 50
/// Global minimum: f(x*) = 0, at x* = (420.9687, ...)
/// [problem]: http://www.sfu.ca/~ssurjano/schwef.html
fn schwefel(solution: &[f64]) -> f64 {
    418.9829_f64 * solution.len() as f64
        - solution.iter().fold(0_f64, |sum, x| {
            sum + x * x.abs().sqrt().sin()
        })
}

/// An Orderable, Cloneable solution with a cached fitness
pub struct Individual {
    pub solution: Vec<f64>,
    pub fitness: f64,
}

impl Individual {
    /// Constructs a new Individual with 50 random values in the range
    pub fn new<R: Rng>(range: &Range<f64>, rng: &mut R) -> Self {
        let solution: Vec<_> = (0..50).map(|_| range.ind_sample(rng)).collect();
        let fitness = schwefel(&solution);
        Individual { solution: solution, fitness: fitness }
    }

    /// Mutates 0 or 1 random genes to a new value in the range
    pub fn mutate<R: Rng>(&mut self, range: &Range<f64>, rng: &mut R) {
        for _ in 0..rng.gen_range(0, 2) {
            let i = rng.gen_range(0, self.solution.len());
            self.solution[i] = range.ind_sample(rng);
        }
        self.fitness = schwefel(&self.solution);
    }

    /// Recombines two Individuals with a 1 in 2 chance via two-point crossover
    pub fn combine<R: Rng>(x: &mut Individual, y: &mut Individual, rng: &mut R) {
        if rng.gen_weighted_bool(2) {
            let len = x.solution.len();
            let (begin, n) = (rng.gen_range(0, len), rng.gen_range(0, len));
            for i in begin..(begin + n) % len {
                mem::swap(&mut x.solution[i], &mut y.solution[i]);
            }
            x.fitness = schwefel(&x.solution);
            y.fitness = schwefel(&y.solution);
        }
    }
}

impl Clone for Individual {
    fn clone(&self) -> Self {
        Individual { solution: self.solution.clone(), fitness: self.fitness }
    }
}

impl Eq for Individual {}

impl Ord for Individual {
    /// This dangerously delegates to `partial_cmp`; NaN will panic
    fn cmp(&self, other: &Self) -> Ordering {
        if let Some(result) = self.fitness.partial_cmp(&other.fitness) {
            return result;
        }
        unimplemented!();
    }
}
<commit_msg>Decrease complexity of fitness evaluation<commit_after>/// A genetic algorithm in Rust
/// Copyright (C) 2015  <NAME>

use std::cmp::{Eq, PartialEq, Ordering, PartialOrd};
use std::mem;
use rand::Rng;
use rand::distributions::{IndependentSample, Range};

/// Schwefel's Evolutionary Computation benchmark [problem][]
/// Evaluated on the hypercube with x_i in [-500, 500] and dim(x) = 50
/// Global minimum: f(x*) = 0, at x* = (420.9687, ...)
/// [problem]: http://www.sfu.ca/~ssurjano/schwef.html
fn schwefel(solution: &[f64]) -> f64 {
    418.9829_f64 * solution.len() as f64
        - solution.iter().fold(0_f64, |sum, x| {
            sum + x * x.abs().sqrt().sin()
        })
}

/// An Orderable, Cloneable solution with a cached fitness
pub struct Individual {
    pub solution: Vec<f64>,
    pub fitness: f64,
}

impl Individual {
    /// Constructs a new Individual with 50 random values in the range
    pub fn new<R: Rng>(range: &Range<f64>, rng: &mut R) -> Self {
        let solution: Vec<_> = (0..50).map(|_| range.ind_sample(rng)).collect();
        let fitness = schwefel(&solution);
        Individual { solution: solution, fitness: fitness }
    }

    /// Mutates 0 or 1 random genes to a new value in the range
    /// Fitness is NOT evaluated as it is ALWAYS done in `combine()`
    pub fn mutate<R: Rng>(&mut self, range: &Range<f64>, rng: &mut R) {
        for _ in 0..rng.gen_range(0, 2) {
            let i = rng.gen_range(0, self.solution.len());
            self.solution[i] = range.ind_sample(rng);
        }
    }

    /// Recombines two Individuals with a 1 in 2 chance via two-point crossover
    /// Fitness is ALWAYS evaluated because it is NOT done in mutate()
    pub fn combine<R: Rng>(x: &mut Individual, y: &mut Individual, rng: &mut R) {
        if rng.gen_weighted_bool(2) {
            let len = x.solution.len();
            let (begin, n) = (rng.gen_range(0, len), rng.gen_range(0, len));
            for i in begin..(begin + n) % len {
                mem::swap(&mut x.solution[i], &mut y.solution[i]);
            }
        }
        x.fitness = schwefel(&x.solution);
        y.fitness = schwefel(&y.solution);
    }
}

impl Clone for Individual {
    fn clone(&self) -> Self {
        Individual { solution: self.solution.clone(), fitness: self.fitness }
    }
}

impl Eq for Individual {}

impl Ord for Individual {
    /// This dangerously delegates to `partial_cmp`; NaN will panic
    fn cmp(&self, other: &Self) -> Ordering {
        if let Some(result) = self.fitness.partial_cmp(&other.fitness) {
            return result;
        }
        unimplemented!();
    }
}

{'fraction_non_alphanumeric': 0.14870395634379263, 'fraction_numerical': 0.024166829078152405, 'mean_word_length': 2.4769647696476964, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5065850', 'n_tokens_mistral': 1811, 'n_tokens_neox': 1674, 'n_words': 502}