scarlet_queen_core/
fitness.rs

1//! Mod for `FitnessIndividualTrait`.
2
3use std::collections::HashMap;
4
5use crate::each_crate_individual::EachCrateIndividual;
6
7/// A trait for a individual having a method for assigning a fitness score to a individual.
8///
9/// The process corresponds the "Fitness" step of `GroupTrait`.
10///
11/// # Example
12/// ```
13/// use std::{collections::HashMap, rc::Rc};
14///
15/// use scarlet_queen_core::{Individual, EachCrateIndividual, FitnessIndividualTrait};
16///
17/// struct Fitness(Rc<Individual<u8>>);
18///
19/// impl EachCrateIndividual for Fitness {
20///     type Item = u8;
21///
22///     fn new(individual: &std::rc::Rc<Individual<u8>>) -> Self {
23///         Fitness(Rc::clone(individual))
24///     }
25///
26///     fn get_individual(&self) -> &Individual<u8> {
27///         &self.0
28///     }
29/// }
30///
31/// impl FitnessIndividualTrait for Fitness {
32///     fn fitness(&self, other: &Self) -> usize {
33///         if self.get_value() >= other.get_value() {
34///             1
35///         } else {
36///             0
37///         }
38///     }
39/// }
40///
41/// let r_1: Rc<Individual<u8>> = Rc::new(Individual::new_with_id(0, 13));
42/// let sample_1: Fitness = Fitness::new(&r_1);
43///
44/// assert_eq!(sample_1.get_individual(), r_1.as_ref());
45/// assert_eq!(sample_1.get_id(), 0usize);
46/// assert_eq!(sample_1.get_value(), &13u8);
47///
48/// let sample_2: Fitness = Fitness::new(&Rc::new(Individual::new_with_id(1, 5)));
49///
50/// assert_eq!(sample_1.fitness(&sample_2), 1);
51///
52/// let sample: Vec<Fitness> = vec![
53///     sample_1,
54///     sample_2,
55///     Fitness::new(&Rc::new(Individual::new_with_id(2, 15)))
56/// ];
57///
58/// assert_eq!(Fitness::fitness_group(&sample), vec![(0usize, 1usize), (1, 0), (2, 2)].into_iter().collect::<HashMap<usize, usize>>());
59/// ```
60pub trait FitnessIndividualTrait: EachCrateIndividual {
61    /// Calculate a fitness score to an other individual.
62    ///
63    /// * `other` - A target of fitness.
64    fn fitness(&self, other: &Self) -> usize;
65
66    /// Calculate a fitness to a group.
67    ///
68    /// A fitness score to a group is the sum of fitness scores to other individuals of the group.
69    ///
70    /// The elements of `group` must be assigned a number to.
71    ///
72    /// * `'a` - A lifetime of group.
73    /// * `G` - A type of group.
74    /// * `group` - A value which you are able to get `Self` from.
75    fn fitness_group<'a, G>(group: G) -> HashMap<usize, usize>
76    where
77        G: IntoIterator<Item = &'a Self>,
78        Self: 'a,
79    {
80        // get group
81        let group_vec: Vec<&Self> = group.into_iter().collect::<Vec<&Self>>();
82
83        // calculate a sum of fitness scores to other individuals
84        group_vec
85            .iter()
86            .map(|v| {
87                (
88                    v.get_id(),
89                    group_vec.iter().map(|u| v.fitness(u)).sum::<usize>() - v.fitness(v),
90                )
91            })
92            .collect::<HashMap<usize, usize>>()
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use std::{collections::HashMap, rc::Rc};
99
100    use super::FitnessIndividualTrait;
101    use crate::{each_crate_individual::EachCrateIndividual, individual::Individual};
102
103    struct Fitness(Rc<Individual<u8>>);
104    impl Fitness {
105        fn new_for_test(id: usize, value: u8) -> Self {
106            Fitness(Rc::new(Individual::new_with_id(id, value)))
107        }
108    }
109    impl EachCrateIndividual for Fitness {
110        type Item = u8;
111        fn new(individual: &std::rc::Rc<Individual<u8>>) -> Self {
112            Fitness(Rc::clone(individual))
113        }
114        fn get_individual(&self) -> &Individual<u8> {
115            &self.0
116        }
117    }
118    impl FitnessIndividualTrait for Fitness {
119        fn fitness(&self, other: &Self) -> usize {
120            if self.get_value() >= other.get_value() {
121                1
122            } else {
123                0
124            }
125        }
126    }
127
128    #[test]
129    fn test_fitnessindividualtrait_fitnessgroup() {
130        let testcases: Vec<(Vec<Fitness>, HashMap<usize, usize>)> = vec![
131            (
132                vec![
133                    Fitness::new_for_test(0, 10),
134                    Fitness::new_for_test(1, 10),
135                    Fitness::new_for_test(2, 6),
136                    Fitness::new_for_test(3, 6),
137                    Fitness::new_for_test(4, 6),
138                    Fitness::new_for_test(5, 5),
139                    Fitness::new_for_test(6, 3),
140                    Fitness::new_for_test(7, 2),
141                    Fitness::new_for_test(8, 2),
142                    Fitness::new_for_test(9, 1),
143                ],
144                vec![
145                    (0, 9),
146                    (1, 9),
147                    (2, 7),
148                    (3, 7),
149                    (4, 7),
150                    (5, 4),
151                    (6, 3),
152                    (7, 2),
153                    (8, 2),
154                    (9, 0),
155                ]
156                .into_iter()
157                .collect::<HashMap<usize, usize>>(),
158            ),
159            (
160                vec![
161                    Fitness::new_for_test(0, 3),
162                    Fitness::new_for_test(1, 1),
163                    Fitness::new_for_test(2, 1),
164                    Fitness::new_for_test(3, 1),
165                ],
166                vec![(0, 3), (1, 2), (2, 2), (3, 2)]
167                    .into_iter()
168                    .collect::<HashMap<usize, usize>>(),
169            ),
170            (
171                vec![Fitness::new_for_test(0, 1)],
172                vec![(0, 0)].into_iter().collect::<HashMap<usize, usize>>(),
173            ),
174            (
175                vec![],
176                vec![].into_iter().collect::<HashMap<usize, usize>>(),
177            ),
178            (
179                vec![
180                    Fitness::new_for_test(0, 17),
181                    Fitness::new_for_test(1, 2),
182                    Fitness::new_for_test(2, 20),
183                    Fitness::new_for_test(3, 20),
184                    Fitness::new_for_test(4, 16),
185                    Fitness::new_for_test(5, 16),
186                    Fitness::new_for_test(6, 12),
187                    Fitness::new_for_test(7, 19),
188                    Fitness::new_for_test(8, 1),
189                    Fitness::new_for_test(9, 4),
190                    Fitness::new_for_test(10, 14),
191                    Fitness::new_for_test(11, 10),
192                    Fitness::new_for_test(12, 8),
193                    Fitness::new_for_test(13, 2),
194                    Fitness::new_for_test(14, 8),
195                    Fitness::new_for_test(15, 16),
196                    Fitness::new_for_test(16, 16),
197                    Fitness::new_for_test(17, 10),
198                    Fitness::new_for_test(18, 4),
199                    Fitness::new_for_test(19, 1),
200                ],
201                vec![
202                    (0, 16),
203                    (1, 3),
204                    (2, 19),
205                    (3, 19),
206                    (4, 15),
207                    (5, 15),
208                    (6, 10),
209                    (7, 17),
210                    (8, 1),
211                    (9, 5),
212                    (10, 11),
213                    (11, 9),
214                    (12, 7),
215                    (13, 3),
216                    (14, 7),
217                    (15, 15),
218                    (16, 15),
219                    (17, 9),
220                    (18, 5),
221                    (19, 1),
222                ]
223                .into_iter()
224                .collect::<HashMap<usize, usize>>(),
225            ),
226        ];
227        for (arg, result) in testcases.into_iter() {
228            assert_eq!(Fitness::fitness_group(&arg), result);
229        }
230    }
231}