radiate_core/objectives/
score.rs

1use radiate_error::RadiateError;
2#[cfg(feature = "serde")]
3use serde::{Deserialize, Serialize};
4use std::fmt::Debug;
5use std::hash::Hash;
6use std::iter::Sum;
7use std::ops::{Add, Div, Index, Mul, Sub};
8use std::sync::Arc;
9
10/// A trait for types that can be scored.
11/// We can use this for a common interface for all scored types.
12pub trait Scored {
13    fn score(&self) -> Option<&Score>;
14}
15
16/// A [Score] is a value that can be used to compare the fitness of two individuals and represents
17/// the 'fitness' of an individual within the genetic algorithm.
18/// The [Score] can be a single value or multiple values, depending on the problem being solved.
19/// For ease of use the [Score] struct provides methods
20/// to convert the score to a single value, an integer, a string, or a vector of `f32` values.
21///
22/// Note: The reason it is a Vec is for multi-objective optimization problems. This allows for multiple
23/// fitness values to be returned from the fitness function.
24#[derive(Clone, PartialEq, Default)]
25#[repr(transparent)]
26pub struct Score {
27    values: Arc<[f32]>,
28}
29
30impl Score {
31    pub fn from_vec(values: Vec<f32>) -> Self {
32        if values.iter().any(|&v| v.is_nan()) {
33            panic!("Score value cannot be NaN");
34        }
35
36        Score {
37            values: Arc::from(values),
38        }
39    }
40
41    pub fn as_f32(&self) -> f32 {
42        self.values.get(0).cloned().unwrap_or(f32::NAN)
43    }
44
45    pub fn as_i32(&self) -> i32 {
46        self.values[0] as i32
47    }
48
49    pub fn as_string(&self) -> String {
50        self.values[0].to_string()
51    }
52
53    pub fn as_usize(&self) -> usize {
54        self.values[0] as usize
55    }
56
57    pub fn iter(&self) -> impl Iterator<Item = &f32> + '_ {
58        self.values.iter()
59    }
60}
61
62impl AsRef<[f32]> for Score {
63    fn as_ref(&self) -> &[f32] {
64        &self.values
65    }
66}
67
68impl PartialOrd for Score {
69    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
70        self.values.partial_cmp(&other.values)
71    }
72}
73
74impl Debug for Score {
75    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76        write!(f, "{:?}", self.values)
77    }
78}
79
80impl Hash for Score {
81    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
82        let mut hash: usize = 0;
83
84        for value in self.values.iter() {
85            let value_hash = value.to_bits();
86            hash = hash.wrapping_add(value_hash as usize);
87        }
88
89        hash.hash(state);
90    }
91}
92
93impl Index<usize> for Score {
94    type Output = f32;
95    fn index(&self, index: usize) -> &Self::Output {
96        &self.values[index]
97    }
98}
99
100impl Into<Vec<f32>> for Score {
101    fn into(self) -> Vec<f32> {
102        self.values.to_vec()
103    }
104}
105
106impl From<f32> for Score {
107    fn from(value: f32) -> Self {
108        if value.is_nan() {
109            panic!("Score value cannot be NaN")
110        }
111
112        Score {
113            values: Arc::from(vec![value]),
114        }
115    }
116}
117
118impl TryFrom<i16> for Score {
119    type Error = RadiateError;
120
121    fn try_from(value: i16) -> Result<Self, Self::Error> {
122        Ok(Score {
123            values: Arc::from(vec![value as f32]),
124        })
125    }
126}
127
128impl From<f64> for Score {
129    fn from(value: f64) -> Self {
130        if value.is_nan() {
131            panic!("Score value cannot be NaN")
132        }
133
134        Score {
135            values: Arc::from(vec![value as f32]),
136        }
137    }
138}
139
140impl From<i32> for Score {
141    fn from(value: i32) -> Self {
142        Score {
143            values: Arc::from(vec![value as f32]),
144        }
145    }
146}
147
148impl From<i64> for Score {
149    fn from(value: i64) -> Self {
150        Score {
151            values: Arc::from(vec![value as f32]),
152        }
153    }
154}
155
156impl From<usize> for Score {
157    fn from(value: usize) -> Self {
158        Score {
159            values: Arc::from(vec![value as f32]),
160        }
161    }
162}
163
164impl From<String> for Score {
165    fn from(value: String) -> Self {
166        Score {
167            values: Arc::from(vec![
168                value.parse::<f32>().expect("Failed to parse string to f32"),
169            ]),
170        }
171    }
172}
173
174impl From<&str> for Score {
175    fn from(value: &str) -> Self {
176        Score {
177            values: Arc::from(vec![
178                value.parse::<f32>().expect("Failed to parse string to f32"),
179            ]),
180        }
181    }
182}
183
184impl From<Vec<f32>> for Score {
185    fn from(value: Vec<f32>) -> Self {
186        Score::from_vec(value)
187    }
188}
189
190impl From<Vec<f64>> for Score {
191    fn from(value: Vec<f64>) -> Self {
192        Score::from_vec(value.into_iter().map(|v| v as f32).collect())
193    }
194}
195
196impl From<Vec<i32>> for Score {
197    fn from(value: Vec<i32>) -> Self {
198        Score::from_vec(value.into_iter().map(|v| v as f32).collect())
199    }
200}
201
202impl From<Vec<i64>> for Score {
203    fn from(value: Vec<i64>) -> Self {
204        Score::from_vec(value.into_iter().map(|v| v as f32).collect())
205    }
206}
207
208impl From<Vec<usize>> for Score {
209    fn from(value: Vec<usize>) -> Self {
210        Score::from_vec(value.into_iter().map(|v| v as f32).collect())
211    }
212}
213
214impl From<Vec<String>> for Score {
215    fn from(value: Vec<String>) -> Self {
216        Score::from_vec(
217            value
218                .into_iter()
219                .map(|v| v.parse::<f32>().unwrap())
220                .collect(),
221        )
222    }
223}
224
225impl From<Vec<&str>> for Score {
226    fn from(value: Vec<&str>) -> Self {
227        Score::from_vec(
228            value
229                .into_iter()
230                .map(|v| v.parse::<f32>().unwrap())
231                .collect(),
232        )
233    }
234}
235
236impl Add for Score {
237    type Output = Self;
238
239    fn add(self, other: Self) -> Self {
240        if self.values.is_empty() {
241            return other;
242        }
243
244        let mut values = Vec::with_capacity(self.values.len());
245
246        for i in 0..self.values.len() {
247            values.push(self.values[i] + other.values[i]);
248        }
249
250        Score {
251            values: Arc::from(values),
252        }
253    }
254}
255
256impl Add<f32> for Score {
257    type Output = Self;
258
259    fn add(self, other: f32) -> Self {
260        if self.values.is_empty() {
261            return Score::from(other);
262        }
263
264        let mut values = Vec::with_capacity(self.values.len());
265        for i in 0..self.values.len() {
266            values.push(self.values[i] + other);
267        }
268
269        Score {
270            values: Arc::from(self.values),
271        }
272    }
273}
274
275impl Sub for Score {
276    type Output = Self;
277
278    fn sub(self, other: Self) -> Self {
279        if self.values.is_empty() {
280            return other;
281        }
282
283        let mut values = Vec::with_capacity(self.values.len());
284
285        for i in 0..self.values.len() {
286            values.push(self.values[i] - other.values[i]);
287        }
288
289        Score {
290            values: Arc::from(values),
291        }
292    }
293}
294
295impl Sub<f32> for Score {
296    type Output = Self;
297
298    fn sub(self, other: f32) -> Self {
299        if self.values.is_empty() {
300            return Score::from(-other);
301        }
302
303        let mut values = Vec::with_capacity(self.values.len());
304        for i in 0..self.values.len() {
305            values.push(self.values[i] - other);
306        }
307
308        Score {
309            values: Arc::from(values),
310        }
311    }
312}
313
314impl Mul for Score {
315    type Output = Self;
316
317    fn mul(self, other: Self) -> Self {
318        if self.values.is_empty() {
319            return other;
320        }
321
322        let mut values = Vec::with_capacity(self.values.len());
323        for i in 0..self.values.len() {
324            values.push(self.values[i] * other.values[i]);
325        }
326
327        Score {
328            values: Arc::from(values),
329        }
330    }
331}
332
333impl Mul<f32> for Score {
334    type Output = Self;
335
336    fn mul(self, other: f32) -> Self {
337        if self.values.is_empty() {
338            return Score::from(other);
339        }
340
341        let mut values = Vec::with_capacity(self.values.len());
342        for i in 0..self.values.len() {
343            values.push(self.values[i] * other);
344        }
345
346        Score {
347            values: Arc::from(values),
348        }
349    }
350}
351
352impl Mul<Score> for f32 {
353    type Output = Score;
354
355    fn mul(self, other: Score) -> Score {
356        if other.values.is_empty() {
357            return Score::from(self);
358        }
359
360        let mut values = Vec::with_capacity(other.values.len());
361        for i in 0..other.values.len() {
362            values.push(other.values[i] * self);
363        }
364
365        Score {
366            values: Arc::from(values),
367        }
368    }
369}
370
371impl Div for Score {
372    type Output = Self;
373
374    fn div(self, other: Self) -> Self {
375        if self.values.is_empty() {
376            return other;
377        }
378
379        let mut values = Vec::with_capacity(self.values.len());
380        for i in 0..self.values.len() {
381            values.push(self.values[i] / other.values[i]);
382        }
383
384        Score {
385            values: Arc::from(values),
386        }
387    }
388}
389
390impl Div<f32> for Score {
391    type Output = Self;
392
393    fn div(self, other: f32) -> Self {
394        if self.values.is_empty() {
395            return Score::from(other);
396        }
397
398        let mut values = Vec::with_capacity(self.values.len());
399        for i in 0..self.values.len() {
400            values.push(self.values[i] / other);
401        }
402
403        Score {
404            values: Arc::from(values),
405        }
406    }
407}
408
409impl Sum for Score {
410    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
411        let mut values = vec![];
412
413        for score in iter {
414            for (i, value) in score.values.iter().enumerate() {
415                if values.len() <= i {
416                    values.push(*value);
417                } else {
418                    values[i] += value;
419                }
420            }
421        }
422
423        Score {
424            values: Arc::from(values),
425        }
426    }
427}
428
429impl<'a> Sum<&'a Score> for Score {
430    fn sum<I: Iterator<Item = &'a Score>>(iter: I) -> Self {
431        let mut values = vec![];
432
433        for score in iter {
434            for (i, value) in score.values.iter().enumerate() {
435                if values.len() <= i {
436                    values.push(*value);
437                } else {
438                    values[i] += value;
439                }
440            }
441        }
442
443        Score {
444            values: Arc::from(values),
445        }
446    }
447}
448
449#[cfg(feature = "serde")]
450impl Serialize for Score {
451    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
452    where
453        S: serde::Serializer,
454    {
455        self.values.as_ref().serialize(serializer)
456    }
457}
458
459#[cfg(feature = "serde")]
460impl<'de> Deserialize<'de> for Score {
461    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
462    where
463        D: serde::Deserializer<'de>,
464    {
465        let vec = Vec::<f32>::deserialize(deserializer)?;
466        for value in &vec {
467            if value.is_nan() {
468                return Err(serde::de::Error::custom("Score value cannot be NaN"));
469            }
470        }
471
472        Ok(Score {
473            values: Arc::from(vec),
474        })
475    }
476}
477
478#[cfg(test)]
479mod tests {
480    use super::*;
481
482    #[test]
483    fn test_score_from_vec() {
484        let score = Score::from(vec![1.0, 2.0, 3.0]);
485        assert_eq!(score.values.len(), 3);
486    }
487
488    #[test]
489    fn test_score_from_usize() {
490        let score = Score::from(3);
491        assert_eq!(score.values.len(), 1);
492        assert_eq!(score.as_f32(), 3.0);
493        assert_eq!(score.as_i32(), 3);
494    }
495
496    #[test]
497    fn test_score_from_f32() {
498        let score = Score::from(1.0);
499        assert_eq!(score.as_f32(), 1.0);
500        assert_eq!(score.as_i32(), 1)
501    }
502
503    #[test]
504    fn test_score_from_i32() {
505        let score = Score::from(-5);
506        assert_eq!(score.as_f32(), -5.0);
507        assert_eq!(score.as_i32(), -5);
508    }
509
510    #[test]
511    fn test_score_add() {
512        let score1 = Score::from(vec![1.0, 2.0, 3.0]);
513        let score2 = Score::from(vec![4.0, 5.0, 6.0]);
514        let score3 = score1 + score2;
515
516        assert_eq!(score3.values.len(), 3);
517        assert_eq!(score3.as_f32(), 5.0);
518        assert_eq!(score3[0], 5.0);
519        assert_eq!(score3[1], 7.0);
520        assert_eq!(score3[2], 9.0);
521    }
522
523    #[test]
524    fn test_score_sub() {
525        let score1 = Score::from(vec![5.0, 7.0, 9.0]);
526        let score2 = Score::from(vec![4.0, 5.0, 6.0]);
527        let score3 = score1 - score2;
528        assert_eq!(score3.values.len(), 3);
529        assert_eq!(score3.as_f32(), 1.0);
530        assert_eq!(score3[0], 1.0);
531        assert_eq!(score3[1], 2.0);
532        assert_eq!(score3[2], 3.0);
533    }
534
535    #[test]
536    fn test_score_mul() {
537        let score1 = Score::from(vec![1.0, 2.0, 3.0]);
538        let score2 = Score::from(vec![4.0, 5.0, 6.0]);
539        let score3 = score1 * score2;
540        assert_eq!(score3.values.len(), 3);
541        assert_eq!(score3.as_f32(), 4.0);
542        assert_eq!(score3[0], 4.0);
543        assert_eq!(score3[1], 10.0);
544        assert_eq!(score3[2], 18.0);
545    }
546
547    #[test]
548    fn test_score_div() {
549        let score1 = Score::from(vec![4.0, 8.0, 12.0]);
550        let score2 = Score::from(vec![2.0, 4.0, 6.0]);
551        let score3 = score1 / score2;
552        assert_eq!(score3.values.len(), 3);
553        assert_eq!(score3.as_f32(), 2.0);
554        assert_eq!(score3[0], 2.0);
555        assert_eq!(score3[1], 2.0);
556        assert_eq!(score3[2], 2.0);
557    }
558
559    #[test]
560    #[cfg(feature = "serde")]
561    fn test_score_can_serialize() {
562        let score = Score::from(vec![1.0, 2.0, 3.0]);
563        let serialized = serde_json::to_string(&score).expect("Failed to serialize Score");
564        let deserialized: Score =
565            serde_json::from_str(&serialized).expect("Failed to deserialize Score");
566        assert_eq!(score, deserialized);
567    }
568}