use super::constants::CROSSOVER_RATE;
use crate::chromosome::Chromosome;
use rand::rngs::StdRng;
use rand::Rng;
pub fn crossover(
rng: &mut StdRng,
individual1: &Chromosome,
individual2: &Chromosome,
) -> (Chromosome, Chromosome) {
let mut new_genes1 = Vec::new();
let mut new_genes2 = Vec::new();
let zipped_genes = individual1.genes.iter().zip(individual2.genes.iter());
for (gene1, gene2) in zipped_genes {
if rng.gen_range(0.0..1.0) <= CROSSOVER_RATE {
new_genes1.push(*gene2);
new_genes2.push(*gene1);
} else {
new_genes1.push(*gene1);
new_genes2.push(*gene2);
}
}
let mut new_individual1 = individual1.clone();
let mut new_individual2 = individual2.clone();
new_individual1.genes = new_genes1;
new_individual2.genes = new_genes2;
(new_individual1, new_individual2)
}
#[cfg(test)]
mod tests {
use super::*;
use rand::SeedableRng;
fn create_test_chromosome(genes: Vec<f64>) -> Chromosome {
Chromosome {
genes,
fitness: 0.0,
vdw: 0.0,
elec: 0.0,
desolv: 0.0,
air: 0.0,
restraint_penalty: 0.0,
rmsd: 0.0,
fnat: 0.0,
}
}
#[test]
fn test_crossover_produces_two_offspring() {
let mut rng = StdRng::seed_from_u64(42);
let parent1 = create_test_chromosome(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
let parent2 = create_test_chromosome(vec![7.0, 8.0, 9.0, 10.0, 11.0, 12.0]);
let (offspring1, offspring2) = crossover(&mut rng, &parent1, &parent2);
assert_eq!(offspring1.genes.len(), 6);
assert_eq!(offspring2.genes.len(), 6);
}
#[test]
fn test_crossover_preserves_gene_count() {
let mut rng = StdRng::seed_from_u64(42);
let parent1 = create_test_chromosome(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
let parent2 = create_test_chromosome(vec![7.0, 8.0, 9.0, 10.0, 11.0, 12.0]);
let (offspring1, offspring2) = crossover(&mut rng, &parent1, &parent2);
assert_eq!(offspring1.genes.len(), parent1.genes.len());
assert_eq!(offspring2.genes.len(), parent2.genes.len());
}
#[test]
fn test_crossover_genes_come_from_parents() {
let mut rng = StdRng::seed_from_u64(42);
let parent1 = create_test_chromosome(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
let parent2 = create_test_chromosome(vec![7.0, 8.0, 9.0, 10.0, 11.0, 12.0]);
let (offspring1, offspring2) = crossover(&mut rng, &parent1, &parent2);
for i in 0..6 {
let gene1 = offspring1.genes[i];
let gene2 = offspring2.genes[i];
let from_p1 = gene1 == parent1.genes[i] || gene1 == parent2.genes[i];
let from_p2 = gene2 == parent1.genes[i] || gene2 == parent2.genes[i];
assert!(from_p1, "Offspring1 gene {} not from parents", i);
assert!(from_p2, "Offspring2 gene {} not from parents", i);
}
}
#[test]
fn test_crossover_swaps_genes() {
let mut rng = StdRng::seed_from_u64(42);
let parent1 = create_test_chromosome(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
let parent2 = create_test_chromosome(vec![7.0, 8.0, 9.0, 10.0, 11.0, 12.0]);
let (offspring1, offspring2) = crossover(&mut rng, &parent1, &parent2);
let mut swapped_count = 0;
for i in 0..6 {
if offspring1.genes[i] == parent2.genes[i] && offspring2.genes[i] == parent1.genes[i] {
swapped_count += 1;
}
}
assert!(
swapped_count > 0,
"Expected at least one gene swap with CROSSOVER_RATE = {}",
CROSSOVER_RATE
);
}
#[test]
fn test_crossover_offspring_differ_from_parents() {
let mut rng = StdRng::seed_from_u64(42);
let parent1 = create_test_chromosome(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
let parent2 = create_test_chromosome(vec![7.0, 8.0, 9.0, 10.0, 11.0, 12.0]);
let (offspring1, offspring2) = crossover(&mut rng, &parent1, &parent2);
let offspring1_same = offspring1.genes == parent1.genes;
let offspring2_same = offspring2.genes == parent2.genes;
assert!(
!offspring1_same || !offspring2_same,
"At least one offspring should differ from its parent"
);
}
#[test]
fn test_crossover_complementary_swap() {
let mut rng = StdRng::seed_from_u64(42);
let parent1 = create_test_chromosome(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
let parent2 = create_test_chromosome(vec![7.0, 8.0, 9.0, 10.0, 11.0, 12.0]);
let (offspring1, offspring2) = crossover(&mut rng, &parent1, &parent2);
for i in 0..6 {
if offspring1.genes[i] == parent2.genes[i] {
assert_eq!(
offspring2.genes[i], parent1.genes[i],
"Complementary swap failed at position {}",
i
);
} else if offspring1.genes[i] == parent1.genes[i] {
assert_eq!(
offspring2.genes[i], parent2.genes[i],
"Complementary swap failed at position {}",
i
);
}
}
}
#[test]
fn test_crossover_preserves_other_fields() {
let mut rng = StdRng::seed_from_u64(42);
let mut parent1 = create_test_chromosome(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
parent1.fitness = 100.0;
parent1.vdw = 10.0;
let parent2 = create_test_chromosome(vec![7.0, 8.0, 9.0, 10.0, 11.0, 12.0]);
let (offspring1, offspring2) = crossover(&mut rng, &parent1, &parent2);
assert_eq!(offspring1.fitness, parent1.fitness);
assert_eq!(offspring2.fitness, parent2.fitness);
}
}