radiate_alters/crossovers/
simulated_binary.rs1use radiate_core::{
2 AlterResult, BoundedGene, Chromosome, Crossover, Gene, Rate, Valid, random_provider,
3};
4use radiate_utils::Float;
5
6const NAME: &str = "sbx_crossover";
7
8pub struct SimulatedBinaryCrossover {
9 crossover_rate: Rate,
10 contiguty: f32,
11}
12
13impl SimulatedBinaryCrossover {
14 pub fn new(crossover_rate: impl Into<Rate>, contiguty: f32) -> Self {
15 let crossover_rate = crossover_rate.into();
16 if !crossover_rate.is_valid() {
17 panic!("Rate {crossover_rate:?} is not valid. Must be between 0.0 and 1.0",);
18 }
19 Self {
20 contiguty,
21 crossover_rate,
22 }
23 }
24}
25
26impl<A, G, C> Crossover<C> for SimulatedBinaryCrossover
27where
28 A: Float,
29 G: Gene<Allele = A> + BoundedGene,
30 C: Chromosome<Gene = G>,
31{
32 fn name(&self) -> String {
33 NAME.to_string()
34 }
35
36 fn rate(&self) -> Rate {
37 self.crossover_rate.clone()
38 }
39
40 #[inline]
41 fn cross_chromosomes(&self, chrom_one: &mut C, chrom_two: &mut C, _: f32) -> AlterResult {
42 let length = std::cmp::min(chrom_one.len(), chrom_two.len());
43
44 if length < 2 {
45 return AlterResult::empty();
46 }
47
48 let mut count = 0;
49
50 random_provider::with_rng(|rand| {
51 let one_slice = chrom_one.as_mut_slice();
52 let two_slice = chrom_two.as_slice();
53 for i in 0..length {
54 if rand.bool(0.5) {
55 let u = rand.random::<f32>();
56 let beta = A::from(if u <= 0.5 {
57 (2.0 * u).powf(1.0 / (self.contiguty + 1.0))
58 } else {
59 (0.5 / (1.0 - u)).powf(1.0 / (self.contiguty + 1.0))
60 })
61 .unwrap();
62
63 let v1 = one_slice[i].allele().clone();
64 let v2 = two_slice[i].allele().clone();
65
66 let v = if rand.bool(0.5) {
67 ((v1 - v2) * A::HALF) - (beta * A::HALF * (v1 - v2).abs())
68 } else {
69 ((v1 - v2) * A::HALF) + (beta * A::HALF * (v1 - v2).abs())
70 };
71
72 let (one_min, one_max) = one_slice[i].bounds();
73 let new_gene = v.clamp(*one_min, *one_max);
74
75 count += 1;
76
77 *one_slice[i].allele_mut() = new_gene;
78 }
79 }
80 });
81
82 AlterResult::from(count)
83 }
84}