buddy_up_lib/algorithm/
mod.rs1pub mod history;
2use crate::People;
3use crate::Person;
4use genetic_algorithm::{chromosome::GenesOwner, strategy::evolve::prelude::*};
5use history::History;
6use serde::Deserialize;
7use serde::Serialize;
8use tracing::{debug, trace};
9
10#[derive(Debug, Serialize, Deserialize)]
11pub struct Pairs(Vec<(Person, Person)>);
12
13impl Pairs {
14 pub fn inner(self) -> Vec<(Person, Person)> {
15 self.0
16 }
17}
18
19pub fn pair(people: People, last: &History) -> Pairs {
22 let ids = people.as_ids();
23
24 let genotype = UniqueGenotype::builder()
25 .with_allele_list(ids)
26 .build()
27 .unwrap();
28
29 debug!("{genotype}");
30
31 let mut evolve = Evolve::builder()
32 .with_genotype(genotype)
33 .with_target_population_size(50)
34 .with_max_stale_generations(1000)
35 .with_fitness(PairFitness::new(last.clone()))
36 .with_fitness_ordering(FitnessOrdering::Minimize)
37 .with_target_fitness_score(0)
38 .with_replace_on_equal_fitness(true)
40 .with_mutate(MutateSingleGene::new(0.2))
41 .with_crossover(CrossoverClone::new())
42 .with_select(SelectElite::new(0.9))
43 .build()
45 .unwrap();
46
47 evolve.call();
48 let genes = evolve
49 .best_genes()
50 .expect("Something went wrong getting best genes");
51
52 let pairs: Vec<(usize, usize)> = genes.chunks(2).map(|c| (c[0], c[1])).collect();
53 let pairs: Vec<(Person, Person)> = pairs
54 .iter()
55 .map(|(id1, id2)| {
56 (
57 Person::new(*id1, people.name_from_id(*id1).unwrap()),
58 Person::new(*id2, people.name_from_id(*id2).unwrap()),
59 )
60 })
61 .collect();
62 Pairs(pairs)
63}
64
65#[derive(Clone, Debug)]
66struct PairFitness {
67 last: History,
68}
69
70impl PairFitness {
71 fn new(last: History) -> PairFitness {
72 Self { last }
73 }
74}
75impl Fitness for PairFitness {
76 type Genotype = UniqueGenotype<usize>;
77 #[allow(clippy::cast_possible_wrap)]
78 fn calculate_for_chromosome(
79 &mut self,
80 chromosome: &FitnessChromosome<Self>,
81 _genotype: &FitnessGenotype<Self>,
82 ) -> Option<FitnessValue> {
83 let mut score = 0;
84 chromosome.genes().chunks(2).for_each(|chunk| {
85 let (i, j) = (chunk[0], chunk[1]);
86
87 let last = match self.last.get((i, j)) {
88 Some(x) => {
89 trace!("Found score {x} for pair ({i}, {j}).");
90 x
91 }
92 None => {
93 if let Some(x) = self.last.get((j, i)) {
94 trace!("Found score {x} for pair ({j}, {i}).");
95 x
96 } else {
97 trace!("Found no score for pair ({j}, {i}), using 0");
98 0
99 }
100 }
101 };
102 score += last as isize;
104 });
105 trace!("Score for chromosome {:?}: {score}", chromosome.genes());
106 Some(score)
107 }
108}