wafrift_evolution/evolution/crossover/
mutation.rs1use crate::evolution::{Chromosome, GenePool};
2use crate::lineage::MutationOp;
3use rand::Rng;
4
5pub fn mutate_with_log(
7 chromosome: &mut Chromosome,
8 gene_pool: &GenePool,
9 mutation_rate: f64,
10 rng: &mut impl Rng,
11) -> Vec<MutationOp> {
12 let mut log = Vec::new();
13 for gene in &mut chromosome.genes {
14 if rng.gen_bool(mutation_rate)
15 && let Some(value) = gene_pool.random_value(&gene.0, rng)
16 && value != gene.1
17 {
18 log.push(MutationOp {
19 gene_name: gene.0.clone(),
20 from: std::mem::replace(&mut gene.1, value.clone()),
21 to: value,
22 operator: "value_mutation".into(),
23 });
24 }
25 }
26 log
27}
28
29pub fn mutate(
31 chromosome: &mut Chromosome,
32 gene_pool: &GenePool,
33 mutation_rate: f64,
34 rng: &mut impl Rng,
35) {
36 let _ = mutate_with_log(chromosome, gene_pool, mutation_rate, rng);
37}
38
39pub fn structural_add_mutation(
41 chromosome: &mut Chromosome,
42 gene_pool: &GenePool,
43 add_rate: f64,
44 rng: &mut impl Rng,
45) {
46 let pool_names: Vec<&str> = gene_pool.gene_names();
47 let missing_names: Vec<&str> = pool_names
48 .into_iter()
49 .filter(|name| !chromosome.has_gene(name))
50 .collect();
51
52 if !missing_names.is_empty() && rng.gen_bool(add_rate) {
53 let name = missing_names[rng.gen_range(0..missing_names.len())];
54 if let Some(value) = gene_pool.random_value(name, rng) {
55 chromosome.genes.push((name.to_string(), value));
56 }
57 }
58}
59
60pub const ESSENTIAL_GENES: &[&str] = &["encoding"];
62
63pub fn structural_remove_mutation(
65 chromosome: &mut Chromosome,
66 remove_rate: f64,
67 min_genes: usize,
68 rng: &mut impl Rng,
69) {
70 if chromosome.genes.len() > min_genes && rng.gen_bool(remove_rate) {
71 let removable: Vec<usize> = chromosome
72 .genes
73 .iter()
74 .enumerate()
75 .filter(|(_, (name, _))| !ESSENTIAL_GENES.contains(&name.as_str()))
76 .map(|(i, _)| i)
77 .collect();
78
79 if !removable.is_empty() {
80 let idx = removable[rng.gen_range(0..removable.len())];
81 chromosome.genes.remove(idx);
82 }
83 }
84}
85
86pub fn swap_mutation(chromosome: &mut Chromosome, swap_rate: f64, rng: &mut impl Rng) {
88 if chromosome.genes.len() < 2 || !rng.gen_bool(swap_rate) {
89 return;
90 }
91 let idx_a = rng.gen_range(0..chromosome.genes.len());
92 let idx_b = rng.gen_range(0..chromosome.genes.len());
93 if idx_a != idx_b {
94 chromosome.genes.swap(idx_a, idx_b);
95 }
96}
97
98pub fn scramble_mutation(chromosome: &mut Chromosome, scramble_rate: f64, rng: &mut impl Rng) {
100 if chromosome.genes.len() < 3 || !rng.gen_bool(scramble_rate) {
101 return;
102 }
103 let start = rng.gen_range(0..chromosome.genes.len() - 1);
104 let end = rng.gen_range(start + 1..chromosome.genes.len());
105 for i in (start + 1..end).rev() {
106 let j = rng.gen_range(start..=i);
107 chromosome.genes.swap(i, j);
108 }
109}
110
111pub fn comprehensive_mutate(
113 chromosome: &mut Chromosome,
114 gene_pool: &GenePool,
115 value_mutation_rate: f64,
116 structural_add_rate: f64,
117 structural_remove_rate: f64,
118 min_genes: usize,
119 rng: &mut impl Rng,
120) -> Vec<MutationOp> {
121 let log = mutate_with_log(chromosome, gene_pool, value_mutation_rate, rng);
122 structural_add_mutation(chromosome, gene_pool, structural_add_rate, rng);
123 structural_remove_mutation(chromosome, structural_remove_rate, min_genes, rng);
124 swap_mutation(chromosome, 0.1, rng);
125 scramble_mutation(chromosome, 0.05, rng);
126 log
127}