ebi_arithmetic 0.3.12

Exact arithmetic for Ebi - a stochastic process mining utility
Documentation
use crate::{
    Zero,
    fraction::{
        fraction_enum::FractionEnum, fraction_exact::FractionExact, fraction_f64::FractionF64,
    },
    log_polynomial::{
        log_polynomial_enum::LogPolynomialEnum, log_polynomial_exact::LogPolynomialExact,
        log_polynomial_f64::LogPolynomialF64,
    },
};
use malachite::{Natural, Rational, base::num::basic::traits::Two};
use std::{collections::hash_map::Entry, ops::SubAssign};

impl SubAssign for LogPolynomialExact {
    fn sub_assign(&mut self, rhs: Self) {
        for (argument, coefficient) in rhs.argument2coefficient.into_iter() {
            match self.argument2coefficient.entry(argument) {
                Entry::Occupied(mut occupied_entry) => {
                    *occupied_entry.get_mut() -= coefficient;
                    if occupied_entry.get().is_zero() {
                        occupied_entry.remove_entry();
                    }
                }
                Entry::Vacant(vacant_entry) => {
                    vacant_entry.insert(-coefficient);
                }
            };
        }
    }
}

impl SubAssign<&LogPolynomialExact> for LogPolynomialExact {
    fn sub_assign(&mut self, rhs: &Self) {
        for (argument, coefficient) in rhs.argument2coefficient.iter() {
            match self.argument2coefficient.entry(argument.clone()) {
                Entry::Occupied(mut occupied_entry) => {
                    *occupied_entry.get_mut() -= coefficient;
                    if occupied_entry.get().is_zero() {
                        occupied_entry.remove_entry();
                    }
                }
                Entry::Vacant(vacant_entry) => {
                    vacant_entry.insert(-coefficient);
                }
            };
        }
    }
}

impl SubAssign<FractionExact> for LogPolynomialExact {
    fn sub_assign(&mut self, rhs: FractionExact) {
        match self.argument2coefficient.entry(Natural::TWO) {
            Entry::Occupied(mut occupied_entry) => {
                *occupied_entry.get_mut() -= rhs.0;
                if occupied_entry.get().is_zero() {
                    occupied_entry.remove_entry();
                }
            }
            Entry::Vacant(vacant_entry) => {
                vacant_entry.insert(-rhs.0);
            }
        };
    }
}

impl SubAssign<&FractionExact> for LogPolynomialExact {
    fn sub_assign(&mut self, rhs: &FractionExact) {
        match self.argument2coefficient.entry(Natural::TWO) {
            Entry::Occupied(mut occupied_entry) => {
                *occupied_entry.get_mut() -= &rhs.0;
                if occupied_entry.get().is_zero() {
                    occupied_entry.remove_entry();
                }
            }
            Entry::Vacant(vacant_entry) => {
                vacant_entry.insert(-&rhs.0);
            }
        };
    }
}

impl SubAssign<Rational> for LogPolynomialExact {
    fn sub_assign(&mut self, rhs: Rational) {
        match self.argument2coefficient.entry(Natural::TWO) {
            Entry::Occupied(mut occupied_entry) => {
                *occupied_entry.get_mut() -= &rhs;
                if occupied_entry.get().is_zero() {
                    occupied_entry.remove_entry();
                }
            }
            Entry::Vacant(vacant_entry) => {
                vacant_entry.insert(-rhs);
            }
        };
    }
}

impl SubAssign<&Rational> for LogPolynomialExact {
    fn sub_assign(&mut self, rhs: &Rational) {
        match self.argument2coefficient.entry(Natural::TWO) {
            Entry::Occupied(mut occupied_entry) => {
                *occupied_entry.get_mut() -= rhs;
                if occupied_entry.get().is_zero() {
                    occupied_entry.remove_entry();
                }
            }
            Entry::Vacant(vacant_entry) => {
                vacant_entry.insert(-rhs);
            }
        };
    }
}

impl SubAssign for LogPolynomialF64 {
    fn sub_assign(&mut self, rhs: Self) {
        self.0 -= rhs.0
    }
}

impl SubAssign<&LogPolynomialF64> for LogPolynomialF64 {
    fn sub_assign(&mut self, rhs: &Self) {
        self.0 -= rhs.0
    }
}

impl SubAssign<FractionF64> for LogPolynomialF64 {
    fn sub_assign(&mut self, rhs: FractionF64) {
        self.0 -= rhs.0
    }
}

