use general::{Magma, Op, Inverse, Additive, Multiplicative};
use cmp::ApproxEq;
pub trait Quasigroup<O: Op>
: Magma<O> + Inverse<O>
{
fn prop_inv_is_latin_square(args: (Self, Self)) -> bool
where Self: ApproxEq {
let (a, b) = (|| args.0.clone(), || args.1.clone());
a().approx_eq(&(a().operate(b().inv()).operate(b()))) &&
a().approx_eq(&(a().operate(b().operate(b().inv()))))
}
}
impl_marker!(Quasigroup<Additive>; i8, i16, i32, i64, f32, f64);
impl_marker!(Quasigroup<Multiplicative>; f32, f64);
#[cfg(test)]
mod tests {
macro_rules! check_int {
($($T:ident),* $(,)*) => {
$(mod $T {
use ops::Additive;
use general::Quasigroup;
#[quickcheck]
fn prop_inv_is_latin_square(args: ($T, $T)) -> bool {
Quasigroup::<Additive>::prop_inv_is_latin_square(args)
}
})+
}
}
check_int!(i8, i16, i32, i64);
}