1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use super::*;
use crate::utils::parallel_into_collect;
use std::cmp::Ordering;
use std::ops::Range;
pub struct NaiveBranching {
inner: Arc<dyn Mutation + Send + Sync>,
normal_chance: f64,
intensive_chance: f64,
threshold: f64,
steepness: f64,
generations: Range<usize>,
}
impl NaiveBranching {
pub fn new(
inner: Arc<dyn Mutation + Send + Sync>,
chance: (f64, f64, f64),
steepness: f64,
generations: Range<usize>,
) -> Self {
Self { inner, normal_chance: chance.0, intensive_chance: chance.1, threshold: chance.2, steepness, generations }
}
}
impl Mutation for NaiveBranching {
fn mutate_one(&self, refinement_ctx: &RefinementContext, insertion_ctx: InsertionContext) -> InsertionContext {
let branching_chance = self.get_branching_chance(refinement_ctx);
let is_branch = insertion_ctx.random.uniform_real(0., 1.) < branching_chance;
if is_branch {
let random = insertion_ctx.random.clone();
let (min, max) = (self.generations.start as i32, self.generations.end as i32);
let gens = random.uniform_int(min, max) as usize;
(1_usize..=gens).fold(insertion_ctx, |parent, idx| {
let child = self.inner.mutate_one(&refinement_ctx, parent.deep_copy());
let use_worse_chance = random.uniform_real(0., 1.);
let use_worse_probability = get_use_worse_probability(idx, gens, self.steepness);
let is_child_better = refinement_ctx.population.cmp(&child, &parent) == Ordering::Less;
if use_worse_chance < use_worse_probability || is_child_better {
child
} else {
parent
}
})
} else {
self.inner.mutate_one(&refinement_ctx, insertion_ctx)
}
}
fn mutate_all(
&self,
refinement_ctx: &RefinementContext,
individuals: Vec<InsertionContext>,
) -> Vec<InsertionContext> {
parallel_into_collect(individuals, |insertion_ctx| self.mutate_one(refinement_ctx, insertion_ctx))
}
}
impl NaiveBranching {
fn get_branching_chance(&self, refinement_ctx: &RefinementContext) -> f64 {
if refinement_ctx.statistics.improvement_1000_ratio < self.threshold {
self.intensive_chance
} else {
self.normal_chance
}
}
}
fn get_use_worse_probability(current: usize, total: usize, steepness: f64) -> f64 {
1. - (current as f64 / total as f64).powf(steepness)
}