use crate::ga::individual::IndividualTrait;
pub trait ReplacementOperator<IndividualT: IndividualTrait> {
fn apply(&self, population: Vec<IndividualT>, children: Vec<IndividualT>) -> Vec<IndividualT>;
fn requires_children_fitness(&self) -> bool {
true
}
}
pub struct BothParents;
impl BothParents {
pub fn new() -> Self {
Self
}
}
impl<IndividualT: IndividualTrait> ReplacementOperator<IndividualT> for BothParents {
#[inline(always)]
fn apply(&self, _population: Vec<IndividualT>, children: Vec<IndividualT>) -> Vec<IndividualT> {
children
}
#[inline(always)]
fn requires_children_fitness(&self) -> bool {
false
}
}
pub struct Noop;
impl Noop {
pub fn new() -> Self {
Self
}
}
impl<IndividualT: IndividualTrait> ReplacementOperator<IndividualT> for Noop {
#[inline(always)]
fn apply(&self, population: Vec<IndividualT>, _children: Vec<IndividualT>) -> Vec<IndividualT> {
population
}
#[inline(always)]
fn requires_children_fitness(&self) -> bool {
false
}
}
pub struct WeakParent;
impl WeakParent {
pub fn new() -> Self {
Self
}
}
impl<IndividualT: IndividualTrait> ReplacementOperator<IndividualT> for WeakParent {
fn apply(&self, mut population: Vec<IndividualT>, mut children: Vec<IndividualT>) -> Vec<IndividualT> {
debug_assert_eq!(
population.len(),
children.len(),
"Population and children must be of the same size"
);
debug_assert!(population.len() % 2 == 0, "Population size must be even");
for i in (0..(population.len() - 1)).step_by(2) {
if population[i] < population[i + 1] {
population.swap(i, i + 1);
}
if children[i] < children[i + 1] {
children.swap(i, i + 1);
}
if children[i] > population[i] {
population.swap(i, i + 1);
std::mem::swap(&mut children[i], &mut population[i]);
if children[i + 1] > population[i + 1] {
std::mem::swap(&mut children[i + 1], &mut population[i + 1]);
}
} else if children[i] > population[i + 1] {
std::mem::swap(&mut children[i], &mut population[i + 1]);
}
}
population
}
}
#[cfg(test)]
mod tests {
use crate::ga::Individual;
use super::{BothParents, Noop, ReplacementOperator, WeakParent};
#[test]
fn noop_has_new_method() {
let _ = Noop::new();
}
#[test]
fn both_parents_has_new_method() {
let _ = BothParents::new();
}
#[test]
fn weak_parent_swaps_when_children_are_stronger() {
let parents = vec![
Individual {
chromosome: 0.0,
fitness: 60.0,
},
Individual {
chromosome: 0.0,
fitness: 40.0,
},
];
let children = vec![
Individual {
chromosome: 0.0,
fitness: 120.0,
},
Individual {
chromosome: 0.0,
fitness: 100.0,
},
];
let children_clone = children.clone();
let result = WeakParent::new().apply(parents, children);
assert_eq!(result, children_clone);
}
#[test]
fn weak_parent_does_not_swap_when_parents_are_stronger() {
let parents = vec![
Individual {
chromosome: 0.0,
fitness: 60.0,
},
Individual {
chromosome: 0.0,
fitness: 40.0,
},
];
let children = vec![
Individual {
chromosome: 0.0,
fitness: 10.0,
},
Individual {
chromosome: 0.0,
fitness: 12.0,
},
];
let parents_clone = parents.clone();
let result = WeakParent::new().apply(parents, children);
assert_eq!(result, parents_clone);
}
#[test]
fn weak_parent_cross_swaps_child_1() {
let parents = vec![
Individual {
chromosome: 0.0,
fitness: 60.0,
},
Individual {
chromosome: 0.0,
fitness: 40.0,
},
];
let children = vec![
Individual {
chromosome: 0.0,
fitness: 50.0,
},
Individual {
chromosome: 0.0,
fitness: 30.0,
},
];
let expected_result = vec![
Individual {
chromosome: 0.0,
fitness: 60.0,
},
Individual {
chromosome: 0.0,
fitness: 50.0,
},
];
let result = WeakParent::new().apply(parents, children);
assert_eq!(result, expected_result);
}
#[test]
fn weak_parent_cross_swaps_child_2() {
let parents = vec![
Individual {
chromosome: 0.0,
fitness: 60.0,
},
Individual {
chromosome: 0.0,
fitness: 40.0,
},
];
let children = vec![
Individual {
chromosome: 0.0,
fitness: 30.0,
},
Individual {
chromosome: 0.0,
fitness: 50.0,
},
];
let expected_result = vec![
Individual {
chromosome: 0.0,
fitness: 60.0,
},
Individual {
chromosome: 0.0,
fitness: 50.0,
},
];
let result = WeakParent::new().apply(parents, children);
assert_eq!(result, expected_result);
}
#[test]
fn weak_parent_takes_two_best() {
let parents = vec![
Individual {
chromosome: 0.0,
fitness: 60.0,
},
Individual {
chromosome: 0.0,
fitness: 40.0,
},
];
let children = vec![
Individual {
chromosome: 0.0,
fitness: 70.0,
},
Individual {
chromosome: 0.0,
fitness: 50.0,
},
];
let expected_result = vec![
Individual {
chromosome: 0.0,
fitness: 70.0,
},
Individual {
chromosome: 0.0,
fitness: 60.0,
},
];
let result = WeakParent::new().apply(parents, children);
assert_eq!(result, expected_result);
}
}