-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlib.rs
81 lines (70 loc) · 2.77 KB
/
lib.rs
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
78
79
80
81
pub use crate::{selection_method::*, crossover_method::*, mutation_method::*, statistics::*};
pub mod selection_method;
pub mod crossover_method;
pub mod mutation_method;
pub mod statistics;
pub struct GeneticAlgorithm<S>
where S: SelectionMethod
{
selection_method: S,
crossover_method: Box<dyn CrossoverMethod>,
mutation_method: Box<dyn MutationMethod>,
save_bests: usize
}
impl<S> GeneticAlgorithm<S>
where S: SelectionMethod
{
pub fn new(
selection_method: S,
crossover_method: impl CrossoverMethod + 'static,
mutation_method: impl MutationMethod + 'static,
save_bests: usize
) -> Self {
Self {
selection_method,
crossover_method: Box::new(crossover_method),
mutation_method: Box::new(mutation_method),
save_bests
}
}
/// Given a population of individuals, selects, reproduces, and mutates the population.
pub fn evolve<I>(&self, population: &mut [I]) -> (Vec<I>, Statistics)
where I: Individual + Clone
{
assert!(!population.is_empty());
// Sort the population by decreasing fitness
population.sort_by(|i1, i2| i1.fitness().partial_cmp(&i2.fitness()).unwrap().reverse() );
let new_population = population
.iter()
.enumerate()
.map(|(index, individual)| {
if index < self.save_bests {
individual.clone()
} else {
// Selects two parents and extracts their genome
let parent_a = self.selection_method.select(population).genome();
let parent_b = self.selection_method.select(population).genome();
// Apply crossover method to parents to create the genome of a child
let mut child = self.crossover_method.crossover(&parent_a, &parent_b);
// Mutates the child's genome
self.mutation_method.mutate(&mut child);
// Convert the genome back to an individual
I::create(child)
}
})
.collect();
(new_population, Statistics::new(population))
}
}
pub trait Individual {
/// The actual score to the game, similar but not equal to fitness.
/// For example, the number of apples eaten.
fn score(&self) -> u32;
/// The fitness function, two rank the effectivness of an individual's brain.
/// For example, an expression that combines score and lifetime.
fn fitness(&self) -> u32;
/// Convert an individual to its genome, an array that contains weights and biases of the brain.
fn genome(&self) -> &Vec<f32>;
/// Convert a genome back to an individual.
fn create(genom: Vec<f32>) -> Self;
}