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())
}
}
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()
}
}
pub trait AbstractField<A: Operator = Additive, M: Operator = Multiplicative>
: AbstractRingCommutative<A, M>
+ AbstractGroupAbelian<M>
{ }
impl_marker!(AbstractRing<Additive, Multiplicative>; i8, i16, i32, i64, f32, f64);
impl_marker!(AbstractRingCommutative<Additive, Multiplicative>; i8, i16, i32, i64, f32, f64);
impl_marker!(AbstractField<Additive, Multiplicative>; f32, f64);