radiate_rust/engines/
genetic_engine.rs

1use std::sync::Arc;
2
3use crate::engines::alterers::alter::Alter;
4use crate::engines::genetic_engine_params::GeneticEngineParams;
5use crate::engines::genome::genes::gene::Gene;
6use crate::engines::genome::population::Population;
7use crate::engines::optimize::Optimize;
8use crate::engines::schema::timer::Timer;
9use crate::engines::score::Score;
10
11use super::engine_context::EngineContext;
12use super::genome::phenotype::Phenotype;
13use super::selectors::selector::Select;
14use super::codexes::Codex;
15
16pub struct GeneticEngine<'a, G, A, T>
17where
18    G: Gene<G, A>,
19    T: Clone,
20{
21    pub params: GeneticEngineParams<'a, G, A, T>,
22}
23
24impl<'a, G, A, T> GeneticEngine<'a, G, A, T>
25where
26    G: Gene<G, A>,
27    T: Clone
28{
29
30    pub fn new(params: GeneticEngineParams<'a, G, A, T>) -> Self {
31        GeneticEngine { params }
32    }
33
34    pub fn from_codex(codex: &'a impl Codex<G, A, T>) -> GeneticEngineParams<G, A, T> {
35        GeneticEngineParams::new().codex(codex)
36    }
37
38    pub fn run<F>(&self, limit: F) -> EngineContext<G, A, T> 
39    where
40        F: Fn(&EngineContext<G, A, T>) -> bool
41    {
42        let mut ctx = self.start();
43
44        loop {
45            self.evaluate(&mut ctx);
46
47            let mut survivors = self.select_survivors(&ctx.population);
48            let mut offspring = self.select_offspring(&ctx.population);
49
50            self.alter(&mut offspring, ctx.index);
51
52            self.filter(&mut survivors, ctx.index);
53            self.filter(&mut offspring, ctx.index);
54
55            self.recombine(&mut ctx, survivors, offspring);
56
57            self.evaluate(&mut ctx);
58            self.audit(&mut ctx);
59
60            if limit(&ctx) {
61                break self.stop(&mut ctx)
62            }
63        }
64    }
65
66    fn evaluate(&self, handle: &mut EngineContext<G, A, T>) {
67        let codex = self.codex();
68        let fitness_fn = self.fitness_fn();
69        let optimize = self.optimize();
70
71        for idx in 0..handle.population.len() {
72            let individual = handle.population.get_mut(idx);
73            if !individual.score().is_some() {
74                let decoded = codex.decode(individual.genotype());
75                let score = fitness_fn(decoded);
76
77                individual.set_score(Some(score));
78            }
79        }
80
81        optimize.sort(&mut handle.population);
82    }
83
84    fn select_survivors(&self, population: &Population<G, A>) -> Population<G, A> {
85        let selector = self.survivor_selector();
86        let count = self.survivor_count();
87        let optimize = self.optimize();
88
89        selector.select(population, optimize, count)
90    }
91
92    fn select_offspring(&self, population: &Population<G, A>) -> Population<G, A> {
93        let selector = self.offspring_selector();
94        let count = self.offspring_count();
95        let optimize = self.optimize();
96
97        selector.select(population, optimize, count)
98    }
99
100    fn alter(&self, population: &mut Population<G, A>, generation: i32) {
101        let alterer = self.alterer();
102        let optimize = self.optimize();
103
104        alterer.alter(population, optimize, generation);
105    }
106
107    fn filter(&self, population: &mut Population<G, A>, generation: i32) {
108        let max_age = self.params.max_age;
109        let codex = self.codex();
110
111        for i in 0..population.len() {
112            let phenotype = population.get(i);
113            
114            if phenotype.age(generation) > max_age {
115                population.set(i, Phenotype::from_genotype(codex.encode(), generation));
116            } else if !phenotype.genotype().is_valid() {
117                population.set(i, Phenotype::from_genotype(codex.encode(), generation));
118            }
119        }
120    }
121
122    fn recombine(&self, handle: &mut EngineContext<G, A, T>, survivors: Population<G, A>, offspring: Population<G, A>) {
123        handle.population = survivors
124            .into_iter()
125            .chain(offspring.into_iter())
126            .collect::<Population<G, A>>();
127    }
128
129    fn audit(&self, output: &mut EngineContext<G, A, T>) {
130        let codex = self.codex();
131        let optimize = self.optimize();
132
133        if !output.population.is_sorted {
134            self.optimize().sort(&mut output.population);
135        }
136
137        if let Some(current_score) = &output.score {
138            if let Some(best_score) = output.population.get(0).score() {
139                if optimize.is_better(best_score, &current_score) {
140                    output.score = Some(best_score.clone());
141                    output.best = codex.decode(&output.population.get(0).genotype());
142                }
143            }
144        } else {
145            output.score = output.population.get(0).score().clone();
146            output.best = codex.decode(&output.population.get(0).genotype());
147        }
148
149        output.index += 1;
150    }
151
152    fn survivor_selector(&self) -> &impl Select<G, A> {
153        &self.params.survivor_selector
154    }
155
156    fn offspring_selector(&self) -> &impl Select<G, A> {
157        &self.params.offspring_selector
158    }
159
160    fn alterer(&self) -> &impl Alter<G, A> {
161        self.params.alterer.as_ref().unwrap()
162    }
163
164    fn codex(&self) -> &Arc<&'a dyn Codex<G, A, T>> {
165        self.params.codex.as_ref().unwrap()
166    }
167
168    fn fitness_fn(&self) -> &Arc<dyn Fn(T) -> Score> {
169        self.params.fitness_fn.as_ref().unwrap()
170    }
171
172    fn population(&self) -> &Population<G, A> {
173        self.params.population.as_ref().unwrap()
174    }
175
176    fn optimize(&self) -> &Optimize {
177        &self.params.optimize
178    }
179
180    fn survivor_count(&self) -> usize {
181        self.params.population_size - self.offspring_count()
182    }
183
184    fn offspring_count(&self) -> usize {
185        (self.params.population_size as f32 * self.params.offspring_fraction) as usize
186    }
187
188    fn start(&self) -> EngineContext<G, A, T> {
189        let population = self.population();
190
191        EngineContext {
192            population: population.clone(),
193            best: self.codex().decode(&population.get(0).genotype()),
194            index: 0,
195            timer: Timer::new(),
196            score: None
197        }
198    }
199
200    fn stop(&self, output: &mut EngineContext<G, A, T>) -> EngineContext<G, A, T> {
201        output.timer.stop();
202        output.clone()
203    }
204}