use approx::ApproxEq;
use general::{Operator, Additive, Multiplicative, AbstractGroupAbelian, AbstractMonoid};
use general::wrapper::Wrapper as W;
pub trait AbstractRing<A: Operator = Additive, M: Operator = Multiplicative>:
AbstractGroupAbelian<A> + AbstractMonoid<M> {
fn prop_mul_and_add_are_distributive_approx(args: (Self, Self, Self)) -> bool
where Self: ApproxEq {
let (a, b, c) = args;
let a = || { W::<_, A, M>::new(a.clone()) };
let b = || { W::<_, A, M>::new(b.clone()) };
let c = || { W::<_, A, M>::new(c.clone()) };
relative_eq!(a() * (b() + c()), a() * b() + a() * c()) &&
relative_eq!((b() + c()) * a(), b() * a() + c() * a())
}
fn prop_mul_and_add_are_distributive(args: (Self, Self, Self)) -> bool
where Self: Eq {
let (a, b, c) = args;
let a = || { W::<_, A, M>::new(a.clone()) };
let b = || { W::<_, A, M>::new(b.clone()) };
let c = || { W::<_, A, M>::new(c.clone()) };
(a() * b()) + c() == (a() * b()) + (a() * c()) &&
(b() + c()) * a() == (b() * a()) + (c() * a())
}
}
#[macro_export]
macro_rules! impl_ring(
(<$A:ty, $M:ty> for $($T:ty);* $(;)*) => {
impl_abelian!(<$A> for $($T);*);
impl_monoid!(<$M> for $($T);*);
impl_marker!(AbstractRing<$A, $M>; $($T);*);
}
);
pub trait AbstractRingCommutative<A: Operator = Additive, M: Operator = Multiplicative> : AbstractRing<A, M> {
fn prop_mul_is_commutative_approx(args: (Self, Self)) -> bool
where Self: ApproxEq {
let (a, b) = args;
let a = || { W::<_, A, M>::new(a.clone()) };
let b = || { W::<_, A, M>::new(b.clone()) };
relative_eq!(a() * b(), b() * a())
}
fn prop_mul_is_commutative(args: (Self, Self)) -> bool
where Self: Eq {
let (a, b) = args;
let a = || { W::<_, A, M>::new(a.clone()) };
let b = || { W::<_, A, M>::new(b.clone()) };
a() * b() == b() * a()
}
}
#[macro_export]
macro_rules! impl_ring_commutative(
(<$A:ty, $M:ty> for $($T:ty);* $(;)*) => {
impl_ring!(<$A, $M> for $($T);*);
impl_marker!($crate::general::AbstractRingCommutative<$A, $M>; $($T);*);
}
);
pub trait AbstractField<A: Operator = Additive, M: Operator = Multiplicative>
: AbstractRingCommutative<A, M>
+ AbstractGroupAbelian<M>
{ }
#[macro_export]
macro_rules! impl_field(
(<$A:ty, $M:ty> for $($T:ty);* $(;)*) => {
impl_ring_commutative!(<$A, $M> for $($T);*);
impl_marker!($crate::general::AbstractQuasigroup<$M>; $($T);*);
impl_marker!($crate::general::AbstractLoop<$M>; $($T);*);
impl_marker!($crate::general::AbstractGroup<$M>; $($T);*);
impl_marker!($crate::general::AbstractGroupAbelian<$M>; $($T);*);
impl_marker!($crate::general::AbstractField<$A, $M>; $($T);*);
}
);
impl_ring_commutative!(<Additive, Multiplicative> for i8; i16; i32; i64);
impl_field!(<Additive, Multiplicative> for f32; f64);