use std::collections::{HashMap, HashSet};
use std::hash::Hash;
use std::mem::swap;
use rand::prelude::IteratorRandom;
use rand::Rng;
use smallvec::SmallVec;
pub fn crossover_pmx<T: Copy + Hash + Default + Eq>(s1: &mut [T], s2: &mut [T]) {
let mut r = rand::thread_rng();
let st = r.gen_range(0..s1.len());
let en = r.gen_range(st..s1.len());
let c1 = crossover_pmx_single(s1, s2, st, en);
let c2 = crossover_pmx_single(s2, s1, st, en);
s1.copy_from_slice(&c1);
s2.copy_from_slice(&c2);
}
pub fn crossover_pmx_single<T: Copy + Hash + Default + Eq>(
s1: &[T],
s2: &[T],
st: usize,
en: usize,
) -> Vec<T> {
if s1.is_empty() {
return vec![];
}
let mut c1 = vec![Default::default(); s1.len()];
let mut m: HashMap<T, T> = HashMap::new();
for i in st..=en {
c1[i] = s1[i]; m.entry(s1[i]).or_insert(s2[i]); }
for i in (0..st).chain((en + 1)..s1.len()) {
let mut ins = s2[i];
let mut count = 0;
while let Some(&next) = m.get(&ins) {
ins = next;
count += 1;
if count > s1.len() {
ins = s2[i];
break; }
}
c1[i] = ins;
}
c1
}
pub fn crossover_order<T: Copy + Hash + Default + Eq>(s1: &mut [T], s2: &mut [T]) {
let mut r = rand::thread_rng();
let st = r.gen_range(0..s1.len());
let en = r.gen_range(st..s1.len());
let c1 = crossover_order_single(s1, s2, st, en);
let c2 = crossover_order_single(s2, s1, st, en);
s1.copy_from_slice(&c1);
s2.copy_from_slice(&c2);
}
pub fn crossover_order_single<T: Copy + Hash + Default + Eq>(
s1: &[T],
s2: &[T],
st: usize,
en: usize,
) -> Vec<T> {
if s1.is_empty() {
return vec![];
}
let mut c1 = vec![Default::default(); s1.len()];
let mut m: HashSet<T> = HashSet::new();
for i in st..=en {
c1[i] = s1[i]; m.insert(s1[i]); }
let mut cur_idx = (en + 1) % c1.len();
for i in 0..s2.len() {
if cur_idx == st {
break;
}
let v = s2[(en + 1 + i) % c1.len()];
if m.contains(&v) {
continue;
}
c1[cur_idx] = v;
cur_idx = (cur_idx + 1) % c1.len();
}
for _ in 0..s2.len() {
if cur_idx == st {
break;
}
c1[cur_idx] = s2[cur_idx];
cur_idx = (cur_idx + 1) % c1.len();
}
c1
}
pub fn crossover_cycle<T: Copy + Hash + Default + Eq>(s1: &mut [T], s2: &mut [T]) {
let mut c1: Vec<T> = vec![Default::default(); s1.len()];
let mut c2: Vec<T> = vec![Default::default(); s1.len()];
let mut m: HashMap<T, usize> = HashMap::new();
for (i, v) in s1.iter().enumerate() {
m.entry(*v).or_insert(i);
}
let mut seen = vec![false; s1.len()];
for i in 0..s1.len() {
if seen[i] {
continue;
}
let mut idx = i;
while !seen[idx] {
c1[idx] = s1[idx];
c2[idx] = s2[idx];
seen[idx] = true;
if let Some(&next) = m.get(&s2[idx]) {
idx = next; }
}
swap(&mut c1, &mut c2); }
s1.copy_from_slice(&c2);
s2.copy_from_slice(&c1);
}
pub fn crossover_kpx<T>(s1: &mut [T], s2: &mut [T], k: usize) {
let mut r = rand::thread_rng();
let xpoints = (0..s1.len().min(s2.len())).choose_multiple(&mut r, k);
crossover_kpx_pts(s1, s2, &xpoints);
}
pub fn crossover_kpx_pts<T>(s1: &mut [T], s2: &mut [T], xpoints: &[usize]) {
let mut xpoints: SmallVec<[usize; 4]> = SmallVec::from_slice(xpoints);
let min = s1.len().min(s2.len());
xpoints.push(min);
xpoints.sort_unstable();
for &[st, en] in xpoints.array_chunks::<2>() {
for i in st..en {
swap(&mut s1[i], &mut s2[i]);
}
}
}
pub fn crossover_ux<T>(s1: &mut [T], s2: &mut [T]) {
let mut r = rand::thread_rng();
crossover_ux_rng(s1, s2, &mut r);
}
pub fn crossover_ux_rng<T, R: Rng + ?Sized>(s1: &mut [T], s2: &mut [T], r: &mut R) {
let min = s1.len().min(s2.len());
for i in 0..min {
if r.gen::<bool>() {
swap(&mut s1[i], &mut s2[i]);
}
}
}
pub fn crossover_arith_alpha(s1: &mut [f64], s2: &mut [f64], alpha: f64) {
let min = s1.len().min(s2.len());
for i in 0..min {
let c1 = alpha * s1[i] + (1.0 - alpha) * s2[i];
let c2 = alpha * s2[i] + (1.0 - alpha) * s1[i];
(s1[i], s2[i]) = (c1, c2);
}
}
pub fn crossover_arith(s1: &mut [f64], s2: &mut [f64]) {
let mut r = rand::thread_rng();
crossover_arith_alpha(s1, s2, r.gen());
}
pub fn crossover_blx(s1: &mut [f64], s2: &mut [f64], alpha: f64) {
let mut r = rand::thread_rng();
let min = s1.len().min(s2.len());
for i in 0..min {
let x = s1[i].min(s2[i]);
let y = s1[i].max(s2[i]);
let dist = y - x;
let left = x - dist * alpha;
let right = y + dist * alpha;
s1[i] = r.gen_range(left..=right);
s2[i] = r.gen_range(left..=right);
}
}
#[cfg(test)]
mod tests {
use rand::rngs::mock::StepRng;
use super::*;
use crate::ops::util::{str_to_vec, vec_to_str};
#[test]
fn test_crossover_pmx() {
let a: [i32; 0] = [];
let b: [i32; 0] = [];
assert_eq!(crossover_pmx_single(&a, &b, 0, 0), []);
let a = [1];
let b = [1];
assert_eq!(crossover_pmx_single(&a, &b, 0, 0), [1]);
let a = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let b = [9, 3, 7, 8, 2, 6, 5, 1, 4];
assert_eq!(crossover_pmx_single(&a, &b, 3, 6), [9, 3, 2, 4, 5, 6, 7, 1, 8]);
let a = str_to_vec("abcdefghi");
let b = str_to_vec("icghbfead");
assert_eq!(vec_to_str(&crossover_pmx_single(&a, &b, 3, 6)), "icbdefgah");
let a = [1, 1, 1, 1, 1];
let b = [1, 1, 1, 1, 1];
assert_eq!(crossover_pmx_single(&a, &b, 1, 3), [1, 1, 1, 1, 1]);
let a = [1, 2, 3, 1, 1];
let b = [1, 1, 4, 5, 6];
assert_eq!(crossover_pmx_single(&a, &b, 1, 3), [5, 2, 3, 1, 6]);
}
#[test]
fn test_crossover_order() {
let a: [i32; 0] = [];
let b: [i32; 0] = [];
assert_eq!(crossover_order_single(&a, &b, 0, 0), []);
let a = [1];
let b = [1];
assert_eq!(crossover_order_single(&a, &b, 0, 0), [1]);
let a = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let b = [9, 3, 7, 8, 2, 6, 5, 1, 4];
assert_eq!(crossover_order_single(&a, &b, 3, 6), [3, 8, 2, 4, 5, 6, 7, 1, 9]);
let a = str_to_vec("abcdefghi");
let b = str_to_vec("icghbfead");
assert_eq!(vec_to_str(&crossover_order_single(&a, &b, 3, 6)), "chbdefgai");
let a = [1, 1, 1, 1, 1];
let b = [1, 1, 1, 1, 1];
assert_eq!(crossover_order_single(&a, &b, 1, 3), [1, 1, 1, 1, 1]);
let a = [1, 2, 3, 1, 1];
let b = [1, 1, 4, 5, 6];
assert_eq!(crossover_order_single(&a, &b, 1, 3), [4, 2, 3, 1, 6]);
}
#[test]
fn test_crossover_cycle() {
let mut a: [i32; 0] = [];
let mut b: [i32; 0] = [];
crossover_cycle(&mut a, &mut b);
assert_eq!(a, []);
assert_eq!(b, []);
let mut a = [1];
let mut b = [1];
crossover_cycle(&mut a, &mut b);
assert_eq!(a, [1]);
assert_eq!(b, [1]);
let mut a = [1];
let mut b = [2];
crossover_cycle(&mut a, &mut b);
assert_eq!(a, [1]);
assert_eq!(b, [2]);
let mut a = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let mut b = [9, 3, 7, 8, 2, 6, 5, 1, 4];
crossover_cycle(&mut a, &mut b);
assert_eq!(a, [1, 3, 7, 4, 2, 6, 5, 8, 9]);
assert_eq!(b, [9, 2, 3, 8, 5, 6, 7, 1, 4]);
let mut a = str_to_vec("abcdefghi");
let mut b = str_to_vec("icghbfead");
crossover_cycle(&mut a, &mut b);
assert_eq!(vec_to_str(&a), "acgdbfehi");
assert_eq!(vec_to_str(&b), "ibchefgad");
let mut a = [1, 1, 1, 1, 1];
let mut b = [1, 1, 1, 1, 1];
crossover_cycle(&mut a, &mut b);
assert_eq!(a, [1, 1, 1, 1, 1]);
assert_eq!(b, [1, 1, 1, 1, 1]);
let mut a = [1, 2, 3, 1, 1];
let mut b = [1, 1, 4, 5, 6];
crossover_cycle(&mut a, &mut b);
assert_eq!(a, [1, 1, 3, 5, 1]);
assert_eq!(b, [1, 2, 4, 1, 6]);
}
#[test]
fn test_crossover_1px() {
let mut a = str_to_vec("abcd");
let mut b = str_to_vec("wxyz");
crossover_kpx_pts(&mut a, &mut b, &[3]);
assert_eq!(vec_to_str(&a), "abcz");
assert_eq!(vec_to_str(&b), "wxyd");
}
#[test]
fn test_crossover_2px() {
let mut a = str_to_vec("abcd");
let mut b = str_to_vec("wxyz");
crossover_kpx_pts(&mut a, &mut b, &[1, 2]);
assert_eq!(vec_to_str(&a), "axcd");
assert_eq!(vec_to_str(&b), "wbyz");
}
#[test]
fn test_crossover_ux() {
let mut r = StepRng::new(1 << 31, 1 << 31);
let mut a = str_to_vec("abcd");
let mut b = str_to_vec("wxyz");
crossover_ux_rng(&mut a, &mut b, &mut r);
assert_eq!(vec_to_str(&a), "wbyd");
assert_eq!(vec_to_str(&b), "axcz");
}
}