use batch_impl::batch_trait;
use crate::op::{Additive, Multiplicative};
use crate::tower::{Band, BoundedLattice, EuclideanDomain, LieAlgebra, Monoid, Power};
batch_trait! {
Band: @trait<Multiplicative> [bool, (<Band<>>,).1..=16];
Power: @trait[<Additive>,<Multiplicative>] [@num,bool],
@trait<Additive> (<@trait<>>,).1..=12,
@trait<Multiplicative> (<@trait<>>,).1..=12;
BoundedLattice: [@u*,@i*]{
fn top() -> Self { Self::MAX } fn bottom() -> Self { Self::MIN }
},
bool{
fn top() -> Self { true } fn bottom() -> Self { false }
},
(<@trait>,).1..=12 impl{(A@..,)}{
fn top() -> Self { ( @(@A::top(),).. ) }
fn bottom() -> Self { ( @(@A::bottom(),).. ) }
};
LieAlgebra: @trait<Additive> [@num,bool]{
fn bracket(&self, _other: &Self) -> Self {<Self as Monoid>::identity() }
};
EuclideanDomain: @trait<Additive, Multiplicative>[
[@u8..u64, usize]{
fn quot_rem(&self, divisor: &Self) -> (Self, Self) { (self.div_euclid(*divisor), self.rem_euclid(*divisor)) }
fn euclidean_norm(&self) -> u128 { *self as u128 }
},
u128{
fn quot_rem(&self, divisor: &Self) -> (Self, Self) { (self.div_euclid(*divisor), self.rem_euclid(*divisor)) }
fn euclidean_norm(&self) -> u128 { *self }
},
[@i8..i64, isize]{
fn quot_rem(&self, divisor: &Self) -> (Self, Self) { (self.div_euclid(*divisor), self.rem_euclid(*divisor)) }
fn euclidean_norm(&self) -> u128 { self.unsigned_abs() as u128 }
},
i128{
fn quot_rem(&self, divisor: &Self) -> (Self, Self) { (self.div_euclid(*divisor), self.rem_euclid(*divisor)) }
fn euclidean_norm(&self) -> u128 { self.unsigned_abs() }
}];
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tower::{BoundedLattice, EuclideanDomain, Power};
#[test]
fn powers_via_square_and_multiply() {
assert_eq!(<u8 as Power<Multiplicative>>::pow(&3, 4), 81);
assert_eq!(<u8 as Power<Multiplicative>>::pow(&3, 0), 1);
assert_eq!(<u8 as Power<Additive>>::pow(&3, 4), 12);
assert_eq!(<(u8, u8) as Power<Multiplicative>>::pow(&(2, 3), 3), (8, 27));
let v = (2u16, 2u16, 2u16, 2u16, 2u16, 2u16, 2u16, 2u16, 2u16, 2u16, 2u16, 2u16);
let p = <(u16, u16, u16, u16, u16, u16, u16, u16, u16, u16, u16, u16) as Power<
Multiplicative,
>>::pow(&v, 10);
assert_eq!(p.0, 1024);
assert_eq!(p.11, 1024);
}
#[test]
fn band_tuples_to_16() {
fn assert_band<T: Band<Multiplicative>>() {}
assert_band::<(
bool,
bool,
bool,
bool,
bool,
bool,
bool,
bool,
bool,
bool,
bool,
bool,
bool,
bool,
bool,
bool,
)>();
}
#[test]
fn euclidean_gcd() {
assert_eq!(<u32 as EuclideanDomain<Additive, Multiplicative>>::gcd(&12, &18), 6);
assert_eq!(<u32 as EuclideanDomain<Additive, Multiplicative>>::gcd(&17, &5), 1);
assert_eq!(<i64 as EuclideanDomain<Additive, Multiplicative>>::gcd(&-12, &18), 6);
let (q, r) = <i32 as EuclideanDomain<Additive, Multiplicative>>::quot_rem(&17, &5);
assert_eq!((q, r), (3, 2));
}
#[test]
fn bounded_lattices() {
assert_eq!(<u8 as BoundedLattice>::top(), u8::MAX);
assert_eq!(<u8 as BoundedLattice>::bottom(), 0);
assert!(<bool as BoundedLattice>::top());
assert!(!<bool as BoundedLattice>::bottom());
assert_eq!(<(u8, u8) as BoundedLattice>::top(), (u8::MAX, u8::MAX));
let v = <(u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8) as BoundedLattice>::top();
assert_eq!(v.0, u8::MAX);
assert_eq!(v.11, u8::MAX);
}
}