use std::{cmp::Ordering, fmt::Debug};
use derive_more::{Add, Mul, Neg, Sub};
use serde::Serialize;
use crate::problems::objective::{IllegalObjective, Objective};
#[derive(Copy, Clone, Serialize, PartialEq, PartialOrd, Add, Sub, Mul, Neg)]
pub struct SingleObjective(f64);
impl SingleObjective {
pub fn is_finite(&self) -> bool {
self.0.is_finite()
}
pub fn value(&self) -> f64 {
self.0
}
}
impl Debug for SingleObjective {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.0)
}
}
impl Eq for SingleObjective {}
#[allow(clippy::derive_ord_xor_partial_ord)]
impl Ord for SingleObjective {
fn cmp(&self, other: &Self) -> Ordering {
self.partial_cmp(other).unwrap()
}
}
impl Objective for SingleObjective {}
impl Default for SingleObjective {
fn default() -> Self {
Self(f64::INFINITY)
}
}
impl From<SingleObjective> for f64 {
fn from(value: SingleObjective) -> Self {
value.value()
}
}
impl TryFrom<f64> for SingleObjective {
type Error = IllegalObjective;
fn try_from(value: f64) -> Result<Self, Self::Error> {
match value {
x if x.is_nan() => Err(IllegalObjective::NaN),
x if x.is_infinite() && x.is_sign_negative() => Err(IllegalObjective::NegativeInfinity),
x => Ok(SingleObjective(x)),
}
}
}
#[cfg(test)]
mod tests {
use super::SingleObjective;
#[test]
fn is_finite_returns_true_for_finite() {
assert!(SingleObjective(0.).is_finite());
assert!(SingleObjective(-1.).is_finite());
assert!(SingleObjective(1.).is_finite());
assert!(SingleObjective(1e200).is_finite());
assert!(SingleObjective(-1e200).is_finite());
}
#[test]
fn is_finite_returns_false_for_infinite() {
assert!(!SingleObjective(f64::INFINITY).is_finite());
}
#[test]
fn try_from_invalid_is_err() {
assert!(SingleObjective::try_from(f64::NAN).is_err());
assert!(SingleObjective::try_from(f64::NEG_INFINITY).is_err());
}
}