use crate::domain::quantitative::NORMALIZATION_DOMAIN;
use crate::domain::{Quantitative, QuantitativeLimit};
use crate::Valuation;
use std::fmt::{Debug, Display, Formatter};
use std::ops::{Add, Sub};
#[derive(Debug, PartialEq)]
pub struct Interval<'domain, T: QuantitativeLimit> {
domain: &'domain Quantitative<T>,
min: T,
max: T,
}
#[derive(Debug, PartialEq)]
pub enum IntervalError<T: QuantitativeLimit> {
InvalidRange { min: T, max: T },
InvalidMin { min: T, inf: T },
InvalidMax { max: T, sup: T },
}
impl<T: QuantitativeLimit + Display> Display for IntervalError<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
use IntervalError::*;
match &self {
InvalidRange { min, max } => {
write!(f, "Min ({}) > Max ({}).", min, max)
}
InvalidMin { min, inf } => {
write!(f, "Min ({}) < Inf ({}).", min, inf)
}
InvalidMax { max, sup } => {
write!(f, "Max ({}) > Sup ({}).", max, sup)
}
}
}
}
impl<'domain, T: QuantitativeLimit> Valuation for Interval<'domain, T> {}
impl<
'domain,
T: QuantitativeLimit + Copy + Debug + Display + Into<f64> + Add<Output = T> + Sub<Output = T>,
> Interval<'domain, T>
{
pub fn new(domain: &'domain Quantitative<T>, min: T, max: T) -> Result<Self, IntervalError<T>> {
use IntervalError::*;
if min > max {
Err(InvalidRange { min, max })
} else if min < domain.inf() {
Err(InvalidMin {
min,
inf: domain.inf(),
})
} else if max > domain.sup() {
Err(InvalidMax {
max,
sup: domain.sup(),
})
} else {
Ok(Self { domain, min, max })
}
}
pub fn value(&self) -> (T, T) {
(self.min, self.max)
}
pub fn domain(&self) -> &'domain Quantitative<T> {
self.domain
}
pub fn normalize(&self) -> Interval<f64> {
let normalize = |v: f64| {
(v - self.domain.inf().into()) / (self.domain.sup().into() - self.domain.inf().into())
};
Interval::<f64> {
domain: &NORMALIZATION_DOMAIN,
min: normalize(self.min.into()),
max: normalize(self.max.into()),
}
}
pub fn neg(&self) -> Self {
Self {
domain: self.domain,
min: self.domain.sup() + self.domain.inf() - self.max,
max: self.domain.sup() + self.domain.inf() - self.min,
}
}
}
impl<'domain> Interval<'domain, f64> {
pub fn resume(&self) -> f64 {
(self.max / 2.0) + (self.min / 2.0)
}
}
impl<'domain> Interval<'domain, f32> {
pub fn resume(&self) -> f32 {
(self.max / 2.0) + (self.min / 2.0)
}
}
impl<'domain> Interval<'domain, i32> {
pub fn resume(&self) -> i32 {
(self.max / 2) + (self.min / 2)
}
}