scirs2_optimize/multi_objective/crossover/
mod.rs

1//! Crossover operators for multi-objective optimization
2//!
3//! Various crossover strategies for generating offspring solutions.
4
5use scirs2_core::random::Rng;
6
7/// Trait for crossover operators
8pub trait CrossoverOperator {
9    /// Perform crossover between two parents
10    fn crossover(&self, parent1: &[f64], parent2: &[f64]) -> (Vec<f64>, Vec<f64>);
11}
12
13/// Simulated Binary Crossover (SBX)
14#[derive(Debug, Clone)]
15pub struct SimulatedBinaryCrossover {
16    crossover_probability: f64,
17    distribution_index: f64,
18}
19
20/// Simulated Binary Crossover (SBX) - Alias for compatibility
21pub type SBX = SimulatedBinaryCrossover;
22
23impl SimulatedBinaryCrossover {
24    pub fn new(distribution_index: f64, crossover_probability: f64) -> Self {
25        Self {
26            crossover_probability,
27            distribution_index,
28        }
29    }
30}
31
32impl CrossoverOperator for SimulatedBinaryCrossover {
33    fn crossover(&self, parent1: &[f64], parent2: &[f64]) -> (Vec<f64>, Vec<f64>) {
34        let mut rng = scirs2_core::random::rng();
35        let n = parent1.len();
36        let mut child1 = vec![0.0; n];
37        let mut child2 = vec![0.0; n];
38
39        if rng.random::<f64>() <= self.crossover_probability {
40            for i in 0..n {
41                if rng.random::<f64>() <= 0.5 {
42                    let beta = self.calculate_beta(&mut rng);
43                    child1[i] = 0.5 * ((1.0 + beta) * parent1[i] + (1.0 - beta) * parent2[i]);
44                    child2[i] = 0.5 * ((1.0 - beta) * parent1[i] + (1.0 + beta) * parent2[i]);
45                } else {
46                    child1[i] = parent1[i];
47                    child2[i] = parent2[i];
48                }
49            }
50        } else {
51            child1 = parent1.to_vec();
52            child2 = parent2.to_vec();
53        }
54
55        (child1, child2)
56    }
57}
58
59impl SimulatedBinaryCrossover {
60    fn calculate_beta(&self, rng: &mut impl Rng) -> f64 {
61        let u = rng.random::<f64>();
62        if u <= 0.5 {
63            (2.0 * u).powf(1.0 / (self.distribution_index + 1.0))
64        } else {
65            (1.0 / (2.0 * (1.0 - u))).powf(1.0 / (self.distribution_index + 1.0))
66        }
67    }
68}
69
70/// Uniform crossover
71#[derive(Debug, Clone)]
72pub struct UniformCrossover {
73    crossover_probability: f64,
74}
75
76impl UniformCrossover {
77    pub fn new(crossover_probability: f64) -> Self {
78        Self {
79            crossover_probability,
80        }
81    }
82}
83
84impl CrossoverOperator for UniformCrossover {
85    fn crossover(&self, parent1: &[f64], parent2: &[f64]) -> (Vec<f64>, Vec<f64>) {
86        let mut rng = scirs2_core::random::rng();
87        let n = parent1.len();
88        let mut child1 = vec![0.0; n];
89        let mut child2 = vec![0.0; n];
90
91        if rng.random::<f64>() <= self.crossover_probability {
92            for i in 0..n {
93                if rng.gen_bool(0.5) {
94                    child1[i] = parent1[i];
95                    child2[i] = parent2[i];
96                } else {
97                    child1[i] = parent2[i];
98                    child2[i] = parent1[i];
99                }
100            }
101        } else {
102            child1 = parent1.to_vec();
103            child2 = parent2.to_vec();
104        }
105
106        (child1, child2)
107    }
108}