use ops::traits::CrossoverOperator;
use rand::distributions::{Range, IndependentSample};
use rand::Rng;
#[derive(Clone, Copy, Default, Serialize, Deserialize)]
pub struct TwoPoint;
impl<C> CrossoverOperator<Vec<C>> for TwoPoint
where
C: Clone + Sized,
{
fn crossover<R: Rng>(
&self,
g1: &Vec<C>,
g2: &Vec<C>,
rng: &mut R,
) -> (Vec<C>, Vec<C>)
{
assert_eq!(g1.len(), g2.len(), "Genomes must be the same length");
let range = Range::new(0, g1.len());
let s1 = range.ind_sample(rng);
let s2 = range.ind_sample(rng);
let (p1, p2) = if s1 < s2 { (s1, s2) } else { (s2, s1) };
let mut g1 = g1.clone();
let mut g2 = g2.clone();
for i in p1..p2
{
let temp = g1[i].clone();
g1[i] = g2[i].clone();
g2[i] = temp;
}
(g1, g2)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
#[should_panic]
fn test_panics_on_different_len()
{
use rand::thread_rng;
let g1 = vec![0, 1, 2, 3];
let g2 = vec![4, 5];
let mut rng = thread_rng();
TwoPoint.crossover(&g1, &g2, &mut rng);
}
#[test]
fn test_crosses_correctly()
{
use rand::{StdRng, SeedableRng};
use rand::distributions::{Range, IndependentSample};
let g1 = vec![0, 1, 2, 3, 4];
let g2 = vec![5, 6, 7, 8, 9];
let seed: &[_] = &[0, 0, 0, 0];
let range = Range::new(0, g1.len());
let mut rng: StdRng = SeedableRng::from_seed(seed);
let s1 = range.ind_sample(&mut rng);
let s2 = range.ind_sample(&mut rng);
let (p1, p2) = if s1 < s2 { (s1, s2) } else { (s2, s1) };
rng.reseed(seed);
let (c1, c2) = TwoPoint.crossover(&g1, &g2, &mut rng);
println!("Swap between [{}-{})", p1, p2);
println!("G1: {:?}\nG2: {:?}\n", g1, g2);
println!("C1: {:?}\nC2: {:?}", c1, c2);
for i in 0..g1.len()
{
if i >= p1 && i < p2
{
assert_eq!(g2[i], c1[i]);
assert_eq!(g1[i], c2[i]);
}
else
{
assert_eq!(g1[i], c1[i]);
assert_eq!(g2[i], c2[i]);
}
}
}
}