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