Skip to main content

radiate_pgm/
alter.rs

1use crate::PgmChromosome;
2use radiate_core::alter::{AlterResult, Mutate};
3use radiate_core::random_provider;
4use radiate_utils::Value;
5
6#[derive(Clone, Debug)]
7pub struct PgmParamMutator {
8    /// Probability that a given factor is selected for parameter mutation.
9    pub factor_rate: f32,
10    /// Fraction of entries in a factor table to jitter when selected.
11    pub entry_rate: f32,
12    /// Jitter magnitude applied to selected logits.
13    pub step: f32,
14}
15
16impl PgmParamMutator {
17    pub fn new(factor_rate: f32, entry_rate: f32, step: f32) -> Self {
18        Self {
19            factor_rate,
20            entry_rate,
21            step,
22        }
23    }
24}
25
26impl Mutate<PgmChromosome> for PgmParamMutator {
27    #[inline]
28    fn mutate_chromosome(&self, chromosome: &mut PgmChromosome, _: f32) -> AlterResult {
29        let mut count = 0;
30        for f in chromosome.factors.iter_mut() {
31            if random_provider::bool(self.factor_rate) {
32                let Value::Array { values, .. } = &mut f.params else {
33                    continue;
34                };
35
36                random_provider::with_rng(|rng| {
37                    let n = values.len().max(1);
38                    let k = ((n as f32) * self.entry_rate).ceil() as usize;
39                    let k = k.clamp(1, n);
40
41                    let idxs = rng.sample_indices(0..n, k);
42                    let vals = std::sync::Arc::make_mut(values);
43
44                    for &i in &idxs {
45                        vals[i] += rng.range(-self.step..self.step);
46                    }
47
48                    k
49                });
50
51                count += 1;
52            }
53        }
54
55        AlterResult::from(count)
56    }
57}
58
59/// Mutate factor scopes (structure) and rebuild their tables.
60#[derive(Clone, Debug)]
61pub struct PgmScopeMutator {
62    pub factor_rate: f32,
63    pub max_scope: usize,
64}
65
66impl PgmScopeMutator {
67    pub fn new(factor_rate: f32, max_scope: usize) -> Self {
68        Self {
69            factor_rate,
70            max_scope,
71        }
72    }
73}
74
75impl Mutate<PgmChromosome> for PgmScopeMutator {
76    #[inline]
77    fn mutate_chromosome(&self, chromosome: &mut PgmChromosome, _rate: f32) -> AlterResult {
78        let mut count = 0;
79
80        let vars = chromosome.vars.clone();
81        for f in chromosome.factors.iter_mut() {
82            if random_provider::bool(self.factor_rate) {
83                f.resample_scope(&vars, self.max_scope);
84                count += 1;
85            }
86        }
87
88        AlterResult::from(count)
89    }
90}