use std::collections::HashMap;
use crate::{
genetic::{Children, Parents, ParentsSlice},
operator::{CrossoverOp, GeneticOperator},
random::{random_cut_points, Rng},
};
#[allow(missing_copy_implementations)]
#[derive(Default, Clone, Debug, PartialEq)]
pub struct OrderOneCrossover {}
impl OrderOneCrossover {
pub fn new() -> Self {
OrderOneCrossover {}
}
}
impl GeneticOperator for OrderOneCrossover {
fn name() -> String {
"Order-One-Crossover".to_string()
}
}
impl CrossoverOp<Vec<usize>> for OrderOneCrossover {
fn crossover<R>(&self, parents: Parents<Vec<usize>>, rng: &mut R) -> Children<Vec<usize>>
where
R: Rng + Sized,
{
multi_parents_cyclic_crossover(&parents, order_one_crossover, rng)
}
}
#[allow(missing_copy_implementations)]
#[derive(Default, Clone, Debug, PartialEq)]
pub struct PartiallyMappedCrossover {}
impl PartiallyMappedCrossover {
pub fn new() -> Self {
PartiallyMappedCrossover {}
}
}
impl GeneticOperator for PartiallyMappedCrossover {
fn name() -> String {
"Partially-Mapped-Crossover".to_string()
}
}
impl CrossoverOp<Vec<usize>> for PartiallyMappedCrossover {
fn crossover<R>(&self, parents: Parents<Vec<usize>>, rng: &mut R) -> Children<Vec<usize>>
where
R: Rng + Sized,
{
multi_parents_cyclic_crossover(&parents, partial_mapped_crossover, rng)
}
}
fn multi_parents_cyclic_crossover<'a, FN, R>(
parents: ParentsSlice<'a, Vec<usize>>,
crossover: FN,
rng: &mut R,
) -> Children<Vec<usize>>
where
FN: Fn(&'a [usize], &'a [usize], usize, usize) -> Vec<usize>,
R: Rng + Sized,
{
let parents_size = parents.len();
let genome_length = parents[0].len();
let mut offspring: Vec<Vec<usize>> = Vec::with_capacity(parents_size);
let mut p1_index = 0;
let mut p2_index = 1;
while p1_index < parents_size {
let (cutpoint1, cutpoint2) = random_cut_points(rng, genome_length);
let genome = crossover(&parents[p1_index], &parents[p2_index], cutpoint1, cutpoint2);
offspring.push(genome);
p1_index += 1;
p2_index += 1;
if p2_index >= parents_size {
p2_index = 0;
}
}
offspring
}
fn order_one_crossover(
parent1: &[usize],
parent2: &[usize],
cutpoint1: usize,
cutpoint2: usize,
) -> Vec<usize> {
let genome_length = parent1.len();
let mut genome: Vec<usize> = Vec::with_capacity(genome_length);
let mut p1_slice: Vec<usize> = if cutpoint1 == 0 {
parent1
.iter()
.take(cutpoint2 + 1)
.map(ToOwned::to_owned)
.collect()
} else {
parent1
.iter()
.skip(cutpoint1)
.take(cutpoint2 - cutpoint1 + 1)
.map(ToOwned::to_owned)
.collect()
};
let mut p2_slice: Vec<usize> = Vec::with_capacity(genome_length);
let mut p2_index = (cutpoint2 + 1) % genome_length;
for _ in 0..genome_length {
let p2_genome = parent2[p2_index];
if p1_slice.iter().all(|g| p2_genome != *g) {
p2_slice.push(p2_genome);
}
p2_index += 1;
if p2_index >= genome_length {
p2_index = 0;
}
}
let right_offset = genome_length - cutpoint2 - 1;
for locus in 0..genome_length {
if locus < cutpoint1 {
genome.push(p2_slice.remove(right_offset));
} else if locus > cutpoint2 {
genome.push(p2_slice.remove(0));
} else {
genome.push(p1_slice.remove(0));
}
}
genome
}
fn partial_mapped_crossover(
parent1: &[usize],
parent2: &[usize],
cutpoint1: usize,
cutpoint2: usize,
) -> Vec<usize> {
let genome_length = parent1.len();
let mut genome: Vec<usize> = Vec::with_capacity(genome_length);
let mut result: HashMap<usize, usize> = HashMap::with_capacity(genome_length);
let mut inverse: HashMap<usize, usize> = HashMap::with_capacity(genome_length);
for (i, v2) in parent2.iter().enumerate() {
result.insert(i, *v2);
inverse.insert(*v2, i);
}
for (j, v1) in parent1
.iter()
.enumerate()
.take(cutpoint2 + 1)
.skip(cutpoint1)
{
let orig = result[&j];
result.insert(j, *v1);
let k = inverse[v1];
result.insert(k, orig);
inverse.insert(orig, k);
}
for i in 0..genome_length {
genome.push(result[&i])
}
genome
}
#[cfg(test)]
mod tests {
use super::*;
use galvanic_assert::matchers::*;
#[test]
fn order_one_crossover_cutpoints_3_6() {
let p1 = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
let p2 = vec![9, 3, 7, 8, 2, 6, 5, 1, 4];
let children = order_one_crossover(&p1, &p2, 3, 6);
expect_that!(&children, eq(vec![3, 8, 2, 4, 5, 6, 7, 1, 9]));
let children = order_one_crossover(&p2, &p1, 3, 6);
expect_that!(&children, eq(vec![3, 4, 7, 8, 2, 6, 5, 9, 1]));
}
#[test]
fn order_one_crossover_cutpoints_0_0() {
let p1 = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
let p2 = vec![9, 3, 7, 8, 2, 6, 5, 1, 4];
let children = order_one_crossover(&p1, &p2, 0, 0);
expect_that!(&children, eq(vec![1, 3, 7, 8, 2, 6, 5, 4, 9]));
let children = order_one_crossover(&p2, &p1, 0, 0);
expect_that!(&children, eq(vec![9, 2, 3, 4, 5, 6, 7, 8, 1]));
}
#[test]
fn order_one_crossover_cutpoints_0_8() {
let p1 = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
let p2 = vec![9, 3, 7, 8, 2, 6, 5, 1, 4];
let children = order_one_crossover(&p1, &p2, 0, 8);
expect_that!(&children, eq(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]));
let children = order_one_crossover(&p2, &p1, 0, 8);
expect_that!(&children, eq(vec![9, 3, 7, 8, 2, 6, 5, 1, 4]));
}
#[test]
fn order_one_crossover_cutpoints_1_8() {
let p1 = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
let p2 = vec![9, 3, 7, 8, 2, 6, 5, 1, 4];
let children = order_one_crossover(&p1, &p2, 1, 8);
expect_that!(&children, eq(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]));
let children = order_one_crossover(&p2, &p1, 1, 8);
expect_that!(&children, eq(vec![9, 3, 7, 8, 2, 6, 5, 1, 4]));
}
#[test]
fn order_one_crossover_cutpoints_0_7() {
let p1 = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
let p2 = vec![9, 3, 7, 8, 2, 6, 5, 1, 4];
let children = order_one_crossover(&p1, &p2, 0, 7);
expect_that!(&children, eq(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]));
let children = order_one_crossover(&p2, &p1, 0, 7);
expect_that!(&children, eq(vec![9, 3, 7, 8, 2, 6, 5, 1, 4]));
}
#[test]
fn order_one_crossover_cutpoints_1_7() {
let p1 = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
let p2 = vec![1, 3, 7, 8, 2, 6, 5, 9, 4];
let children = order_one_crossover(&p1, &p2, 1, 7);
expect_that!(&children, eq(vec![9, 2, 3, 4, 5, 6, 7, 8, 1]));
let children = order_one_crossover(&p2, &p1, 1, 7);
expect_that!(&children, eq(vec![4, 3, 7, 8, 2, 6, 5, 9, 1]));
}
#[test]
fn partial_mapped_crossover_cutpoints_3_6() {
let p1 = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
let p2 = vec![9, 3, 7, 8, 2, 6, 5, 1, 4];
let children = partial_mapped_crossover(&p1, &p2, 3, 6);
expect_that!(&children, eq(vec![9, 3, 2, 4, 5, 6, 7, 1, 8]));
let children = partial_mapped_crossover(&p2, &p1, 3, 6);
expect_that!(&children, eq(vec![1, 7, 3, 8, 2, 6, 5, 4, 9]));
}
#[test]
fn partial_mapped_crossover_cutpoints_0_0() {
let p1 = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
let p2 = vec![9, 3, 7, 8, 2, 6, 5, 1, 4];
let children = partial_mapped_crossover(&p1, &p2, 0, 0);
expect_that!(&children, eq(vec![1, 3, 7, 8, 2, 6, 5, 9, 4]));
let children = partial_mapped_crossover(&p2, &p1, 0, 0);
expect_that!(&children, eq(vec![9, 2, 3, 4, 5, 6, 7, 8, 1]));
}
#[test]
fn partial_mapped_crossover_cutpoints_0_8() {
let p1 = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
let p2 = vec![9, 3, 7, 8, 2, 6, 5, 1, 4];
let children = partial_mapped_crossover(&p1, &p2, 0, 8);
expect_that!(&children, eq(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]));
let children = partial_mapped_crossover(&p2, &p1, 0, 8);
expect_that!(&children, eq(vec![9, 3, 7, 8, 2, 6, 5, 1, 4]));
}
#[test]
fn partial_mapped_crossover_cutpoints_1_8() {
let p1 = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
let p2 = vec![9, 3, 7, 8, 2, 6, 5, 1, 4];
let children = partial_mapped_crossover(&p1, &p2, 1, 8);
expect_that!(&children, eq(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]));
let children = partial_mapped_crossover(&p2, &p1, 1, 8);
expect_that!(&children, eq(vec![9, 3, 7, 8, 2, 6, 5, 1, 4]));
}
#[test]
fn partial_mapped_crossover_cutpoints_0_7() {
let p1 = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
let p2 = vec![9, 3, 7, 8, 2, 6, 5, 1, 4];
let children = partial_mapped_crossover(&p1, &p2, 0, 7);
expect_that!(&children, eq(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]));
let children = partial_mapped_crossover(&p2, &p1, 0, 7);
expect_that!(&children, eq(vec![9, 3, 7, 8, 2, 6, 5, 1, 4]));
}
#[test]
fn partial_mapped_crossover_cutpoints_1_7() {
let p1 = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
let p2 = vec![1, 3, 7, 8, 2, 6, 5, 9, 4];
let children = partial_mapped_crossover(&p1, &p2, 1, 7);
expect_that!(&children, eq(vec![1, 2, 3, 4, 5, 6, 7, 8, 9]));
let children = partial_mapped_crossover(&p2, &p1, 1, 7);
expect_that!(&children, eq(vec![1, 3, 7, 8, 2, 6, 5, 9, 4]));
}
}