alga2 0.1.0

A modern abstract-algebra hierarchy for Rust — the successor to alga, powered by batch-impl
Documentation
//! The primitive numeric matrix (v0.1 core) — generated by batch-impl.
//!
//! 15 types (`@num` + `bool` as the field F₂) × every additive/multiplicative
//! level. `batch_impl_only` covers the directive-carrying traits (magma
//! through module); the marker levels and simple methods ride `batch_trait!`
//! — the matrix supplies the quantity, every method body written exactly
//! once.
//!
//! Integer operations are wrapping (mod 2.N): under `Additive`, `u8` is the
//! group Z/256Z, which plain `+` would break with an overflow panic in debug
//! builds. Floats use plain arithmetic (an approximate field); `bool` is the
//! exact two-element field (xor as `+`, and as `*`).
//!
//! Impl counts: additive ladder 5 × 15 = 75, multiplicative ladder 3 × 15 =
//! 45, semiring ladder 3 × 15 + Field 3 = 48, module level 15 + 3 vector
//! spaces → 186 impls.

use batch_impl::batch_trait;

use crate::op::{Additive, Multiplicative};
use crate::tower::{
    AbelianGroup, CommutativeRing, DivisionRing, Field, FiniteField, FreeModule, Group, Loop,
    Magma, Module, Monoid, Quasigroup, Ring, Semigroup, Semiring, VectorSpace,
};

// ---- one batch_trait! block: every numeric level, additive and
// ---- multiplicative sides merged; the `@int` constant reuses the integer
// ---- matrix across both operators — zero duplication ----

