1use crate::{Chromosome, Gene, MetricSet, math::indexes, random_provider, stats::metric_tags};
2use crate::{GetPairMut, Phenotype};
3use crate::{RateSet, error::RadiateResult};
4pub use radiate_expr::*;
5use radiate_utils::{SmallStr, generate_metric_key};
6use std::collections::HashMap;
7use std::sync::Arc;
8
9#[macro_export]
10macro_rules! alters {
11 ($($struct_instance:expr),* $(,)?) => {
12 {
13 let mut vec: Vec<Alterer<_>> = Vec::new();
14 $(
15 vec.push($struct_instance.into_alterer());
16 )*
17 vec
18 }
19 };
20}
21
22#[derive(Clone, Default)]
23pub struct AlterUpdates(pub HashMap<SmallStr, usize>);
24
25impl AlterUpdates {
26 pub fn new() -> Self {
27 AlterUpdates(HashMap::new())
28 }
29
30 pub fn clear(&mut self) {
31 for value in self.0.values_mut() {
32 *value = 0;
33 }
34 }
35
36 pub fn iter(&self) -> impl Iterator<Item = (&SmallStr, &usize)> {
37 self.0.iter().filter(|(_, count)| **count > 0)
38 }
39
40 pub fn upsert(&mut self, name: impl AsRef<str>, value: usize) {
41 if let Some(existing) = self.0.get_mut(name.as_ref()) {
42 *existing += value;
43 } else {
44 self.0
45 .insert(SmallStr::from_string(name.as_ref().into()), value);
46 }
47 }
48}
49
50pub struct AlterContext<'a> {
51 alter_counts: &'a mut AlterUpdates,
52 generation: usize,
53 control_rate: f32,
54 internal_rates: &'a [f32],
55}
56
57impl<'a> AlterContext<'a> {
58 pub fn new(
59 alter_counts: &'a mut AlterUpdates,
60 generation: usize,
61 control_rate: f32,
62 internal_rates: &'a [f32],
63 ) -> Self {
64 AlterContext {
65 alter_counts,
66 generation,
67 control_rate,
68 internal_rates,
69 }
70 }
71
72 pub fn rate(&self) -> f32 {
73 self.control_rate
74 }
75
76 pub fn internal_rate(&self, index: usize) -> f32 {
77 self.internal_rates.get(index).copied().unwrap_or(0.0)
78 }
79
80 pub fn generation(&self) -> usize {
81 self.generation
82 }
83
84 pub fn upsert(&mut self, name: impl AsRef<str>, value: usize) {
85 self.alter_counts.upsert(name, value);
86 }
87}
88
89#[derive(Clone)]
90pub enum AlterInner<C: Chromosome> {
91 Mutate(Arc<dyn Mutate<C>>),
92 Crossover(Arc<dyn Crossover<C>>),
93}
94
95#[derive(Clone)]
99pub struct Alterer<C: Chromosome> {
100 time_name: SmallStr,
101 name: SmallStr,
102 inner: AlterInner<C>,
103 alter_counts: AlterUpdates,
104 rate_set: RateSet,
105}
106
107impl<C: Chromosome> Alterer<C> {
108 pub fn mutation(name: impl Into<SmallStr>, m: Arc<dyn Mutate<C>>) -> Self {
109 Self::build_internal(name, AlterInner::Mutate(m))
110 }
111
112 pub fn crossover(name: impl Into<SmallStr>, c: Arc<dyn Crossover<C>>) -> Self {
113 Self::build_internal(name, AlterInner::Crossover(c))
114 }
115
116 fn build_internal(name: impl Into<SmallStr>, inner: AlterInner<C>) -> Self {
117 let name = name.into();
118
119 let time_name = SmallStr::from_string(format!("{}.time", name));
120 let control_rate_name = SmallStr::from_string(format!("{}.rate", name));
121
122 let rate_set = match &inner {
123 AlterInner::Mutate(m) => m.rates().alias(control_rate_name.clone()),
124 AlterInner::Crossover(c) => c.rates().alias(control_rate_name.clone()),
125 };
126
127 Self {
128 time_name,
129 name,
130 inner,
131 alter_counts: AlterUpdates::new(),
132 rate_set,
133 }
134 }
135
136 pub fn rates(&self) -> &RateSet {
137 &self.rate_set
138 }
139
140 pub fn name(&self) -> &str {
141 &self.name
142 }
143
144 pub fn alter(
145 &mut self,
146 population: &mut [Phenotype<C>],
147 metrics: &mut MetricSet,
148 generation: usize,
149 ) -> RadiateResult<()> {
150 let rates = self.rate_set.calculate_rates(generation, metrics)?;
151
152 self.alter_counts.clear();
153
154 let mut ctx = AlterContext::new(&mut self.alter_counts, generation, rates[0], &rates[1..]);
155
156 match &mut self.inner {
157 AlterInner::Mutate(m) => {
158 let mutator = Arc::get_mut(&mut (*m)).unwrap();
159
160 let timer = std::time::Instant::now();
161 let result = mutator.mutate(population, &mut ctx);
162 metrics.upsert(&self.time_name, timer.elapsed());
163 metrics.upsert(&self.name, result);
164
165 for (name, count) in ctx.alter_counts.iter() {
166 metrics.upsert(name, *count);
167 }
168 }
169 AlterInner::Crossover(c) => {
170 let timer = std::time::Instant::now();
171 let result = c.crossover(population, &mut ctx);
172 metrics.upsert(&self.time_name, timer.elapsed());
173 metrics.upsert(&self.name, result);
174
175 for (name, count) in ctx.alter_counts.iter() {
176 metrics.upsert(name, *count);
177 }
178 }
179 }
180
181 Ok(())
182 }
183}
184
185const MIN_POPULATION_SIZE: usize = 3;
189const MIN_NUM_PARENTS: usize = 2;
192
193pub trait Crossover<C: Chromosome>: Send + Sync {
205 fn name(&self) -> String {
206 generate_metric_key::<Self>(metric_tags::CROSSOVER)
207 }
208
209 fn into_alterer(self) -> Alterer<C>
210 where
211 Self: Sized + 'static,
212 {
213 Alterer::crossover(self.name(), Arc::new(self))
214 }
215
216 fn rates(&self) -> RateSet {
217 RateSet::default()
218 }
219
220 #[inline]
221 fn crossover(&self, mut population: &mut [Phenotype<C>], ctx: &mut AlterContext) -> usize {
222 let mut result = 0;
223 let mut parents = [0; MIN_NUM_PARENTS];
224 let pop_size = population.len();
225
226 for i in 0..pop_size {
227 if random_provider::bool(ctx.rate()) && pop_size > MIN_POPULATION_SIZE {
228 indexes::fill_subset_inclusive(i, pop_size, &mut parents);
229
230 result += population
231 .get_pair_mut(parents[0], parents[1])
232 .map(|(one, two)| self.cross(one, two, ctx))
233 .unwrap_or(0);
234 }
235 }
236
237 result
238 }
239
240 #[inline]
241 fn cross(
242 &self,
243 parent_one: &mut Phenotype<C>,
244 parent_two: &mut Phenotype<C>,
245 ctx: &mut AlterContext,
246 ) -> usize {
247 let geno_one = parent_one.genotype_mut();
248 let geno_two = parent_two.genotype_mut();
249
250 let min_len = std::cmp::min(geno_one.len(), geno_two.len());
251 let chromosome_index = random_provider::range(0..min_len);
252
253 let chrom_one = &mut geno_one[chromosome_index];
254 let chrom_two = &mut geno_two[chromosome_index];
255
256 let cross_result = self.cross_chromosomes(chrom_one, chrom_two, ctx);
257
258 if cross_result > 0 {
259 parent_one.invalidate(ctx.generation());
260 parent_two.invalidate(ctx.generation());
261 }
262
263 cross_result
264 }
265
266 #[inline]
267 fn cross_chromosomes(
268 &self,
269 chrom_one: &mut C,
270 chrom_two: &mut C,
271 ctx: &mut AlterContext,
272 ) -> usize {
273 let mut cross_count = 0;
274
275 for i in 0..std::cmp::min(chrom_one.len(), chrom_two.len()) {
276 if random_provider::bool(ctx.rate()) {
277 let gene_one = chrom_one.get_mut(i);
278 let gene_two = chrom_two.get_mut(i);
279
280 if let Some((gene_one, gene_two)) = gene_one.zip(gene_two) {
281 std::mem::swap(gene_one, gene_two);
282 cross_count += 1;
283 }
284 }
285 }
286
287 cross_count
288 }
289}
290
291pub trait Mutate<C: Chromosome>: Send + Sync {
292 fn name(&self) -> String {
293 generate_metric_key::<Self>(metric_tags::MUTATOR)
294 }
295
296 fn into_alterer(self) -> Alterer<C>
297 where
298 Self: Sized + 'static,
299 {
300 Alterer::mutation(self.name(), Arc::new(self))
301 }
302
303 fn rates(&self) -> RateSet {
304 RateSet::default()
305 }
306
307 #[inline]
308 fn mutate(&mut self, population: &mut [Phenotype<C>], ctx: &mut AlterContext) -> usize {
309 population
310 .iter_mut()
311 .map(|phenotype| {
312 let mutate_result = phenotype
313 .genotype_mut()
314 .iter_mut()
315 .fold(0, |acc, chromosome| {
316 acc + self.mutate_chromosome(chromosome, ctx)
317 });
318
319 if mutate_result > 0 {
320 phenotype.invalidate(ctx.generation());
321 }
322
323 mutate_result
324 })
325 .sum()
326 }
327
328 #[inline]
329 fn mutate_chromosome(&mut self, chromosome: &mut C, ctx: &mut AlterContext) -> usize {
330 chromosome
331 .iter_mut()
332 .filter(|_| random_provider::bool(ctx.rate()))
333 .fold(0, |acc, gene| {
334 *gene = gene.new_instance();
335 acc + 1
336 })
337 }
338}