Skip to main content

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