use crate::*;
#[derive(Clone, Debug)]
pub struct DivisibilityOrder<A>
where
A: IntegralDomain,
{
base: A,
}
impl<A: IntegralDomain> DivisibilityOrder<A> {
pub fn new(base: A) -> Self {
Self { base }
}
pub fn base(&self) -> &A {
&self.base
}
}
impl<A: IntegralDomain> Domain for DivisibilityOrder<A> {
type Elem = A::Elem;
fn contains(&self, elem: &Self::Elem) -> bool {
self.base.is_zero(elem) || self.base.is_one(&self.base.associate_coef(elem))
}
fn equals(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> bool {
self.base.equals(elem1, elem2)
}
}
impl<A: IntegralDomain> PartialOrder for DivisibilityOrder<A> {
fn leq(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> bool {
self.base.divisible(elem2, elem1)
}
}
impl<A: IntegralDomain> BoundedOrder for DivisibilityOrder<A> {
fn max(&self) -> Self::Elem {
self.base.zero()
}
fn min(&self) -> Self::Elem {
self.base.one()
}
}
impl<A: EuclideanDomain> Lattice for DivisibilityOrder<A> {
fn meet(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem {
let elem = self.base.gcd(elem1, elem2);
self.base.associate_repr(&elem)
}
fn join(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem {
let elem = self.base.lcm(elem1, elem2);
self.base.associate_repr(&elem)
}
}
impl<A: EuclideanDomain> DistributiveLattice for DivisibilityOrder<A> {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn order() {
let lat = DivisibilityOrder::new(I32);
for a in -50..50 {
if a < 0 {
assert!(!lat.contains(&a));
continue;
}
for b in 0..50 {
let c = lat.meet(&a, &b);
assert!(lat.contains(&c));
assert!(lat.leq(&c, &a));
assert!(lat.leq(&c, &b));
let d = lat.join(&a, &b);
assert!(lat.contains(&d));
assert!(lat.leq(&a, &d));
assert!(lat.leq(&a, &d));
if lat.leq(&a, &b) {
assert!(c == a);
assert!(d == b);
}
}
}
}
}