#![doc(include = "../../doc/references.md")]
use crate::helpers::*;
use crate::numeric::*;
use crate::com_ring::*;
pub trait Field: ComRing {
fn invert(&self) -> Self;
fn is_invertible(&self) -> bool {
*self != Self::zero()
}
fn div(&self, other: &Self) -> Self {
self.mul(&other.invert())
}
}
pub trait FieldLaws: Field {
fn left_inverse(&self) -> bool {
self.invert().mul(self) == Self::one()
}
fn right_inverse(&self) -> bool {
self.mul(&self.invert()) == Self::one()
}
fn inverse(&self) -> bool {
self.left_inverse() && self.right_inverse()
}
fn add_cancellation(&self, x: &Self, y: &Self) -> bool {
imply(self.add(x) == y.add(x), self == y)
}
fn mul_cancellation(&self, x: &Self, y: &Self) -> bool {
if x.is_zero() {return true;}
imply(self.mul(x) == y.mul(x), self == y)
}
fn zero_cancellation(&self, x: &Self) -> bool {
imply(self.mul(x).is_zero(), self.is_zero() || x.is_zero())
}
}
impl<F: Field> FieldLaws for F {}
pub trait NumFieldLaws: NumEq + Field {
fn num_left_inverse(&self, eps: &Self::Eps) -> bool {
self.invert().mul(self).num_eq(&Self::one(), eps)
}
fn num_right_inverse(&self, eps: &Self::Eps) -> bool {
self.mul(&self.invert()).num_eq(&Self::one(), eps)
}
fn num_inverse(&self, eps: &Self::Eps) -> bool {
self.num_left_inverse(eps) && self.num_right_inverse(eps)
}
fn num_add_cancellation(&self, x: &Self, y: &Self, eps: &Self::Eps) -> bool {
imply(self.add(x).num_eq(&y.add(x), eps), self.num_eq(&y, eps))
}
fn num_mul_cancellation(&self, x: &Self, y: &Self, eps: &Self::Eps) -> bool {
if x.is_zero() {return true;}
imply(self.mul(x).num_eq(&y.mul(x), eps), self.num_eq(&y, eps))
}
fn num_zero_cancellation(&self, x: &Self, _: &Self::Eps) -> bool {
imply(self.mul(x).is_zero(), self.is_zero() || x.is_zero())
}
}
impl<F: NumEq + Field> NumFieldLaws for F {}
macro_rules! float_field {
($type:ty) => {
impl Field for $type {
fn invert(&self) -> Self {
self.recip()
}
}
};
($type:ty, $($others:ty),+) => {
float_field! {$type}
float_field! {$($others),+}
};
}
float_field! {
f32, f64
}
impl Field for () {
fn invert(&self) -> Self {}
fn is_invertible(&self) -> bool {
true
}
}
impl<A: Field> Field for (A,) {
fn invert(&self) -> Self {
(self.0.invert(), )
}
fn is_invertible(&self) -> bool {
self.0.is_invertible()
}
}
impl<A: Field, B: Field> Field for (A, B) {
fn invert(&self) -> Self {
(self.0.invert(), self.1.invert())
}
fn is_invertible(&self) -> bool {
self.0.is_invertible() && self.1.is_invertible()
}
}
impl<A: Field, B: Field, C: Field> Field for (A, B, C) {
fn invert(&self) -> Self {
let (a, b, c) = self;
(a.invert(), b.invert(), c.invert())
}
fn is_invertible(&self) -> bool {
let (a, b, c) = self;
a.is_invertible() && b.is_invertible() && c.is_invertible()
}
}
macro_rules! array_field {
($size:expr) => {
impl<T: Copy + Field> Field for [T; $size] {
fn invert(&self) -> Self {
self.map(&|&x| x.invert())
}
fn is_invertible(&self) -> bool {
self.all(&|&x| x.is_invertible())
}
}
};
($size:expr, $($others:expr),+) => {
array_field! {$size}
array_field! {$($others),+}
};
}
array_field! {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
}
#[cfg(test)]
mod tests;