use crate::*;
use std::fmt::Debug;
pub trait Domain: Clone {
type Elem: Clone + Debug;
fn contains(&self, _elem: &Self::Elem) -> bool {
true
}
fn equals(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> bool;
}
pub trait Semigroup: Domain {
fn mul(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem;
fn mul_assign(&self, elem1: &mut Self::Elem, elem2: &Self::Elem) {
*elem1 = self.mul(elem1, elem2);
}
fn square(&self, elem: &mut Self::Elem) {
*elem = self.mul(elem, elem);
}
}
pub trait Monoid: Semigroup {
fn one(&self) -> Self::Elem;
fn is_one(&self, elem: &Self::Elem) -> bool {
self.equals(elem, &self.one())
}
fn try_inv(&self, elem: &Self::Elem) -> Option<Self::Elem>;
fn invertible(&self, elem: &Self::Elem) -> bool {
self.try_inv(elem).is_some()
}
}
pub trait Group: Monoid {
fn inv(&self, elem: &Self::Elem) -> Self::Elem {
self.try_inv(elem).unwrap()
}
fn power(&self, mut num: isize, elem: &Self::Elem) -> Self::Elem {
let mut elem = if num < 0 {
num = -num;
self.inv(elem)
} else {
elem.clone()
};
let mut res = self.one();
while num > 0 {
if num % 2 != 0 {
self.mul_assign(&mut res, &elem);
}
num /= 2;
self.square(&mut elem);
}
res
}
}
pub trait AbelianGroup: Domain {
fn zero(&self) -> Self::Elem;
fn is_zero(&self, elem: &Self::Elem) -> bool {
self.equals(elem, &self.zero())
}
fn neg(&self, elem: &Self::Elem) -> Self::Elem;
fn neg_assign(&self, elem: &mut Self::Elem) {
*elem = self.neg(elem);
}
fn add(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem;
fn add_assign(&self, elem1: &mut Self::Elem, elem2: &Self::Elem) {
*elem1 = self.add(elem1, elem2);
}
fn double(&self, elem: &mut Self::Elem) {
*elem = self.add(elem, elem);
}
fn sub(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem {
let mut elem = self.neg(elem2);
self.add_assign(&mut elem, elem1);
elem
}
fn sub_assign(&self, elem1: &mut Self::Elem, elem2: &Self::Elem) {
self.add_assign(elem1, &self.neg(elem2));
}
fn times(&self, num: isize, elem: &Self::Elem) -> Self::Elem {
let group = AdditiveGroup::new(self.clone());
group.power(num, elem)
}
}
pub trait UnitaryRing: AbelianGroup + Monoid {
fn int(&self, elem: isize) -> Self::Elem {
self.times(elem, &self.one())
}
}
pub trait IntegralDomain: UnitaryRing {
fn try_div(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Option<Self::Elem>;
fn divisible(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> bool {
if self.is_zero(elem2) {
self.is_zero(elem1)
} else {
self.try_div(elem1, elem2).is_some()
}
}
fn associates(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> bool {
self.divisible(elem1, elem2) && self.divisible(elem2, elem1)
}
fn associate_repr(&self, elem: &Self::Elem) -> Self::Elem;
fn associate_coef(&self, elem: &Self::Elem) -> Self::Elem;
}
pub trait EuclideanDomain: IntegralDomain {
fn quo_rem(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> (Self::Elem, Self::Elem);
fn quo(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem {
self.quo_rem(elem1, elem2).0
}
fn rem(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem {
self.quo_rem(elem1, elem2).1
}
fn reduced(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> bool {
self.is_zero(elem2) || self.is_zero(&self.quo(elem1, elem2))
}
fn gcd(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem {
let mut elem1 = elem1.clone();
let mut elem2 = elem2.clone();
while !self.is_zero(&elem2) {
let rem = self.rem(&elem1, &elem2);
elem1 = elem2;
elem2 = rem;
}
elem1
}
fn lcm(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem {
let gcd = self.gcd(elem1, elem2);
if self.is_zero(&gcd) {
gcd
} else {
self.mul(&self.quo(elem1, &gcd), elem2)
}
}
fn extended_gcd(
&self,
elem1: &Self::Elem,
elem2: &Self::Elem,
) -> (Self::Elem, Self::Elem, Self::Elem) {
if self.is_zero(elem2) {
(elem1.clone(), self.one(), self.zero())
} else {
let (quo, rem) = self.quo_rem(elem1, elem2);
let (gcd, x, y) = self.extended_gcd(elem2, &rem);
let z = self.sub(&x, &self.mul(&y, &quo));
(gcd, y, z)
}
}
fn relative_primes(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> bool {
let gcd = self.gcd(elem1, elem2);
self.invertible(&gcd)
}
}
pub trait Field: EuclideanDomain {
fn inv(&self, elem: &Self::Elem) -> Self::Elem;
fn div(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem {
self.mul(elem1, &self.inv(elem2))
}
fn power(&self, num: isize, elem: &Self::Elem) -> Self::Elem {
if self.is_zero(elem) {
self.zero()
} else {
let group = MultiplicativeGroup::new(self.clone());
group.power(num, elem)
}
}
}
impl<A: Field> IntegralDomain for A {
fn try_div(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Option<Self::Elem> {
Some(self.div(elem1, elem2))
}
fn associate_repr(&self, elem: &Self::Elem) -> Self::Elem {
if self.is_zero(elem) {
self.zero()
} else {
self.one()
}
}
fn associate_coef(&self, elem: &Self::Elem) -> Self::Elem {
self.inv(elem)
}
}
impl<A: Field> EuclideanDomain for A {
fn quo_rem(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> (Self::Elem, Self::Elem) {
assert!(!self.is_zero(elem2));
(self.div(elem1, elem2), self.zero())
}
fn quo(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem {
assert!(!self.is_zero(elem2));
self.div(elem1, elem2)
}
fn rem(&self, _elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem {
assert!(!self.is_zero(elem2));
self.zero()
}
fn reduced(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> bool {
self.is_zero(elem1) || self.is_zero(elem2)
}
fn gcd(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem {
if self.is_zero(elem1) && self.is_zero(elem2) {
self.zero()
} else {
self.one()
}
}
fn lcm(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem {
if self.is_zero(elem1) || self.is_zero(elem2) {
self.zero()
} else {
self.one()
}
}
}
pub trait PartialOrder: Domain {
fn leq(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> bool;
fn less_than(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> bool {
!self.equals(elem1, elem2) && self.leq(elem1, elem2)
}
fn comparable(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> bool {
self.leq(elem1, elem2) || self.leq(elem2, elem1)
}
}
pub trait BoundedOrder: PartialOrder {
fn max(&self) -> Self::Elem;
fn min(&self) -> Self::Elem;
}
pub trait Lattice: PartialOrder {
fn meet(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem;
fn join(&self, elem1: &Self::Elem, elem2: &Self::Elem) -> Self::Elem;
}
pub trait DistributiveLattice: Lattice {}
pub trait BooleanAlgebra: DistributiveLattice + BoundedOrder {
fn not(&self, elem: &Self::Elem) -> Self::Elem;
}