batch_trait! {
    @int=[@u*,@i*];
    @pri=[@num, bool];
    @tr_mul=@trait<Multiplicative>;
    @tr_am=@trait<Additive,Multiplicative>;
    Magma:@int{
            fn combine(&self, rhs: &Self) -> Self { self.wrapping_add(*rhs) }
        }, @f*{
            fn combine(&self, rhs: &Self) -> Self { *self + *rhs }
        }, bool{
            fn combine(&self, rhs: &Self) -> Self { *self != *rhs }
        },
        @tr_mul [@int{
            fn combine(&self, rhs: &Self) -> Self { self.wrapping_mul(*rhs) }
        }, @f*{
            fn combine(&self, rhs: &Self) -> Self { *self * *rhs }
        }, bool{
            fn combine(&self, rhs: &Self) -> Self { *self && *rhs }
        }];
    Monoid:@int{
            fn identity() -> Self { 0 }
        }, @f*{
            fn identity() -> Self { 0. }
        }, bool{
            fn identity() -> Self { false }
        },
        @tr_mul [
        @int{
            fn identity() -> Self { 1 }
        }, @f*{
            fn identity() -> Self { 1. }
        }, bool{
            fn identity() -> Self { true }
        }];
    Group: @int{
        fn inverse(&self) -> Self { self.wrapping_neg() }
    }, @f*{
        fn inverse(&self) -> Self { -*self }
    }, bool{
        fn inverse(&self) -> Self { *self }
    };
    DivisionRing: @f*{
        fn inv(&self) -> Self { 1.0 / *self }
    }, bool{
        fn inv(&self) -> Self { *self }
    };
    Semigroup: @trait[<Additive>,<Multiplicative>] @pri;
    Quasigroup: @pri;
    Loop: @pri;
    AbelianGroup: @pri;
    Semiring: @pri;
    Ring: @pri;
    CommutativeRing: @pri;
    Field: [@f*, bool];
    FiniteField: bool{
        fn characteristic() -> u64 { 2 }
        fn order() -> u64 { 2 }
    };
    VectorSpace: @tr_am [@f*,bool] where Self::Scalar: Field;
    FreeModule: @tr_am @pri{
        fn rank() -> usize { 1 }
        fn basis_element(_i: usize) -> Self { <Self as Monoid<Multiplicative>>::identity() }
        fn coordinate(&self, _i: usize) -> Self::Scalar { *self }
    };
    Module: @trait<Additive, Multiplicative,Scalar=Self> [
        @int{
            fn scale(s: &Self::Scalar, v: Self) -> Self { s.wrapping_mul(v) }
        }, @f*{
            fn scale(s: &Self::Scalar, v: Self) -> Self { s * v }
        }, bool{
            fn scale(s: &Self::Scalar, v: Self) -> Self { *s && v }
        }
    ];
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::tower::{AbelianGroup, DivisionRing, Field, Group, Magma, Monoid, Ring};

    fn add<T: Magma<Additive>>(a: T, b: T) -> T {
        <T as Magma<Additive>>::combine(&a, &b)
    }

    fn mul<T: Magma<Multiplicative>>(a: T, b: T) -> T {
        <T as Magma<Multiplicative>>::combine(&a, &b)
    }

    /// Every law of the additive ladder, checked for one concrete type.
    fn assert_additive_abelian<T>(a: T, b: T)
    where
        T: AbelianGroup<Additive> + Copy + PartialEq + core::fmt::Debug,
    {
        // associativity
        assert_eq!(add(add(a, b), a), add(a, add(b, a)));
        // identity
        let id = <T as Monoid<Additive>>::identity();
        assert_eq!(add(a, id), a);
        assert_eq!(add(id, a), a);
        // inverse
        let inv = <T as Group<Additive>>::inverse(&a);
        assert_eq!(add(a, inv), id);
        // commutativity
        assert_eq!(add(a, b), add(b, a));
    }

    /// Monoid laws of the multiplicative ladder (integers have no
    /// multiplicative inverses, so the ladder stops at Monoid there).
    fn assert_multiplicative_monoid<T>(a: T, b: T, c: T)
    where
        T: Monoid<Multiplicative> + Copy + PartialEq + core::fmt::Debug,
    {
        // associativity
        assert_eq!(mul(mul(a, b), c), mul(a, mul(b, c)));
        // identity
        let one = <T as Monoid<Multiplicative>>::identity();
        assert_eq!(mul(a, one), a);
        assert_eq!(mul(one, a), a);
    }

    /// Distributivity + multiplicative identity, the ring laws.
    fn assert_ring<T>(a: T, b: T, c: T)
    where
        T: Ring<Additive, Multiplicative> + Copy + PartialEq + core::fmt::Debug,
    {
        let one = <T as Monoid<Multiplicative>>::identity();
        assert_eq!(mul(a, one), a);
        assert_eq!(mul(one, a), a);
        // distributivity: a·(b+c) == a·b + a·c
        assert_eq!(mul(a, add(b, c)), add(mul(a, b), mul(a, c)));
    }

    /// Multiplicative inverse: a·a⁻¹ == 1 (and the reverse order).
    fn assert_field<T>(a: T)
    where
        T: Field<Additive, Multiplicative> + Copy + PartialEq + core::fmt::Debug,
    {
        let one = <T as Monoid<Multiplicative>>::identity();
        let inv = <T as DivisionRing<Additive, Multiplicative>>::inv(&a);
        assert_eq!(mul(a, inv), one);
        assert_eq!(mul(inv, a), one);
    }

    #[test]
    fn additive_ladder_holds_for_all_numerics() {
        assert_additive_abelian(3u8, 5u8);
        assert_additive_abelian(3u16, 5u16);
        assert_additive_abelian(3u32, 5u32);
        assert_additive_abelian(3u64, 5u64);
        assert_additive_abelian(3u128, 5u128);
        assert_additive_abelian(3usize, 5usize);
        assert_additive_abelian(3i8, 5i8);
        assert_additive_abelian(3i16, 5i16);
        assert_additive_abelian(3i32, 5i32);
        assert_additive_abelian(3i64, 5i64);
        assert_additive_abelian(3i128, 5i128);
        assert_additive_abelian(3isize, 5isize);
        assert_additive_abelian(3.5f32, 1.25f32);
        assert_additive_abelian(3.5f64, 1.25f64);
    }

    #[test]
    fn multiplicative_monoid_holds_for_all_numerics() {
        assert_multiplicative_monoid(3u8, 5u8, 7u8);
        assert_multiplicative_monoid(3u16, 5u16, 7u16);
        assert_multiplicative_monoid(3u32, 5u32, 7u32);
        assert_multiplicative_monoid(3u64, 5u64, 7u64);
        assert_multiplicative_monoid(3u128, 5u128, 7u128);
        assert_multiplicative_monoid(3usize, 5usize, 7usize);
        assert_multiplicative_monoid(3i8, 5i8, 7i8);
        assert_multiplicative_monoid(3i16, 5i16, 7i16);
        assert_multiplicative_monoid(3i32, 5i32, 7i32);
        assert_multiplicative_monoid(3i64, 5i64, 7i64);
        assert_multiplicative_monoid(3i128, 5i128, 7i128);
        assert_multiplicative_monoid(3isize, 5isize, 7isize);
        assert_multiplicative_monoid(3.0f32, 5.0f32, 7.0f32);
        assert_multiplicative_monoid(3.0f64, 5.0f64, 7.0f64);
    }

    #[test]
    fn ring_laws_hold_for_all_numerics() {
        assert_ring(2u8, 3u8, 4u8);
        assert_ring(2u16, 3u16, 4u16);
        assert_ring(2u32, 3u32, 4u32);
        assert_ring(2u64, 3u64, 4u64);
        assert_ring(2u128, 3u128, 4u128);
        assert_ring(2usize, 3usize, 4usize);
        assert_ring(2i8, 3i8, 4i8);
        assert_ring(2i16, 3i16, 4i16);
        assert_ring(2i32, 3i32, 4i32);
        assert_ring(2i64, 3i64, 4i64);
        assert_ring(2i128, 3i128, 4i128);
        assert_ring(2isize, 3isize, 4isize);
        assert_ring(2.0f32, 3.0f32, 4.0f32);
        assert_ring(2.0f64, 3.0f64, 4.0f64);
    }

    #[test]
    fn field_laws_hold_for_floats() {
        assert_field(2.0f32);
        assert_field(0.25f32);
        assert_field(-3.0f32);
        assert_field(2.0f64);
        assert_field(0.25f64);
        assert_field(-3.0f64);
    }

    #[test]
    fn bool_is_the_two_element_field() {
        // F₂: xor as +, and as *.
        assert_additive_abelian(true, false);
        assert_additive_abelian(false, false);
        assert_multiplicative_monoid(true, false, true);
        assert!(!add(true, true));
        assert!(mul(true, true));
        assert!(!<bool as Monoid<Additive>>::identity());
        assert!(<bool as Monoid<Multiplicative>>::identity());
        // Every nonzero element (true) has an inverse: itself.
        assert!(<bool as DivisionRing<Additive, Multiplicative>>::inv(&true));
    }

    #[test]
    fn bool_is_finite_field_f2() {
        use crate::tower::FiniteField;
        assert_eq!(<bool as FiniteField<Additive, Multiplicative>>::characteristic(), 2);
        assert_eq!(<bool as FiniteField<Additive, Multiplicative>>::order(), 2);
    }
}