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}