use radiate_error::RadiateError;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use std::hash::Hash;
use std::iter::Sum;
use std::ops::{Add, Div, Index, Mul, Sub};
use std::sync::Arc;
pub trait Scored {
fn score(&self) -> Option<&Score>;
}
#[derive(Clone, PartialEq, Default)]
#[repr(transparent)]
pub struct Score {
values: Arc<[f32]>,
}
impl Score {
pub fn from_vec(values: Vec<f32>) -> Self {
if values.iter().any(|&v| v.is_nan()) {
panic!("Score value cannot be NaN");
}
Score {
values: Arc::from(values),
}
}
pub fn is_multi_objective(&self) -> bool {
self.values.len() > 1
}
pub fn objective(&self, idx: usize) -> Option<&f32> {
self.values.get(idx)
}
pub fn as_slice(&self) -> &[f32] {
&self.values
}
pub fn as_f32(&self) -> f32 {
self.values.get(0).cloned().unwrap_or(f32::NAN)
}
pub fn as_f64(&self) -> f64 {
self.values.get(0).cloned().unwrap_or(f32::NAN) as f64
}
pub fn as_i32(&self) -> i32 {
self.values[0] as i32
}
pub fn as_string(&self) -> String {
self.values[0].to_string()
}
pub fn as_usize(&self) -> usize {
self.values[0] as usize
}
pub fn iter(&self) -> impl Iterator<Item = &f32> + '_ {
self.values.iter()
}
pub fn len(&self) -> usize {
self.values.len()
}
}
impl AsRef<[f32]> for Score {
fn as_ref(&self) -> &[f32] {
&self.values
}
}
impl PartialOrd for Score {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.values.partial_cmp(&other.values)
}
}
impl Debug for Score {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.values)
}
}
impl Hash for Score {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
let mut hash: usize = 0;
for value in self.values.iter() {
let value_hash = value.to_bits();
hash = hash.wrapping_add(value_hash as usize);
}
hash.hash(state);
}
}
impl Index<usize> for Score {
type Output = f32;
fn index(&self, index: usize) -> &Self::Output {
&self.values[index]
}
}
impl Into<Vec<f32>> for Score {
fn into(self) -> Vec<f32> {
self.values.to_vec()
}
}
impl From<f32> for Score {
fn from(value: f32) -> Self {
if value.is_nan() {
panic!("Score value cannot be NaN")
}
Score {
values: Arc::from(vec![value]),
}
}
}
impl TryFrom<i16> for Score {
type Error = RadiateError;
fn try_from(value: i16) -> Result<Self, Self::Error> {
Ok(Score {
values: Arc::from(vec![value as f32]),
})
}
}
impl From<f64> for Score {
fn from(value: f64) -> Self {
if value.is_nan() {
panic!("Score value cannot be NaN")
}
Score {
values: Arc::from(vec![value as f32]),
}
}
}
impl From<i32> for Score {
fn from(value: i32) -> Self {
Score {
values: Arc::from(vec![value as f32]),
}
}
}
impl From<i64> for Score {
fn from(value: i64) -> Self {
Score {
values: Arc::from(vec![value as f32]),
}
}
}
impl From<usize> for Score {
fn from(value: usize) -> Self {
Score {
values: Arc::from(vec![value as f32]),
}
}
}
impl From<String> for Score {
fn from(value: String) -> Self {
Score {
values: Arc::from(vec![
value.parse::<f32>().expect("Failed to parse string to f32"),
]),
}
}
}
impl From<&str> for Score {
fn from(value: &str) -> Self {
Score {
values: Arc::from(vec![
value.parse::<f32>().expect("Failed to parse string to f32"),
]),
}
}
}
impl From<Vec<f32>> for Score {
fn from(value: Vec<f32>) -> Self {
Score::from_vec(value)
}
}
impl From<Vec<f64>> for Score {
fn from(value: Vec<f64>) -> Self {
Score::from_vec(value.into_iter().map(|v| v as f32).collect())
}
}
impl From<Vec<i32>> for Score {
fn from(value: Vec<i32>) -> Self {
Score::from_vec(value.into_iter().map(|v| v as f32).collect())
}
}
impl From<Vec<i64>> for Score {
fn from(value: Vec<i64>) -> Self {
Score::from_vec(value.into_iter().map(|v| v as f32).collect())
}
}
impl From<Vec<usize>> for Score {
fn from(value: Vec<usize>) -> Self {
Score::from_vec(value.into_iter().map(|v| v as f32).collect())
}
}
impl From<Vec<String>> for Score {
fn from(value: Vec<String>) -> Self {
Score::from_vec(
value
.into_iter()
.map(|v| v.parse::<f32>().unwrap())
.collect(),
)
}
}
impl From<Vec<&str>> for Score {
fn from(value: Vec<&str>) -> Self {
Score::from_vec(
value
.into_iter()
.map(|v| v.parse::<f32>().unwrap())
.collect(),
)
}
}
impl Add for Score {
type Output = Self;
fn add(self, other: Self) -> Self {
if self.values.is_empty() {
return other;
}
let mut values = Vec::with_capacity(self.values.len());
for i in 0..self.values.len() {
values.push(self.values[i] + other.values[i]);
}
Score {
values: Arc::from(values),
}
}
}
impl Add<f32> for Score {
type Output = Self;
fn add(self, other: f32) -> Self {
if self.values.is_empty() {
return Score::from(other);
}
let mut values = Vec::with_capacity(self.values.len());
for i in 0..self.values.len() {
values.push(self.values[i] + other);
}
Score {
values: Arc::from(self.values),
}
}
}
impl Sub for Score {
type Output = Self;
fn sub(self, other: Self) -> Self {
if self.values.is_empty() {
return other;
}
let mut values = Vec::with_capacity(self.values.len());
for i in 0..self.values.len() {
values.push(self.values[i] - other.values[i]);
}
Score {
values: Arc::from(values),
}
}
}
impl Sub<f32> for Score {
type Output = Self;
fn sub(self, other: f32) -> Self {
if self.values.is_empty() {
return Score::from(-other);
}
let mut values = Vec::with_capacity(self.values.len());
for i in 0..self.values.len() {
values.push(self.values[i] - other);
}
Score {
values: Arc::from(values),
}
}
}
impl Mul for Score {
type Output = Self;
fn mul(self, other: Self) -> Self {
if self.values.is_empty() {
return other;
}
let mut values = Vec::with_capacity(self.values.len());
for i in 0..self.values.len() {
values.push(self.values[i] * other.values[i]);
}
Score {
values: Arc::from(values),
}
}
}
impl Mul<f32> for Score {
type Output = Self;
fn mul(self, other: f32) -> Self {
if self.values.is_empty() {
return Score::from(other);
}
let mut values = Vec::with_capacity(self.values.len());
for i in 0..self.values.len() {
values.push(self.values[i] * other);
}
Score {
values: Arc::from(values),
}
}
}
impl Mul<Score> for f32 {
type Output = Score;
fn mul(self, other: Score) -> Score {
if other.values.is_empty() {
return Score::from(self);
}
let mut values = Vec::with_capacity(other.values.len());
for i in 0..other.values.len() {
values.push(other.values[i] * self);
}
Score {
values: Arc::from(values),
}
}
}
impl Div for Score {
type Output = Self;
fn div(self, other: Self) -> Self {
if self.values.is_empty() {
return other;
}
let mut values = Vec::with_capacity(self.values.len());
for i in 0..self.values.len() {
values.push(self.values[i] / other.values[i]);
}
Score {
values: Arc::from(values),
}
}
}
impl Div<f32> for Score {
type Output = Self;
fn div(self, other: f32) -> Self {
if self.values.is_empty() {
return Score::from(other);
}
let mut values = Vec::with_capacity(self.values.len());
for i in 0..self.values.len() {
values.push(self.values[i] / other);
}
Score {
values: Arc::from(values),
}
}
}
impl Sum for Score {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
let mut values = vec![];
for score in iter {
for (i, value) in score.values.iter().enumerate() {
if values.len() <= i {
values.push(*value);
} else {
values[i] += value;
}
}
}
Score {
values: Arc::from(values),
}
}
}
impl<'a> Sum<&'a Score> for Score {
fn sum<I: Iterator<Item = &'a Score>>(iter: I) -> Self {
let mut values = vec![];
for score in iter {
for (i, value) in score.values.iter().enumerate() {
if values.len() <= i {
values.push(*value);
} else {
values[i] += value;
}
}
}
Score {
values: Arc::from(values),
}
}
}
#[cfg(feature = "serde")]
impl Serialize for Score {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.values.as_ref().serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for Score {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let vec = Vec::<f32>::deserialize(deserializer)?;
for value in &vec {
if value.is_nan() {
return Err(serde::de::Error::custom("Score value cannot be NaN"));
}
}
Ok(Score {
values: Arc::from(vec),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_score_from_vec() {
let score = Score::from(vec![1.0, 2.0, 3.0]);
assert_eq!(score.values.len(), 3);
}
#[test]
fn test_score_from_usize() {
let score = Score::from(3);
assert_eq!(score.values.len(), 1);
assert_eq!(score.as_f32(), 3.0);
assert_eq!(score.as_i32(), 3);
}
#[test]
fn test_score_from_f32() {
let score = Score::from(1.0);
assert_eq!(score.as_f32(), 1.0);
assert_eq!(score.as_i32(), 1)
}
#[test]
fn test_score_from_i32() {
let score = Score::from(-5);
assert_eq!(score.as_f32(), -5.0);
assert_eq!(score.as_i32(), -5);
}
#[test]
fn test_score_add() {
let score1 = Score::from(vec![1.0, 2.0, 3.0]);
let score2 = Score::from(vec![4.0, 5.0, 6.0]);
let score3 = score1 + score2;
assert_eq!(score3.values.len(), 3);
assert_eq!(score3.as_f32(), 5.0);
assert_eq!(score3[0], 5.0);
assert_eq!(score3[1], 7.0);
assert_eq!(score3[2], 9.0);
}
#[test]
fn test_score_sub() {
let score1 = Score::from(vec![5.0, 7.0, 9.0]);
let score2 = Score::from(vec![4.0, 5.0, 6.0]);
let score3 = score1 - score2;
assert_eq!(score3.values.len(), 3);
assert_eq!(score3.as_f32(), 1.0);
assert_eq!(score3[0], 1.0);
assert_eq!(score3[1], 2.0);
assert_eq!(score3[2], 3.0);
}
#[test]
fn test_score_mul() {
let score1 = Score::from(vec![1.0, 2.0, 3.0]);
let score2 = Score::from(vec![4.0, 5.0, 6.0]);
let score3 = score1 * score2;
assert_eq!(score3.values.len(), 3);
assert_eq!(score3.as_f32(), 4.0);
assert_eq!(score3[0], 4.0);
assert_eq!(score3[1], 10.0);
assert_eq!(score3[2], 18.0);
}
#[test]
fn test_score_div() {
let score1 = Score::from(vec![4.0, 8.0, 12.0]);
let score2 = Score::from(vec![2.0, 4.0, 6.0]);
let score3 = score1 / score2;
assert_eq!(score3.values.len(), 3);
assert_eq!(score3.as_f32(), 2.0);
assert_eq!(score3[0], 2.0);
assert_eq!(score3[1], 2.0);
assert_eq!(score3[2], 2.0);
}
#[test]
#[cfg(feature = "serde")]
fn test_score_can_serialize() {
let score = Score::from(vec![1.0, 2.0, 3.0]);
let serialized = serde_json::to_string(&score).expect("Failed to serialize Score");
let deserialized: Score =
serde_json::from_str(&serialized).expect("Failed to deserialize Score");
assert_eq!(score, deserialized);
}
}