scirs2_optimize/multi_objective/mutation/
mod.rs

1//! Mutation operators for multi-objective optimization
2//!
3//! Various mutation strategies for maintaining diversity in populations.
4
5use scirs2_core::random::Rng;
6use scirs2_core::random::{Distribution, Normal};
7
8/// Trait for mutation operators
9pub trait MutationOperator {
10    /// Perform mutation on a solution
11    fn mutate(&self, solution: &mut [f64], bounds: &[(f64, f64)]);
12}
13
14/// Polynomial mutation
15#[derive(Debug, Clone)]
16pub struct PolynomialMutation {
17    mutation_probability: f64,
18    distribution_index: f64,
19}
20
21impl PolynomialMutation {
22    pub fn new(mutation_probability: f64, distribution_index: f64) -> Self {
23        Self {
24            mutation_probability,
25            distribution_index,
26        }
27    }
28
29    fn calculate_delta(&self, rng: &mut impl Rng) -> f64 {
30        let u = rng.random::<f64>();
31        if u < 0.5 {
32            (2.0 * u).powf(1.0 / (self.distribution_index + 1.0)) - 1.0
33        } else {
34            1.0 - (2.0 * (1.0 - u)).powf(1.0 / (self.distribution_index + 1.0))
35        }
36    }
37}
38
39impl MutationOperator for PolynomialMutation {
40    fn mutate(&self, solution: &mut [f64], bounds: &[(f64, f64)]) {
41        let mut rng = scirs2_core::random::rng();
42        let n = solution.len();
43
44        for i in 0..n {
45            if rng.random::<f64>() <= self.mutation_probability {
46                let (lower, upper) = bounds[i];
47                let delta = self.calculate_delta(&mut rng);
48                let max_delta = upper - lower;
49
50                solution[i] += delta * max_delta;
51                solution[i] = solution[i].max(lower).min(upper);
52            }
53        }
54    }
55}
56
57/// Gaussian mutation
58#[derive(Debug, Clone)]
59pub struct GaussianMutation {
60    mutation_probability: f64,
61    std_dev: f64,
62}
63
64impl GaussianMutation {
65    pub fn new(mutation_probability: f64, std_dev: f64) -> Self {
66        Self {
67            mutation_probability,
68            std_dev,
69        }
70    }
71}
72
73impl MutationOperator for GaussianMutation {
74    fn mutate(&self, solution: &mut [f64], bounds: &[(f64, f64)]) {
75        let mut rng = scirs2_core::random::rng();
76        let normal = Normal::new(0.0, self.std_dev).unwrap();
77
78        for i in 0..solution.len() {
79            if rng.random::<f64>() <= self.mutation_probability {
80                let (lower, upper) = bounds[i];
81                let perturbation = normal.sample(&mut rng);
82
83                solution[i] += perturbation;
84                solution[i] = solution[i].max(lower).min(upper);
85            }
86        }
87    }
88}
89
90/// Uniform mutation
91#[derive(Debug, Clone)]
92pub struct UniformMutation {
93    mutation_probability: f64,
94}
95
96impl UniformMutation {
97    pub fn new(mutation_probability: f64) -> Self {
98        Self {
99            mutation_probability,
100        }
101    }
102}
103
104impl MutationOperator for UniformMutation {
105    fn mutate(&self, solution: &mut [f64], bounds: &[(f64, f64)]) {
106        let mut rng = scirs2_core::random::rng();
107
108        for i in 0..solution.len() {
109            if rng.random::<f64>() <= self.mutation_probability {
110                let (lower, upper) = bounds[i];
111                solution[i] = rng.gen_range(lower..upper);
112            }
113        }
114    }
115}