use super::Gas;
use crate::candidate::Candidate;
#[mockall_double::double]
use crate::rando::Rando;
#[cfg(doc)]
use crate::crossover::Crossover;
#[cfg(doc)]
use crate::fitness::FitnessConfig;
#[cfg(doc)]
use crate::mutation::Mutation;
#[cfg(doc)]
use crate::tournaments::Tournament;
impl<const N: usize, const NSYMS: usize> Gas<N, NSYMS> {
pub fn generation(
&self,
population: &Vec<Candidate<N, NSYMS>>,
rng: &mut Rando,
score_weights: &Vec<f64>,
) -> Vec<Candidate<N, NSYMS>> {
let mut nextgen = Vec::<Candidate<N, NSYMS>>::with_capacity(population.len());
let (winner, weights) = self.cycle_tournament.run(&population, rng, score_weights);
nextgen.push(winner);
let mut popdist = rng.weighted_iter(&weights);
let mut crossover_iter = self.crossovers.iter();
let mut mutation_iter = self.mutations.iter();
for _ in 1..population.len() {
let mut chromosone;
loop {
let left = &population[popdist.next().unwrap()];
let mut right;
let mut i = 0;
loop {
right = &population[popdist.next().unwrap()];
if left != right {
if left.distance(&right) > self.taboo_distance {
break;
}
}
i += 1;
if i > population.len() {
eprintln!("TABOO!");
break;
}
}
let crossover = crossover_iter.next().unwrap();
let mutation = mutation_iter.next().unwrap();
chromosone = crossover.run(&left.chromosone, &right.chromosone, rng);
chromosone = mutation.run(&chromosone, rng);
if !nextgen.iter().any(|c| c.chromosone == chromosone) {
break;
}
}
nextgen.push(Candidate::from_chromosone(&self, chromosone));
}
nextgen
}
}
#[cfg(test)]
mod tests {
use super::*;
use mockall::predicate;
#[test]
fn test_generation() {
let gas = Gas::<5, 3>::dut();
let mut r = Rando::default();
r.expect_shuffle().times(1).return_const(()); r.expect_weighted_iter() .times(1)
.return_const([0, 1].iter().cloned());
r.expect_gen_range() .with(predicate::eq(0..5))
.times(1)
.return_const(1usize);
r.expect_gen_range() .with(predicate::eq(0..3))
.times(1)
.return_const(1usize);
let pop = &mut vec![
Candidate::from_chromosone(&gas, [0, 0, 0, 0, 0]),
Candidate::from_chromosone(&gas, [1, 0, 1, 0, 1]),
];
let nextgen = gas.generation(&pop, &mut r, &vec![1.0; 9]);
Candidate::assert_eq(
&nextgen[0],
&Candidate::from_chromosone(&gas, [1, 0, 1, 0, 1]),
);
}
}