use crate::*;
use num::{Float, One, Zero};
use std::fmt::Debug;
use std::marker::PhantomData;
pub const F32: ApproxFloats<f32> = ApproxFloats {
phantom: PhantomData,
};
pub const F64: ApproxFloats<f64> = ApproxFloats {
phantom: PhantomData,
};
#[derive(Clone, Debug)]
pub struct ApproxFloats<E> {
phantom: PhantomData<E>,
}
impl<E> Domain for ApproxFloats<E>
where
E: Float + Debug + Zero + One + From<isize>,
{
type Elem = E;
fn contains(&self, elem: &Self::Elem) -> bool {
elem.is_finite()
}
fn equals(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> bool {
elem1 == elem2
}
}
impl<E> Semigroup for ApproxFloats<E>
where
E: Float + Debug + Zero + One + From<isize>,
{
fn mul(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem {
let elem = *elem1 * *elem2;
assert!(elem.is_finite());
elem
}
}
impl<E> Monoid for ApproxFloats<E>
where
E: Float + Debug + Zero + One + From<isize>,
{
fn one(&self) -> Self::Elem {
One::one()
}
fn try_inv(&self, elem: &Self::Elem) -> Option<Self::Elem> {
let elem = self.one() / *elem;
if elem.is_finite() {
Some(elem)
} else {
None
}
}
}
impl<E> AbelianGroup for ApproxFloats<E>
where
E: Float + Debug + Zero + One + From<isize>,
{
fn zero(&self) -> Self::Elem {
Zero::zero()
}
fn is_zero(&self, elem: &Self::Elem) -> bool {
elem.is_zero()
}
fn neg(&self, elem: &Self::Elem) -> Self::Elem {
let elem = -*elem;
assert!(elem.is_finite());
elem
}
fn add(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem {
let elem = *elem1 + *elem2;
assert!(elem.is_finite());
elem
}
fn sub(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem {
let elem = *elem1 - *elem2;
assert!(elem.is_finite());
elem
}
fn times(&self, num: isize, elem: &Self::Elem) -> Self::Elem {
let num: Self::Elem = num.into();
num * *elem
}
}
impl<E> UnitaryRing for ApproxFloats<E> where E: Float + Debug + Zero + One + From<isize> {}
impl<E> Field for ApproxFloats<E>
where
E: Float + Debug + Zero + One + From<isize>,
{
fn inv(&self, elem: &Self::Elem) -> Self::Elem {
self.div(&self.one(), elem)
}
fn div(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem {
assert!(!self.is_zero(elem2));
let elem = *elem1 / *elem2;
assert!(elem.is_finite());
elem
}
}
impl<E> PartialOrder for ApproxFloats<E>
where
E: Float + Debug + Zero + One + From<isize>,
{
fn leq(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> bool {
*elem1 <= *elem2
}
}
impl<E> Lattice for ApproxFloats<E>
where
E: Float + Debug + Zero + One + From<isize>,
{
fn meet(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem {
elem1.min(*elem2)
}
fn join(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem {
elem1.max(*elem2)
}
}
impl<E> DistributiveLattice for ApproxFloats<E> where E: Float + Debug + Zero + One + From<isize> {}