impl SubAssign<&FractionF64> for LogPolynomialF64 {
    fn sub_assign(&mut self, rhs: &FractionF64) {
        self.0 -= rhs.0
    }
}

impl SubAssign<f64> for LogPolynomialF64 {
    fn sub_assign(&mut self, rhs: f64) {
        self.0 -= rhs
    }
}

impl SubAssign<&f64> for LogPolynomialF64 {
    fn sub_assign(&mut self, rhs: &f64) {
        self.0 -= rhs
    }
}

impl SubAssign for LogPolynomialEnum {
    fn sub_assign(&mut self, rhs: Self) {
        if self.matches(&rhs) {
            match (self, rhs) {
                (LogPolynomialEnum::Approx(lp), LogPolynomialEnum::Approx(f)) => lp.sub_assign(f),
                (LogPolynomialEnum::Exact(lp), LogPolynomialEnum::Exact(f)) => lp.sub_assign(f),
                _ => {}
            }
        } else {
            *self = LogPolynomialEnum::CannotCombineExactAndApprox
        }
    }
}

impl SubAssign<&LogPolynomialEnum> for LogPolynomialEnum {
    fn sub_assign(&mut self, rhs: &Self) {
        if self.matches(&rhs) {
            match (self, rhs) {
                (LogPolynomialEnum::Approx(lp), LogPolynomialEnum::Approx(f)) => lp.sub_assign(f),
                (LogPolynomialEnum::Exact(lp), LogPolynomialEnum::Exact(f)) => lp.sub_assign(f),
                _ => {}
            }
        } else {
            *self = LogPolynomialEnum::CannotCombineExactAndApprox
        }
    }
}

impl SubAssign<FractionEnum> for LogPolynomialEnum {
    fn sub_assign(&mut self, rhs: FractionEnum) {
        if self.matches_fraction(&rhs) {
            match (self, rhs) {
                (LogPolynomialEnum::Approx(lp), FractionEnum::Approx(f)) => lp.sub_assign(f),
                (LogPolynomialEnum::Exact(lp), FractionEnum::Exact(f)) => lp.sub_assign(f),
                _ => {}
            }
        } else {
            *self = LogPolynomialEnum::CannotCombineExactAndApprox
        }
    }
}

impl SubAssign<&FractionEnum> for LogPolynomialEnum {
    fn sub_assign(&mut self, rhs: &FractionEnum) {
        if self.matches_fraction(&rhs) {
            match (self, rhs) {
                (LogPolynomialEnum::Approx(lp), FractionEnum::Approx(f)) => lp.sub_assign(f),
                (LogPolynomialEnum::Exact(lp), FractionEnum::Exact(f)) => lp.sub_assign(f),
                _ => {}
            }
        } else {
            *self = LogPolynomialEnum::CannotCombineExactAndApprox
        }
    }
}

macro_rules! subassign_primitive {
    ($t:ty) => {
        impl SubAssign<$t> for LogPolynomialExact {
            fn sub_assign(&mut self, rhs: $t) {
                self.sub_assign(Rational::from(rhs))
            }
        }

        impl SubAssign<$t> for LogPolynomialF64 {
            fn sub_assign(&mut self, rhs: $t) {
                self.sub_assign(rhs as f64)
            }
        }

        impl SubAssign<$t> for LogPolynomialEnum {
            fn sub_assign(&mut self, rhs: $t) {
                match self {
                    LogPolynomialEnum::Exact(lp) => lp.sub_assign(rhs),
                    LogPolynomialEnum::Approx(lp) => lp.sub_assign(rhs),
                    LogPolynomialEnum::CannotCombineExactAndApprox => {}
                }
            }
        }
    };
}
subassign_primitive!(usize);
subassign_primitive!(u128);
subassign_primitive!(u64);
subassign_primitive!(u32);
subassign_primitive!(u16);
subassign_primitive!(u8);
subassign_primitive!(i128);
subassign_primitive!(i64);
subassign_primitive!(i32);
subassign_primitive!(i16);
subassign_primitive!(i8);

#[cfg(test)]
pub mod tests {
    use crate::{One, Zero, log_polynomial::log_polynomial::LogPolynomial};

    #[test]
    fn sub() {
        let mut a = LogPolynomial::one();
        a -= LogPolynomial::one();
        assert_eq!(a, LogPolynomial::zero());

        let mut b = LogPolynomial::from(2);
        b -= 1;
        assert_eq!(b, LogPolynomial::one());
    }
}