use ops::{Op, Inverse, Additive};
use structure::MagmaApprox;
use structure::Magma;
pub trait QuasigroupApprox<O: Op>
: MagmaApprox<O>
+ Inverse<O>
{
fn prop_inv_is_latin_square_approx(args: (Self, Self)) -> bool {
let (a, b) = (|| args.0.clone(), || args.1.clone());
a().approx_eq(&(a().approx(b().inv()).approx(b()))) &&
a().approx_eq(&(a().approx(b().approx(b().inv()))))
}
}
impl_marker!(QuasigroupApprox<Additive>; i8, i16, i32, i64);
pub trait Quasigroup<O: Op>
: QuasigroupApprox<O>
+ Magma<O>
{
fn prop_inv_is_latin_square(args: (Self, Self)) -> bool {
let (a, b) = (|| args.0.clone(), || args.1.clone());
a() == a().operate(b().inv()).operate(b()) &&
a() == a().operate(b()).operate(b().inv())
}
}
impl_marker!(Quasigroup<Additive>; i8, i16, i32, i64);
#[cfg(test)]
mod tests {
macro_rules! check_int {
($($T:ident),* $(,)*) => {
$(mod $T {
use ops::Additive;
use structure::QuasigroupApprox;
use structure::Quasigroup;
#[quickcheck]
fn prop_inv_is_latin_square_approx(args: ($T, $T)) -> bool {
QuasigroupApprox::<Additive>::prop_inv_is_latin_square_approx(args)
}
#[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);
}