use ndarray::{Array1, Axis, concatenate, s};
use crate::operators::CrossoverOperator;
use crate::random::RandomGenerator;
#[derive(Debug, Clone)]
pub struct SinglePointBinaryCrossover;
impl SinglePointBinaryCrossover {
pub fn new() -> Self {
Self {}
}
}
impl CrossoverOperator for SinglePointBinaryCrossover {
fn crossover(
&self,
parent_a: &Array1<f64>,
parent_b: &Array1<f64>,
rng: &mut impl RandomGenerator,
) -> (Array1<f64>, Array1<f64>) {
let num_genes = parent_a.len();
assert_eq!(
num_genes,
parent_b.len(),
"Parents must have the same number of genes"
);
if num_genes == 0 {
return (Array1::default(0), Array1::default(0));
}
let crossover_point = rng.gen_range_usize(1, num_genes);
let offspring_a = concatenate![
Axis(0),
parent_a.slice(s![..crossover_point]),
parent_b.slice(s![crossover_point..])
];
let offspring_b = concatenate![
Axis(0),
parent_b.slice(s![..crossover_point]),
parent_a.slice(s![crossover_point..])
];
(offspring_a, offspring_b)
}
}
#[cfg(test)]
mod tests {
use super::*;
use ndarray::Array1;
use ndarray::array;
use crate::random::{RandomGenerator, TestDummyRng};
struct ControlledFakeRandomGenerator {
responses: Vec<usize>,
index: usize,
dummy: TestDummyRng,
}
impl ControlledFakeRandomGenerator {
fn new(responses: Vec<usize>) -> Self {
Self {
responses,
index: 0,
dummy: TestDummyRng,
}
}
}
impl RandomGenerator for ControlledFakeRandomGenerator {
type R = TestDummyRng;
fn rng(&mut self) -> &mut TestDummyRng {
&mut self.dummy
}
fn gen_range_usize(&mut self, _min: usize, _max: usize) -> usize {
let resp = self.responses[self.index];
self.index += 1;
resp
}
}
#[test]
fn test_single_point_binary_crossover_controlled() {
let parent_a: Array1<f64> = array![0.0, 1.0, 1.0, 0.0, 1.0];
let parent_b: Array1<f64> = array![1.0, 0.0, 0.0, 1.0, 0.0];
let crossover_operator = SinglePointBinaryCrossover::new();
let mut fake_rng = ControlledFakeRandomGenerator::new(vec![3]);
let (offspring_a, offspring_b) =
crossover_operator.crossover(&parent_a, &parent_b, &mut fake_rng);
let expected_offspring_a = array![0.0, 1.0, 1.0, 1.0, 0.0];
let expected_offspring_b = array![1.0, 0.0, 0.0, 0.0, 1.0];
assert_eq!(
offspring_a, expected_offspring_a,
"Offspring A did not match the expected output"
);
assert_eq!(
offspring_b, expected_offspring_b,
"Offspring B did not match the expected output"
);
}
}