1use std::cmp::Ordering;
6
7use serde::{Deserialize, Serialize};
8
9use crate::fitness::traits::FitnessValue;
10use crate::genome::traits::EvolutionaryGenome;
11
12#[derive(Clone, Debug, Serialize, Deserialize)]
16#[serde(bound = "")]
17pub struct Individual<G, F = f64>
18where
19 G: EvolutionaryGenome,
20 F: FitnessValue,
21{
22 pub genome: G,
24 pub fitness: Option<F>,
26 pub birth_generation: usize,
28 pub offspring_count: usize,
30}
31
32impl<G, F> Individual<G, F>
33where
34 G: EvolutionaryGenome,
35 F: FitnessValue,
36{
37 pub fn new(genome: G) -> Self {
39 Self {
40 genome,
41 fitness: None,
42 birth_generation: 0,
43 offspring_count: 0,
44 }
45 }
46
47 pub fn with_fitness(genome: G, fitness: F) -> Self {
49 Self {
50 genome,
51 fitness: Some(fitness),
52 birth_generation: 0,
53 offspring_count: 0,
54 }
55 }
56
57 pub fn with_generation(genome: G, generation: usize) -> Self {
59 Self {
60 genome,
61 fitness: None,
62 birth_generation: generation,
63 offspring_count: 0,
64 }
65 }
66
67 pub fn is_evaluated(&self) -> bool {
69 self.fitness.is_some()
70 }
71
72 pub fn fitness_value(&self) -> &F {
74 self.fitness
75 .as_ref()
76 .expect("Individual has not been evaluated")
77 }
78
79 pub fn fitness_f64(&self) -> f64 {
81 self.fitness_value().to_f64()
82 }
83
84 pub fn set_fitness(&mut self, fitness: F) {
86 self.fitness = Some(fitness);
87 }
88
89 pub fn into_genome(self) -> G {
91 self.genome
92 }
93
94 pub fn genome(&self) -> &G {
96 &self.genome
97 }
98
99 pub fn genome_mut(&mut self) -> &mut G {
101 &mut self.genome
102 }
103
104 pub fn is_better_than(&self, other: &Self) -> bool {
106 match (&self.fitness, &other.fitness) {
107 (Some(f1), Some(f2)) => f1.is_better_than(f2),
108 (Some(_), None) => true,
109 (None, Some(_)) => false,
110 (None, None) => false,
111 }
112 }
113
114 pub fn age(&self, current_generation: usize) -> usize {
116 current_generation.saturating_sub(self.birth_generation)
117 }
118}
119
120impl<G, F> PartialEq for Individual<G, F>
121where
122 G: EvolutionaryGenome + PartialEq,
123 F: FitnessValue + PartialEq,
124{
125 fn eq(&self, other: &Self) -> bool {
126 self.genome == other.genome && self.fitness == other.fitness
127 }
128}
129
130impl<G, F> PartialOrd for Individual<G, F>
131where
132 G: EvolutionaryGenome + PartialEq,
133 F: FitnessValue + PartialEq,
134{
135 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
136 match (&self.fitness, &other.fitness) {
137 (Some(f1), Some(f2)) => f1.partial_cmp(f2),
138 (Some(_), None) => Some(Ordering::Greater),
139 (None, Some(_)) => Some(Ordering::Less),
140 (None, None) => Some(Ordering::Equal),
141 }
142 }
143}
144
145pub type IndividualPair<G, F = f64> = (Individual<G, F>, Individual<G, F>);
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151 use crate::genome::real_vector::RealVector;
152 use crate::genome::traits::RealValuedGenome;
153
154 #[test]
155 fn test_individual_new() {
156 let genome = RealVector::new(vec![1.0, 2.0, 3.0]);
157 let individual: Individual<RealVector> = Individual::new(genome);
158
159 assert!(!individual.is_evaluated());
160 assert_eq!(individual.birth_generation, 0);
161 assert_eq!(individual.offspring_count, 0);
162 }
163
164 #[test]
165 fn test_individual_with_fitness() {
166 let genome = RealVector::new(vec![1.0, 2.0, 3.0]);
167 let individual = Individual::with_fitness(genome, 42.0);
168
169 assert!(individual.is_evaluated());
170 assert_eq!(individual.fitness_f64(), 42.0);
171 }
172
173 #[test]
174 fn test_individual_set_fitness() {
175 let genome = RealVector::new(vec![1.0, 2.0, 3.0]);
176 let mut individual: Individual<RealVector> = Individual::new(genome);
177
178 assert!(!individual.is_evaluated());
179 individual.set_fitness(100.0);
180 assert!(individual.is_evaluated());
181 assert_eq!(individual.fitness_f64(), 100.0);
182 }
183
184 #[test]
185 fn test_individual_is_better_than() {
186 let g1 = RealVector::new(vec![1.0]);
187 let g2 = RealVector::new(vec![2.0]);
188
189 let ind1 = Individual::with_fitness(g1, 100.0);
190 let ind2 = Individual::with_fitness(g2, 50.0);
191
192 assert!(ind1.is_better_than(&ind2));
193 assert!(!ind2.is_better_than(&ind1));
194 }
195
196 #[test]
197 fn test_individual_is_better_than_unevaluated() {
198 let g1 = RealVector::new(vec![1.0]);
199 let g2 = RealVector::new(vec![2.0]);
200
201 let ind1 = Individual::with_fitness(g1, 100.0);
202 let ind2: Individual<RealVector> = Individual::new(g2);
203
204 assert!(ind1.is_better_than(&ind2));
205 assert!(!ind2.is_better_than(&ind1));
206 }
207
208 #[test]
209 fn test_individual_age() {
210 let genome = RealVector::new(vec![1.0]);
211 let individual: Individual<RealVector> = Individual::with_generation(genome, 10);
212
213 assert_eq!(individual.age(10), 0);
214 assert_eq!(individual.age(15), 5);
215 assert_eq!(individual.age(5), 0); }
217
218 #[test]
219 fn test_individual_partial_ord() {
220 let g1 = RealVector::new(vec![1.0]);
221 let g2 = RealVector::new(vec![2.0]);
222
223 let ind1 = Individual::with_fitness(g1, 100.0);
224 let ind2 = Individual::with_fitness(g2, 50.0);
225
226 assert!(ind1 > ind2);
227 assert!(ind2 < ind1);
228 }
229
230 #[test]
231 fn test_individual_into_genome() {
232 let genome = RealVector::new(vec![1.0, 2.0, 3.0]);
233 let individual = Individual::with_fitness(genome.clone(), 42.0);
234
235 let recovered = individual.into_genome();
236 assert_eq!(recovered, genome);
237 }
238
239 #[test]
240 fn test_individual_genome_mut() {
241 let genome = RealVector::new(vec![1.0, 2.0, 3.0]);
242 let mut individual: Individual<RealVector> = Individual::new(genome);
243
244 individual.genome_mut().genes_mut()[0] = 100.0;
245 assert_eq!(individual.genome()[0], 100.0);
246 }
247}