evolution_ternary/
mutation.rs1use crate::population::{TernaryAgent, SimpleRng};
4
5#[derive(Clone, Debug)]
7pub enum CrossoverMethod {
8 SinglePoint,
10 Uniform,
12}
13
14#[derive(Clone, Debug)]
16pub struct Mutation {
17 pub point_rate: f64,
19 pub crossover: CrossoverMethod,
21 pub crossover_rate: f64,
23}
24
25impl Mutation {
26 pub fn default_rates() -> Self {
28 Self {
29 point_rate: 0.01,
30 crossover: CrossoverMethod::SinglePoint,
31 crossover_rate: 0.7,
32 }
33 }
34
35 pub fn point_mutate(&self, agent: &mut TernaryAgent, rng: &mut SimpleRng) {
38 for v in &mut agent.strategy {
39 if rng.next_f64() < self.point_rate {
40 let current = *v;
42 let new_val = (rng.next_u32() % 2) as u8;
43 *v = if new_val < current { new_val } else { new_val + 1 };
44 if *v > 2 { *v = 0; }
45 debug_assert!(*v <= 2);
46 }
47 }
48 }
49
50 pub fn crossover(&self, parent_a: &TernaryAgent, parent_b: &TernaryAgent, rng: &mut SimpleRng) -> (TernaryAgent, TernaryAgent) {
52 if rng.next_f64() > self.crossover_rate {
53 return (parent_a.clone(), parent_b.clone());
54 }
55 match &self.crossover {
56 CrossoverMethod::SinglePoint => {
57 let point = if parent_a.strategy.is_empty() {
58 0
59 } else {
60 ((rng.next_u64() as usize) % parent_a.strategy.len()).max(1)
61 };
62 let mut child_a = parent_a.clone();
63 let mut child_b = parent_b.clone();
64 for i in point..parent_a.strategy.len() {
65 child_a.strategy[i] = parent_b.strategy[i];
66 child_b.strategy[i] = parent_a.strategy[i];
67 }
68 (child_a, child_b)
69 }
70 CrossoverMethod::Uniform => {
71 let mut child_a = parent_a.clone();
72 let mut child_b = parent_b.clone();
73 for i in 0..parent_a.strategy.len() {
74 if rng.next_f64() < 0.5 {
75 child_a.strategy[i] = parent_b.strategy[i];
76 child_b.strategy[i] = parent_a.strategy[i];
77 }
78 }
79 (child_a, child_b)
80 }
81 }
82 }
83
84 pub fn mutate(&self, agent: &mut TernaryAgent, rng: &mut SimpleRng) {
86 self.point_mutate(agent, rng);
87 }
88}
89
90pub fn autofill_mutate(agent: &mut TernaryAgent, start: usize, rng: &mut SimpleRng) {
93 if agent.strategy.len() < 2 || start >= agent.strategy.len() {
94 return;
95 }
96 let len = agent.strategy.len();
98 if start >= 2 {
99 let diff = (agent.strategy[start - 1] as i32 - agent.strategy[start - 2] as i32).rem_euclid(3);
100 for i in start..len {
101 agent.strategy[i] = (agent.strategy[i - 1] as i32 + diff) as u8 % 3;
102 }
103 } else {
104 for i in start..len {
106 agent.strategy[i] = (rng.next_u32() % 3) as u8;
107 }
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114
115 #[test]
116 fn test_autofill_constant_pattern() {
117 let mut agent = TernaryAgent::new_unchecked(vec![1, 1, 1, 0, 0, 0]);
118 let mut rng = SimpleRng::from_seed(99);
119 autofill_mutate(&mut agent, 3, &mut rng);
120 assert_eq!(agent.strategy[3], 1);
121 assert_eq!(agent.strategy[4], 1);
122 assert_eq!(agent.strategy[5], 1);
123 }
124
125 #[test]
126 fn test_autofill_ascending_pattern() {
127 let mut agent = TernaryAgent::new_unchecked(vec![0, 1, 0, 0, 0, 0]);
128 let mut rng = SimpleRng::from_seed(99);
129 autofill_mutate(&mut agent, 2, &mut rng);
130 assert_eq!(agent.strategy[2], 2); assert_eq!(agent.strategy[3], 0); assert_eq!(agent.strategy[4], 1);
133 assert_eq!(agent.strategy[5], 2);
134 }
135}