From 78eacdb23ccab2c5d3f7e1bfdb47028de26a5883 Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Fri, 12 Jul 2024 18:48:40 -0400 Subject: [PATCH 01/21] chore: update doc and fix CI --- .github/workflows/CI.yml | 4 +- src/lib.rs | 286 +++++++++++++++++++++++++++------------ 2 files changed, 200 insertions(+), 90 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index c12059b..d7228dd 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -3,13 +3,13 @@ name: CI on: push: branches: - - main + - master tags: - 'v*.*.*' pull_request: types: [ opened, synchronize, reopened ] branches: - - main + - master env: CARGO_TERM_COLOR: always diff --git a/src/lib.rs b/src/lib.rs index 1e7f48e..e6c6f70 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,98 +1,126 @@ -//! # Algebraic Structures +//! # Noether //! -//! This module provides implementations of various algebraic structures, -//! from basic ones like magmas to more complex ones like fields. +//! Noether provides traits and blanket implementations for algebraic structures, +//! from basic ones like magmas to more complex ones like fields. It leans heavily on +//! the basic traits available in std::ops and num_traits. +//! +//! The goal is to provide a common interface for working with algebraic structures +//! in Rust. +//! +//! Interestingly, these traits can be used to categorize implementations of various +//! structs based on the properties they satisfy, and be applied in most cases for +//! anything from scalar values to n-dimensional arrays. //! //! ## Binary Operations and Their Properties //! //! An algebraic structure consists of a set with one or more binary operations. -//! Let Self be a set and β€’ be a binary operation on Self. -//! Here are the key properties a binary operation may possess: +//! Let 𝑆 be a set (Self) and β€’ be a binary operation on 𝑆. +//! Here are the key properties a binary operation may possess, organized from simplest to most complex: +//! +//! - (Closure) βˆ€ a, b ∈ 𝑆, a β€’ b ∈ 𝑆 +//! - (Totality) βˆ€ a, b ∈ 𝑆, a β€’ b is defined +//! - (Commutativity) βˆ€ a, b ∈ 𝑆, a β€’ b = b β€’ a +//! - (Associativity) βˆ€ a, b, c ∈ 𝑆, (a β€’ b) β€’ c = a β€’ (b β€’ c) +//! - (Idempotence) βˆ€ a ∈ 𝑆, a β€’ a = a +//! - (Identity) βˆƒ e ∈ 𝑆, βˆ€ a ∈ 𝑆, e β€’ a = a β€’ e = a +//! - (Inverses) βˆ€ a ∈ 𝑆, βˆƒ b ∈ 𝑆, a β€’ b = b β€’ a = e (where e is the identity) +//! - (Cancellation) βˆ€ a, b, c ∈ 𝑆, a β€’ b = a β€’ c β‡’ b = c (a β‰  0 if βˆƒ zero element) +//! - (Divisibility) βˆ€ a, b ∈ 𝑆, βˆƒ x ∈ 𝑆, a β€’ x = b +//! - (Regularity) βˆ€ a ∈ 𝑆, βˆƒ x ∈ 𝑆, a β€’ x β€’ a = a +//! - (Alternativity) βˆ€ a, b ∈ 𝑆, (a β€’ a) β€’ b = a β€’ (a β€’ b) ∧ (b β€’ a) β€’ a = b β€’ (a β€’ a) +//! - (Distributivity) βˆ€ a, b, c ∈ 𝑆, a * (b + c) = (a * b) + (a * c) +//! - (Absorption) βˆ€ a, b ∈ 𝑆, a * (a + b) = a ∧ a + (a * b) = a +//! - (Monotonicity) βˆ€ a, b, c ∈ 𝑆, a ≀ b β‡’ a β€’ c ≀ b β€’ c ∧ c β€’ a ≀ c β€’ b +//! - (Modularity) βˆ€ a, b, c ∈ 𝑆, a ≀ c β‡’ a ∨ (b ∧ c) = (a ∨ b) ∧ c +//! - (Switchability) βˆ€ x, y, z ∈ S, (x + y) * z = x + (y * z) +//! - (Min/Max Ops) βˆ€ a, b ∈ S, a ∨ b = min{a,b}, a ∧ b = max{a,b} +//! - (Defect Op) βˆ€ a, b ∈ S, a *₃ b = a + b - 3 +//! - (Continuity) βˆ€ V βŠ† 𝑆 open, f⁻¹(V) is open (for f: 𝑆 β†’ 𝑆, 𝑆 topological) +//! - (Solvability) βˆƒ series {Gα΅’} | G = Gβ‚€ β–· G₁ β–· ... β–· Gβ‚™ = {e}, [Gα΅’, Gα΅’] ≀ Gα΅’β‚Šβ‚ +//! - (Alg. Closure) βˆ€ p(x) ∈ 𝑆[x] non-constant, βˆƒ a ∈ 𝑆 | p(a) = 0 //! -//! - (Closure) βˆ€ a, b ∈ Self, a β€’ b ∈ Self -//! - (Associativity) βˆ€ a, b, c ∈ Self, (a β€’ b) β€’ c = a β€’ (b β€’ c) -//! - (Commutativity) βˆ€ a, b ∈ Self, a β€’ b = b β€’ a -//! - (Identity) βˆƒ e ∈ Self, βˆ€ a ∈ Self, e β€’ a = a β€’ e = a -//! - (Inverses) βˆ€ a ∈ Self, βˆƒ b ∈ Self, a β€’ b = b β€’ a = e (where e is the identity) -//! - (Idempotence) βˆ€ a ∈ Self, a β€’ a = a +//! In general, checking the properties of the binary operators at compile time +//! which are implemented is a challenge. //! //! ## Hierarchy of Scalar Algebraic Structures //! //! ```text -//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” -//! β”‚ Magma β”‚ -//! β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ -//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -//! Latin Square Property Associativity -//! (Unique Solutions) β”‚ -//! β”‚ β”‚ -//! β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β” -//! β”‚Quasigroupβ”‚ β”‚Semigroupβ”‚ -//! β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ -//! β”‚ β”‚ -//! Identity Element Identity Element -//! β”‚ β”‚ -//! β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β” -//! β”‚ Loop β”‚ β”‚ Monoid β”‚ -//! β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ -//! β”‚ β”‚ -//! Associativity Inverses -//! β”‚ β”‚ -//! └───────────┐ β”Œβ”€β”€β”€β”€β”€β”˜ -//! β”‚ β”‚ -//! β”Œβ”€β”€β”€β–Όβ”€β–Όβ”€β”€β”€β” -//! β”‚ Group β”‚ -//! β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ -//! β”‚ -//! Commutativity -//! β”‚ -//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” -//! β”‚ Group (Abelian) β”‚ -//! β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -//! β”‚ -//! Add Second Operation -//! β”‚ -//! β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β” -//! β”‚Semiring β”‚ -//! β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ -//! β”‚ -//! Additive Inverses -//! β”‚ -//! β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β” -//! β”‚ Ring β”‚ -//! β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ -//! β”‚ -//! Multiplicative Commutativity -//! β”‚ -//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” -//! β”‚ Ring β”‚ -//! β”‚ (Commutative) β”‚ -//! β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -//! β”‚ -//! No Zero Divisors -//! β”‚ -//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” -//! β”‚ Integral Domain β”‚ -//! β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -//! β”‚ -//! Euclidean Function -//! β”‚ -//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” -//! β”‚ Euclidean Domain β”‚ -//! β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -//! β”‚ -//! Multiplicative Inverses for Non-Zero -//! Distributive Link -//! β”‚ -//! β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β” -//! β”‚ Field β”‚ -//! β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ -//! β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β” -//! β”‚ β”‚ -//! β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β” -//! β”‚ Finite β”‚ β”‚ Real β”‚ -//! β”‚ Field β”‚ β”‚ Field β”‚ -//! β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +//! β”Œβ”€β”€β”€β”€β”€β” +//! β”‚ Set β”‚ +//! β””β”€β”€β”¬β”€β”€β”˜ +//! β”‚ +//! β”Œβ”€β”€β–Όβ”€β”€β” +//! β”‚Magmaβ”‚ +//! β””β”€β”€β”¬β”€β”€β”˜ +//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +//! β”‚ β”‚ β”‚ +//! β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” +//! β”‚Quasigroup β”‚ β”‚ Semigroup β”‚ β”‚Semilatticeβ”‚ +//! β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +//! β”‚ β”‚ +//! β”Œβ”€β”€β”€β–Όβ”€β”€β”€β” β”Œβ”€β”€β”€β–Όβ”€β”€β”€β” +//! β”‚ Loop β”‚ β”‚Monoid β”‚ +//! β””β”€β”€β”€β”¬β”€β”€β”€β”˜ β””β”€β”€β”€β”¬β”€β”€β”€β”˜ +//! β”‚ β”‚ +//! └────────┐ β”Œβ”€β”€β”€β”€β”€β”˜ +//! β”‚ β”‚ +//! β”Œβ”€β”€β–Όβ”€β–Όβ”€β”€β” +//! β”‚ Group β”‚ +//! β””β”€β”€β”€β”¬β”€β”€β”€β”˜ +//! β”‚ +//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β” +//! β”‚ Abelian Group β”‚ +//! β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +//! β”‚ +//! β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β” +//! β”‚Semiring β”‚ +//! β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ +//! β”‚ +//! β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β” +//! β”‚ Ring β”‚ +//! β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ +//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +//! β”‚ β”‚ +//! β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” +//! β”‚ Module β”‚ β”‚Commutativeβ”‚ +//! β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ Ring β”‚ +//! β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ +//! β”‚ +//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β” +//! β”‚ Integral Domain β”‚ +//! β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +//! β”‚ +//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +//! β”‚Unique Factorization Domainβ”‚ +//! β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +//! β”‚ +//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +//! β”‚Principal Ideal Domain β”‚ +//! β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +//! β”‚ +//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β” +//! β”‚Euclidean Domain β”‚ +//! β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +//! β”‚ +//! β”Œβ”€β”€β”€β–Όβ”€β”€β”€β” +//! β”‚ Field │────────────────────────┐ +//! β””β”€β”€β”€β”¬β”€β”€β”€β”˜ β”‚ +//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ +//! β”‚ β”‚ β”‚ +//! β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” +//! β”‚ Finite β”‚ β”‚ Infinite β”‚ β”‚ Vector β”‚ +//! β”‚ Field β”‚ β”‚ Field β”‚ β”‚ Space β”‚ +//! β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +//! β”‚ +//! β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” +//! β”‚ Field β”‚ +//! β”‚ Extension β”‚ +//! β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ +//! β”‚ +//! β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” +//! β”‚ Extension β”‚ +//! β”‚ Tower β”‚ +//! β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ //! ``` use num_traits::Euclid; @@ -156,7 +184,7 @@ impl ClosedInv for T where T: Inv {} /// /// This trait is meant for sets representing numerics like the natural numbers, integers, real numbers, etc. /// Represents a mathematical set rather than a broader collection type. -pub trait Set: Sized + Copy + PartialEq { +pub trait Set: Sized + Clone + PartialEq { /// Checks if the given element is a member of the set. fn contains(&self, element: &Self) -> bool; } @@ -192,8 +220,6 @@ pub trait Idempotent {} /// - Closure: βˆ€ a, b ∈ Self, a + b ∈ Self pub trait AdditiveMagma: Set + ClosedAdd + ClosedAddAssign {} -impl AdditiveMagma for T where T: Set + ClosedAdd + ClosedAddAssign {} - /// Represents an additive quasigroup. /// /// A quasigroup is a magma where division is always possible and unique. @@ -397,3 +423,87 @@ pub trait FiniteField: Field { pub trait RealField: Field + PartialOrd {} impl RealField for T where T: Field + PartialOrd {} + +#[cfg(test)] +mod tests { + use super::*; + use std::borrow::Cow; + + #[derive(Debug, Clone, PartialEq)] + struct StringMagma<'a>(Cow<'a, str>); + + impl<'a> Set for StringMagma<'a> { + fn contains(&self, _: &Self) -> bool { + true // All strings are valid in our magma + } + } + + impl<'a> Add for StringMagma<'a> { + type Output = Self; + + fn add(self, other: Self) -> Self { + StringMagma(Cow::Owned(self.0.to_string() + &other.0)) + } + } + + impl<'a> AddAssign for StringMagma<'a> { + fn add_assign(&mut self, other: Self) { + self.0 = Cow::Owned(self.0.to_string() + &other.0); + } + } + + impl<'a> AdditiveMagma for StringMagma<'a> {} + + #[test] + fn test_magma_closure() { + let a = StringMagma(Cow::Borrowed("Hello")); + let b = StringMagma(Cow::Borrowed(" World")); + let _ = a + b; // This should compile and run without issues + } + + #[test] + fn test_magma_operation() { + let a = StringMagma(Cow::Borrowed("Hello")); + let b = StringMagma(Cow::Borrowed(" World")); + assert_eq!(a + b, StringMagma(Cow::Borrowed("Hello World"))); + } + + #[test] + fn test_magma_associativity_not_required() { + let a = StringMagma(Cow::Borrowed("A")); + let b = StringMagma(Cow::Borrowed("B")); + let c = StringMagma(Cow::Borrowed("C")); + + // String concatenation is associative, but magmas don't require this property + assert_eq!( + (a.clone() + b.clone()) + c.clone(), + a.clone() + (b.clone() + c.clone()) + ); + } + + #[test] + fn test_magma_commutativity_not_required() { + let a = StringMagma(Cow::Borrowed("Hello")); + let b = StringMagma(Cow::Borrowed(" World")); + + assert_ne!(a.clone() + b.clone(), b + a); + } + + #[test] + fn test_magma_add_assign() { + let mut a = StringMagma(Cow::Borrowed("Hello")); + let b = StringMagma(Cow::Borrowed(" World")); + a += b; + assert_eq!(a, StringMagma(Cow::Borrowed("Hello World"))); + } + + #[test] + fn test_magma_with_empty_string() { + let a = StringMagma(Cow::Borrowed("Hello")); + let e = StringMagma(Cow::Borrowed("")); + + // Empty string acts like an identity, but magmas don't require an identity + assert_eq!(a.clone() + e.clone(), a.clone()); + assert_eq!(e + a.clone(), a); + } +} From 281751d512d4361fa35d57045465c9c178668c8a Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Fri, 12 Jul 2024 19:45:02 -0400 Subject: [PATCH 02/21] feat: closure and markers --- src/lib.rs | 2 + src/operator.rs | 311 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 313 insertions(+) create mode 100644 src/operator.rs diff --git a/src/lib.rs b/src/lib.rs index e6c6f70..d1fefc5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -123,6 +123,8 @@ //! β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ //! ``` +mod operator; + use num_traits::Euclid; pub use num_traits::{Inv, One, Zero}; pub use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; diff --git a/src/operator.rs b/src/operator.rs new file mode 100644 index 0000000..eb2c913 --- /dev/null +++ b/src/operator.rs @@ -0,0 +1,311 @@ +//! # Operator Traits for Algebraic Structures +//! +//! This module defines traits for various operators and their properties, +//! providing a foundation for implementing algebraic structures in Rust. +//! +//! ## Binary Operations and Their Properties +//! +//! An algebraic structure consists of a set with one or more binary operations. +//! Let 𝑆 be a set (Self) and β€’ be a binary operation on 𝑆. +//! Here are the key properties a binary operation may possess, organized from simplest to most complex: +//! +//! - (Closure) βˆ€ a, b ∈ 𝑆, a β€’ b ∈ 𝑆 +//! - (Totality) βˆ€ a, b ∈ 𝑆, a β€’ b is defined +//! - (Commutativity) βˆ€ a, b ∈ 𝑆, a β€’ b = b β€’ a +//! - (Associativity) βˆ€ a, b, c ∈ 𝑆, (a β€’ b) β€’ c = a β€’ (b β€’ c) +//! - (Idempotence) βˆ€ a ∈ 𝑆, a β€’ a = a +//! - (Identity) βˆƒ e ∈ 𝑆, βˆ€ a ∈ 𝑆, e β€’ a = a β€’ e = a +//! - (Inverses) βˆ€ a ∈ 𝑆, βˆƒ b ∈ 𝑆, a β€’ b = b β€’ a = e (where e is the identity) +//! - (Cancellation) βˆ€ a, b, c ∈ 𝑆, a β€’ b = a β€’ c β‡’ b = c (a β‰  0 if βˆƒ zero element) +//! - (Divisibility) βˆ€ a, b ∈ 𝑆, βˆƒ x ∈ 𝑆, a β€’ x = b +//! - (Regularity) βˆ€ a ∈ 𝑆, βˆƒ x ∈ 𝑆, a β€’ x β€’ a = a +//! - (Alternativity) βˆ€ a, b ∈ 𝑆, (a β€’ a) β€’ b = a β€’ (a β€’ b) ∧ (b β€’ a) β€’ a = b β€’ (a β€’ a) +//! - (Distributivity) βˆ€ a, b, c ∈ 𝑆, a * (b + c) = (a * b) + (a * c) +//! - (Absorption) βˆ€ a, b ∈ 𝑆, a * (a + b) = a ∧ a + (a * b) = a +//! - (Monotonicity) βˆ€ a, b, c ∈ 𝑆, a ≀ b β‡’ a β€’ c ≀ b β€’ c ∧ c β€’ a ≀ c β€’ b +//! - (Modularity) βˆ€ a, b, c ∈ 𝑆, a ≀ c β‡’ a ∨ (b ∧ c) = (a ∨ b) ∧ c +//! - (Switchability) βˆ€ x, y, z ∈ S, (x + y) * z = x + (y * z) +//! - (Min/Max Ops) βˆ€ a, b ∈ S, a ∨ b = min{a,b}, a ∧ b = max{a,b} +//! - (Defect Op) βˆ€ a, b ∈ S, a *₃ b = a + b - 3 +//! - (Continuity) βˆ€ V βŠ† 𝑆 open, f⁻¹(V) is open (for f: 𝑆 β†’ 𝑆, 𝑆 topological) +//! +//! To be determined: +//! +//! - (Solvability) βˆƒ series {Gα΅’} | G = Gβ‚€ β–· G₁ β–· ... β–· Gβ‚™ = {e}, [Gα΅’, Gα΅’] ≀ Gα΅’β‚Šβ‚ +//! - (Alg. Closure) βˆ€ p(x) ∈ 𝑆[x] non-constant, βˆƒ a ∈ 𝑆 | p(a) = 0 +//! +//! The traits and blanket implementations provided above serve several important purposes: +//! +//! 1. Closure: All `Closed*` traits ensure that operations on a type always produce a result +//! of the same type. This is crucial for defining algebraic structures. +//! +//! 2. Reference Operations: The `*Ref` variants of traits allow for more efficient operations +//! when the right-hand side can be borrowed, which is common in many algorithms. +//! +//! 3. Marker Traits: Traits like `Commutative`, `Associative`, etc., allow types to declare +//! which algebraic properties they satisfy. This can be used for compile-time checks +//! and to enable more generic implementations of algorithms. +//! +//! 4. Property Checking: Some marker traits include methods to check if the property holds +//! for specific values. While not providing compile-time guarantees, these can be +//! useful for testing and runtime verification. +//! +//! 5. Generic Binary Operations: The `BinaryOp` trait provides a generic way to represent +//! any binary operation, which can be useful for implementing algorithms that work +//! with arbitrary binary operations. +//! +//! 6. Automatic Implementation: The blanket implementations ensure that any type satisfying +//! the basic requirements automatically implements the corresponding closed trait. +//! This reduces boilerplate and makes the traits easier to use. +//! +//! 7. Extensibility: New types that implement the standard traits (like `Add`, `Sub`, etc.) +//! will automatically get the closed trait implementations, making the system more +//! extensible and future-proof. +//! +//! 8. Type Safety: These traits help in catching type-related errors at compile-time, +//! ensuring that operations maintain closure within the same type. +//! +//! 9. Generic Programming: These traits enable more expressive generic programming, +//! allowing functions and structs to be generic over types that are closed under +//! certain operations or satisfy certain algebraic properties. +//! +//! Note that while these blanket implementations cover a wide range of cases, there might +//! be situations where more specific implementations are needed. In such cases, you can +//! still manually implement these traits for your types, and the manual implementations +//! will take precedence over these blanket implementations. + +use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, Rem, RemAssign, Neg}; +use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Shl, ShlAssign, Shr, ShrAssign}; +use num_traits::{Zero, One, Euclid}; + +/// Trait for closed addition operation. +pub trait ClosedAdd: Add {} + +/// Trait for closed addition operation with the right-hand side as a reference. +pub trait ClosedAddRef: for<'a> Add<&'a Rhs, Output = Self> {} + +/// Trait for closed subtraction operation. +pub trait ClosedSub: Sub {} + +/// Trait for closed subtraction operation with the right-hand side as a reference. +pub trait ClosedSubRef: for<'a> Sub<&'a Rhs, Output = Self> {} + +/// Trait for closed multiplication operation. +pub trait ClosedMul: Mul {} + +/// Trait for closed multiplication operation with the right-hand side as a reference. +pub trait ClosedMulRef: for<'a> Mul<&'a Rhs, Output = Self> {} + +/// Trait for closed division operation. +pub trait ClosedDiv: Div {} + +/// Trait for closed division operation with the right-hand side as a reference. +pub trait ClosedDivRef: for<'a> Div<&'a Rhs, Output = Self> {} + +/// Trait for closed remainder operation. +pub trait ClosedRem: Rem {} + +/// Trait for closed remainder operation with the right-hand side as a reference. +pub trait ClosedRemRef: for<'a> Rem<&'a Rhs, Output = Self> {} + +/// Trait for closed negation operation. +pub trait ClosedNeg: Neg {} + +/// Trait for closed addition assignment operation. +pub trait ClosedAddAssign: AddAssign {} + +/// Trait for closed addition assignment operation with the right-hand side as a reference. +pub trait ClosedAddAssignRef: for<'a> AddAssign<&'a Rhs> {} + +/// Trait for closed subtraction assignment operation. +pub trait ClosedSubAssign: SubAssign {} + +/// Trait for closed subtraction assignment operation with the right-hand side as a reference. +pub trait ClosedSubAssignRef: for<'a> SubAssign<&'a Rhs> {} + +/// Trait for closed multiplication assignment operation. +pub trait ClosedMulAssign: MulAssign {} + +/// Trait for closed multiplication assignment operation with the right-hand side as a reference. +pub trait ClosedMulAssignRef: for<'a> MulAssign<&'a Rhs> {} + +/// Trait for closed division assignment operation. +pub trait ClosedDivAssign: DivAssign {} + +/// Trait for closed division assignment operation with the right-hand side as a reference. +pub trait ClosedDivAssignRef: for<'a> DivAssign<&'a Rhs> {} + +/// Trait for closed remainder assignment operation. +pub trait ClosedRemAssign: RemAssign {} + +/// Trait for closed remainder assignment operation with the right-hand side as a reference. +pub trait ClosedRemAssignRef: for<'a> RemAssign<&'a Rhs> {} + +/// Trait for closed bitwise AND operation. +pub trait ClosedBitAnd: BitAnd {} + +/// Trait for closed bitwise AND operation with the right-hand side as a reference. +pub trait ClosedBitAndRef: for<'a> BitAnd<&'a Rhs, Output = Self> {} + +/// Trait for closed bitwise OR operation. +pub trait ClosedBitOr: BitOr {} + +/// Trait for closed bitwise OR operation with the right-hand side as a reference. +pub trait ClosedBitOrRef: for<'a> BitOr<&'a Rhs, Output = Self> {} + +/// Trait for closed bitwise XOR operation. +pub trait ClosedBitXor: BitXor {} + +/// Trait for closed bitwise XOR operation with the right-hand side as a reference. +pub trait ClosedBitXorRef: for<'a> BitXor<&'a Rhs, Output = Self> {} + +/// Trait for closed bitwise NOT operation. +pub trait ClosedNot: Not {} + +/// Trait for closed left shift operation. +pub trait ClosedShl: Shl {} + +/// Trait for closed left shift operation with the right-hand side as a reference. +pub trait ClosedShlRef: for<'a> Shl<&'a Rhs, Output = Self> {} + +/// Trait for closed right shift operation. +pub trait ClosedShr: Shr {} + +/// Trait for closed right shift operation with the right-hand side as a reference. +pub trait ClosedShrRef: for<'a> Shr<&'a Rhs, Output = Self> {} + +/// Trait for closed bitwise AND assignment operation. +pub trait ClosedBitAndAssign: BitAndAssign {} + +/// Trait for closed bitwise AND assignment operation with the right-hand side as a reference. +pub trait ClosedBitAndAssignRef: for<'a> BitAndAssign<&'a Rhs> {} + +/// Trait for closed bitwise OR assignment operation. +pub trait ClosedBitOrAssign: BitOrAssign {} + +/// Trait for closed bitwise OR assignment operation with the right-hand side as a reference. +pub trait ClosedBitOrAssignRef: for<'a> BitOrAssign<&'a Rhs> {} + +/// Trait for closed bitwise XOR assignment operation. +pub trait ClosedBitXorAssign: BitXorAssign {} + +/// Trait for closed bitwise XOR assignment operation with the right-hand side as a reference. +pub trait ClosedBitXorAssignRef: for<'a> BitXorAssign<&'a Rhs> {} + +/// Trait for closed left shift assignment operation. +pub trait ClosedShlAssign: ShlAssign {} + +/// Trait for closed left shift assignment operation with the right-hand side as a reference. +pub trait ClosedShlAssignRef: for<'a> ShlAssign<&'a Rhs> {} + +/// Trait for closed right shift assignment operation. +pub trait ClosedShrAssign: ShrAssign {} + +/// Trait for closed right shift assignment operation with the right-hand side as a reference. +pub trait ClosedShrAssignRef: for<'a> ShrAssign<&'a Rhs> {} + +/// Trait for types with a closed zero value. +pub trait ClosedZero: Zero {} + +/// Trait for types with a closed one value. +pub trait ClosedOne: One {} + +/// Trait for closed Euclidean division operation +pub trait ClosedDivEuclid: Sized { + fn div_euclid(self, rhs: Self) -> Self; +} + +/// Trait for closed Euclidean remainder operation +pub trait ClosedRemEuclid: Sized { + fn rem_euclid(self, rhs: Self) -> Self; +} + +// Blanket implementations +impl ClosedDivEuclid for T +where + T: Euclid, +{ + fn div_euclid(self, rhs: Self) -> Self { + Euclid::div_euclid(&self, &rhs) + } +} + +impl ClosedRemEuclid for T +where + T: Euclid, +{ + fn rem_euclid(self, rhs: Self) -> Self { + Euclid::rem_euclid(&self, &rhs) + } +} + +/// Trait for closed minimum operation +pub trait ClosedMin: Sized { + fn min(self, other: Rhs) -> Self; +} + +/// Trait for closed maximum operation +pub trait ClosedMax: Sized { + fn max(self, other: Rhs) -> Self; +} + +impl ClosedAdd for T where T: Add {} +impl ClosedAddRef for T where T: for<'a> Add<&'a Rhs, Output = T> {} +impl ClosedSub for T where T: Sub {} +impl ClosedSubRef for T where T: for<'a> Sub<&'a Rhs, Output = T> {} +impl ClosedMul for T where T: Mul {} +impl ClosedMulRef for T where T: for<'a> Mul<&'a Rhs, Output = T> {} +impl ClosedDiv for T where T: Div {} +impl ClosedDivRef for T where T: for<'a> Div<&'a Rhs, Output = T> {} +impl ClosedRem for T where T: Rem {} +impl ClosedRemRef for T where T: for<'a> Rem<&'a Rhs, Output = T> {} +impl ClosedNeg for T where T: Neg {} + +impl ClosedAddAssign for T where T: AddAssign {} +impl ClosedAddAssignRef for T where T: for<'a> AddAssign<&'a Rhs> {} +impl ClosedSubAssign for T where T: SubAssign {} +impl ClosedSubAssignRef for T where T: for<'a> SubAssign<&'a Rhs> {} +impl ClosedMulAssign for T where T: MulAssign {} +impl ClosedMulAssignRef for T where T: for<'a> MulAssign<&'a Rhs> {} +impl ClosedDivAssign for T where T: DivAssign {} +impl ClosedDivAssignRef for T where T: for<'a> DivAssign<&'a Rhs> {} +impl ClosedRemAssign for T where T: RemAssign {} +impl ClosedRemAssignRef for T where T: for<'a> RemAssign<&'a Rhs> {} + +impl ClosedBitAnd for T where T: BitAnd {} +impl ClosedBitAndRef for T where T: for<'a> BitAnd<&'a Rhs, Output = T> {} +impl ClosedBitOr for T where T: BitOr {} +impl ClosedBitOrRef for T where T: for<'a> BitOr<&'a Rhs, Output = T> {} +impl ClosedBitXor for T where T: BitXor {} +impl ClosedBitXorRef for T where T: for<'a> BitXor<&'a Rhs, Output = T> {} +impl ClosedNot for T where T: Not {} +impl ClosedShl for T where T: Shl {} +impl ClosedShlRef for T where T: for<'a> Shl<&'a Rhs, Output = T> {} +impl ClosedShr for T where T: Shr {} +impl ClosedShrRef for T where T: for<'a> Shr<&'a Rhs, Output = T> {} + +impl ClosedBitAndAssign for T where T: BitAndAssign {} +impl ClosedBitAndAssignRef for T where T: for<'a> BitAndAssign<&'a Rhs> {} +impl ClosedBitOrAssign for T where T: BitOrAssign {} +impl ClosedBitOrAssignRef for T where T: for<'a> BitOrAssign<&'a Rhs> {} +impl ClosedBitXorAssign for T where T: BitXorAssign {} +impl ClosedBitXorAssignRef for T where T: for<'a> BitXorAssign<&'a Rhs> {} +impl ClosedShlAssign for T where T: ShlAssign {} +impl ClosedShlAssignRef for T where T: for<'a> ShlAssign<&'a Rhs> {} +impl ClosedShrAssign for T where T: ShrAssign {} +impl ClosedShrAssignRef for T where T: for<'a> ShrAssign<&'a Rhs> {} + +impl ClosedZero for T {} +impl ClosedOne for T {} + +impl ClosedMin for T { + fn min(self, other: Self) -> Self { + std::cmp::min(self, other) + } +} + +impl ClosedMax for T { + fn max(self, other: Self) -> Self { + std::cmp::max(self, other) + } +} \ No newline at end of file From 23b6abaa2d229e2f9c8b55323da789a67113e5e7 Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Fri, 12 Jul 2024 19:52:45 -0400 Subject: [PATCH 03/21] fix: remove duplicate --- src/lib.rs | 112 ++++++++++++------------------------------------ src/operator.rs | 71 ++++++++++++++++++++++++++++-- 2 files changed, 94 insertions(+), 89 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d1fefc5..4241d0f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -125,51 +125,7 @@ mod operator; -use num_traits::Euclid; -pub use num_traits::{Inv, One, Zero}; -pub use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; - -/// Trait alias for `Add` with result of type `Self`. -pub trait ClosedAdd: Sized + Add {} - -/// Trait alias for `Sub` with result of type `Self`. -pub trait ClosedSub: Sized + Sub {} - -/// Trait alias for `Mul` with result of type `Self`. -pub trait ClosedMul: Sized + Mul {} - -/// Trait alias for `Div` with result of type `Self`. -pub trait ClosedDiv: Sized + Div {} - -/// Trait alias for `Neg` with result of type `Self`. -pub trait ClosedNeg: Sized + Neg {} - -/// Trait alias for `Add` and `AddAssign` with result of type `Self`. -pub trait ClosedAddAssign: ClosedAdd + AddAssign {} - -/// Trait alias for `Sub` and `SubAssign` with result of type `Self`. -pub trait ClosedSubAssign: ClosedSub + SubAssign {} - -/// Trait alias for `Mul` and `MulAssign` with result of type `Self`. -pub trait ClosedMulAssign: ClosedMul + MulAssign {} - -/// Trait alias for `Div` and `DivAssign` with result of type `Self`. -pub trait ClosedDivAssign: ClosedDiv + DivAssign {} - -/// Trait alias for `Inv` with result of type `Self`. -pub trait ClosedInv: Inv {} - -// Blanket implementations for the closed traits -impl ClosedAdd for T where T: Add + AddAssign {} -impl ClosedSub for T where T: Sub + SubAssign {} -impl ClosedMul for T where T: Mul + MulAssign {} -impl ClosedDiv for T where T: Div + DivAssign {} -impl ClosedNeg for T where T: Neg {} -impl ClosedAddAssign for T where T: ClosedAdd + AddAssign {} -impl ClosedSubAssign for T where T: ClosedSub + SubAssign {} -impl ClosedMulAssign for T where T: ClosedMul + MulAssign {} -impl ClosedDivAssign for T where T: ClosedDiv + DivAssign {} -impl ClosedInv for T where T: Inv {} +pub use operator::*; /// Basic representation of a mathematical set, a collection of distinct objects. /// @@ -191,28 +147,6 @@ pub trait Set: Sized + Clone + PartialEq { fn contains(&self, element: &Self) -> bool; } -// TODO -// A lot of the weirdness here comes from the fact that we can't -// easily wrap the binary operator and find out if it has certain -// properties, and so we introduce this marker trait -// and the chains of lookalike strucure up to the semiring -// when the two operators unit. This is definitely sub optimal. - -/// Marker trait for associative operations. -/// -/// An operation β€’ is associative if (a β€’ b) β€’ c = a β€’ (b β€’ c) for all a, b, c in the set. -pub trait Associative {} - -/// Marker trait for commutative operations. -/// -/// An operation β€’ is commutative if a β€’ b = b β€’ a for all a, b in the set. -pub trait Commutative {} - -/// Marker trait for idempotent operations. -/// -/// An operation β€’ is idempotent if a β€’ a = a for all a in the set. -pub trait Idempotent {} - /// Represents a set with a closed addition operation (magma). /// /// A magma is the most basic algebraic structure, consisting of a set with a single binary operation @@ -240,26 +174,26 @@ impl AdditiveQuasigroup for T where T: AdditiveMagma {} /// /// # Properties /// - Associativity: βˆ€ a, b, c ∈ Self, (a + b) + c = a + (b + c) -pub trait AdditiveSemigroup: AdditiveMagma + Associative {} +pub trait AdditiveSemigroup: AdditiveMagma + Associativity {} -impl AdditiveSemigroup for T where T: AdditiveMagma + Associative {} +impl AdditiveSemigroup for T where T: AdditiveMagma + Associativity {} /// Represents an additive quasigroup with an identity element (zero). /// /// # Properties /// - Identity Element: βˆƒ 0 ∈ Self, βˆ€ a ∈ Self, 0 + a = a + 0 = a -pub trait AdditiveLoop: AdditiveQuasigroup + Zero {} +pub trait AdditiveLoop: AdditiveQuasigroup + ClosedZero {} -impl AdditiveLoop for T where T: AdditiveQuasigroup + Zero {} +impl AdditiveLoop for T where T: AdditiveQuasigroup + ClosedZero {} /// Represents an additive semigroup with an identity element (zero). /// /// # Properties /// - Associativity (from Semigroup) /// - Identity Element: βˆƒ 0 ∈ Self, βˆ€ a ∈ Self, 0 + a = a + 0 = a -pub trait AdditiveMonoid: AdditiveSemigroup + Zero {} +pub trait AdditiveMonoid: AdditiveSemigroup + ClosedZero {} -impl AdditiveMonoid for T where T: AdditiveSemigroup + Zero {} +impl AdditiveMonoid for T where T: AdditiveSemigroup + ClosedZero {} /// Represents an additive group. /// @@ -279,9 +213,9 @@ impl AdditiveGroup for T where T: AdditiveMonoid + AdditiveQuasigroup + Close /// # Properties /// - All Group properties /// - Commutativity: βˆ€ a, b ∈ Self, a + b = b + a -pub trait AdditiveAbelianGroup: AdditiveGroup + Commutative {} +pub trait AdditiveAbelianGroup: AdditiveGroup + Commutativity {} -impl AdditiveAbelianGroup for T where T: AdditiveGroup + Commutative {} +impl AdditiveAbelianGroup for T where T: AdditiveGroup + Commutativity {} /// Represents a set with a closed multiplication operation (magma). pub trait MultiplicativeMagma: Set + ClosedMul + ClosedMulAssign {} @@ -297,21 +231,27 @@ pub trait MultiplicativeQuasigroup: MultiplicativeMagma {} impl MultiplicativeQuasigroup for T where T: MultiplicativeMagma {} /// Represents an associative multiplicative magma. -pub trait MultiplicativeSemigroup: MultiplicativeMagma + Associative {} +pub trait MultiplicativeSemigroup: MultiplicativeMagma + Associativity {} -impl MultiplicativeSemigroup for T where T: MultiplicativeMagma + Associative {} +impl MultiplicativeSemigroup for T where T: MultiplicativeMagma + Associativity {} /// Represents a multiplicative quasigroup with an identity element (one). -pub trait MultiplicativeLoop: MultiplicativeQuasigroup + One {} +pub trait MultiplicativeLoop: MultiplicativeQuasigroup + ClosedOne {} -impl MultiplicativeLoop for T where T: MultiplicativeQuasigroup + One {} +impl MultiplicativeLoop for T where T: MultiplicativeQuasigroup + ClosedOne {} /// Represents a multiplicative monoid. /// /// A monoid is a semigroup with an identity element. -pub trait MultiplicativeMonoid: MultiplicativeSemigroup + MultiplicativeQuasigroup + One {} +pub trait MultiplicativeMonoid: + MultiplicativeSemigroup + MultiplicativeQuasigroup + ClosedOne +{ +} -impl MultiplicativeMonoid for T where T: MultiplicativeSemigroup + MultiplicativeQuasigroup + One {} +impl MultiplicativeMonoid for T where + T: MultiplicativeSemigroup + MultiplicativeQuasigroup + ClosedOne +{ +} /// Represents a multiplicative group. /// @@ -321,9 +261,9 @@ pub trait MultiplicativeGroup: MultiplicativeMonoid + ClosedInv {} impl MultiplicativeGroup for T where T: MultiplicativeMonoid + ClosedInv {} /// Represents a multiplicative abelian (commutative) group. -pub trait MultiplicativeAbelianGroup: MultiplicativeGroup + Commutative {} +pub trait MultiplicativeAbelianGroup: MultiplicativeGroup + Commutativity {} -impl MultiplicativeAbelianGroup for T where T: MultiplicativeGroup + Commutative {} +impl MultiplicativeAbelianGroup for T where T: MultiplicativeGroup + Commutativity {} /// Represents a semiring. /// @@ -383,9 +323,9 @@ impl IntegralDomain for T where T: CommutativeRing {} /// - Euclidean function f: Self \ {0} β†’ β„• satisfying: /// 1. βˆ€ a, b ∈ Self, b β‰  0, βˆƒ q, r ∈ Self such that a = bq + r, where r = 0 or f(r) < f(b) /// 2. βˆ€ a, b ∈ Self, b β‰  0 β‡’ f(a) ≀ f(ab) -pub trait EuclideanDomain: IntegralDomain + Euclid {} +pub trait EuclideanDomain: IntegralDomain + ClosedRemEuclid {} -impl EuclideanDomain for T where T: IntegralDomain + Euclid {} +impl EuclideanDomain for T where T: IntegralDomain + ClosedRemEuclid {} /// Represents a field. /// @@ -430,6 +370,8 @@ impl RealField for T where T: Field + PartialOrd {} mod tests { use super::*; use std::borrow::Cow; + use std::ops::Add; + use std::ops::AddAssign; #[derive(Debug, Clone, PartialEq)] struct StringMagma<'a>(Cow<'a, str>); diff --git a/src/operator.rs b/src/operator.rs index eb2c913..19ebc61 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -74,9 +74,68 @@ //! still manually implement these traits for your types, and the manual implementations //! will take precedence over these blanket implementations. -use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign, Rem, RemAssign, Neg}; -use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Shl, ShlAssign, Shr, ShrAssign}; -use num_traits::{Zero, One, Euclid}; +use num_traits::{Euclid, Inv, One, Zero}; +use std::ops::{ + Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign, +}; +use std::ops::{ + BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Shl, ShlAssign, Shr, + ShrAssign, +}; + +/// Marker trait for commutative operations +pub trait Commutativity {} + +/// Marker trait for associative operations +pub trait Associativity {} + +/// Marker trait for idempotent operations +pub trait Idempotence {} + +/// Marker trait for operations with inverses +pub trait Inverses {} + +/// Marker trait for operations with the cancellation property +pub trait Cancellation {} + +/// Marker trait for operations with the divisibility property +pub trait Divisibility {} + +/// Marker trait for regular operations +pub trait Regularity {} + +/// Marker trait for alternative operations +pub trait Alternativity {} + +/// Marker trait for distributive operations +pub trait Distributivity {} + +/// Marker trait for operations with the absorption property +pub trait Absorption {} + +/// Marker trait for monotonic operations +pub trait Monotonicity {} + +/// Marker trait for modular operations +pub trait Modularity {} + +/// Marker trait for switchable operations +pub trait Switchability {} + +/// Marker trait for min/max operations +pub trait MinMaxOps {} + +/// Marker trait for defect operations +pub trait DefectOp {} + +/// Marker trait for continuous operations +pub trait Continuity {} + +/// Marker trait for solvable operations +pub trait Solvability {} + +/// Marker trait for algebraically closed operations +pub trait AlgebraicClosure {} /// Trait for closed addition operation. pub trait ClosedAdd: Add {} @@ -111,6 +170,9 @@ pub trait ClosedRemRef: for<'a> Rem<&'a Rhs, Output = Self> {} /// Trait for closed negation operation. pub trait ClosedNeg: Neg {} +/// Trait for closed negation operation. +pub trait ClosedInv: Inv {} + /// Trait for closed addition assignment operation. pub trait ClosedAddAssign: AddAssign {} @@ -260,6 +322,7 @@ impl ClosedDivRef for T where T: for<'a> Div<&'a Rhs, Output = T> { impl ClosedRem for T where T: Rem {} impl ClosedRemRef for T where T: for<'a> Rem<&'a Rhs, Output = T> {} impl ClosedNeg for T where T: Neg {} +impl ClosedInv for T where T: Inv {} impl ClosedAddAssign for T where T: AddAssign {} impl ClosedAddAssignRef for T where T: for<'a> AddAssign<&'a Rhs> {} @@ -308,4 +371,4 @@ impl ClosedMax for T { fn max(self, other: Self) -> Self { std::cmp::max(self, other) } -} \ No newline at end of file +} From a8284b8eb35f985cde825a0f70f590ea8646a96d Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Fri, 12 Jul 2024 19:54:31 -0400 Subject: [PATCH 04/21] fix: cleanup duplicate docs --- src/lib.rs | 31 ------------------------------- src/operator.rs | 2 -- 2 files changed, 33 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 4241d0f..69f2aea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,37 +11,6 @@ //! structs based on the properties they satisfy, and be applied in most cases for //! anything from scalar values to n-dimensional arrays. //! -//! ## Binary Operations and Their Properties -//! -//! An algebraic structure consists of a set with one or more binary operations. -//! Let 𝑆 be a set (Self) and β€’ be a binary operation on 𝑆. -//! Here are the key properties a binary operation may possess, organized from simplest to most complex: -//! -//! - (Closure) βˆ€ a, b ∈ 𝑆, a β€’ b ∈ 𝑆 -//! - (Totality) βˆ€ a, b ∈ 𝑆, a β€’ b is defined -//! - (Commutativity) βˆ€ a, b ∈ 𝑆, a β€’ b = b β€’ a -//! - (Associativity) βˆ€ a, b, c ∈ 𝑆, (a β€’ b) β€’ c = a β€’ (b β€’ c) -//! - (Idempotence) βˆ€ a ∈ 𝑆, a β€’ a = a -//! - (Identity) βˆƒ e ∈ 𝑆, βˆ€ a ∈ 𝑆, e β€’ a = a β€’ e = a -//! - (Inverses) βˆ€ a ∈ 𝑆, βˆƒ b ∈ 𝑆, a β€’ b = b β€’ a = e (where e is the identity) -//! - (Cancellation) βˆ€ a, b, c ∈ 𝑆, a β€’ b = a β€’ c β‡’ b = c (a β‰  0 if βˆƒ zero element) -//! - (Divisibility) βˆ€ a, b ∈ 𝑆, βˆƒ x ∈ 𝑆, a β€’ x = b -//! - (Regularity) βˆ€ a ∈ 𝑆, βˆƒ x ∈ 𝑆, a β€’ x β€’ a = a -//! - (Alternativity) βˆ€ a, b ∈ 𝑆, (a β€’ a) β€’ b = a β€’ (a β€’ b) ∧ (b β€’ a) β€’ a = b β€’ (a β€’ a) -//! - (Distributivity) βˆ€ a, b, c ∈ 𝑆, a * (b + c) = (a * b) + (a * c) -//! - (Absorption) βˆ€ a, b ∈ 𝑆, a * (a + b) = a ∧ a + (a * b) = a -//! - (Monotonicity) βˆ€ a, b, c ∈ 𝑆, a ≀ b β‡’ a β€’ c ≀ b β€’ c ∧ c β€’ a ≀ c β€’ b -//! - (Modularity) βˆ€ a, b, c ∈ 𝑆, a ≀ c β‡’ a ∨ (b ∧ c) = (a ∨ b) ∧ c -//! - (Switchability) βˆ€ x, y, z ∈ S, (x + y) * z = x + (y * z) -//! - (Min/Max Ops) βˆ€ a, b ∈ S, a ∨ b = min{a,b}, a ∧ b = max{a,b} -//! - (Defect Op) βˆ€ a, b ∈ S, a *₃ b = a + b - 3 -//! - (Continuity) βˆ€ V βŠ† 𝑆 open, f⁻¹(V) is open (for f: 𝑆 β†’ 𝑆, 𝑆 topological) -//! - (Solvability) βˆƒ series {Gα΅’} | G = Gβ‚€ β–· G₁ β–· ... β–· Gβ‚™ = {e}, [Gα΅’, Gα΅’] ≀ Gα΅’β‚Šβ‚ -//! - (Alg. Closure) βˆ€ p(x) ∈ 𝑆[x] non-constant, βˆƒ a ∈ 𝑆 | p(a) = 0 -//! -//! In general, checking the properties of the binary operators at compile time -//! which are implemented is a challenge. -//! //! ## Hierarchy of Scalar Algebraic Structures //! //! ```text diff --git a/src/operator.rs b/src/operator.rs index 19ebc61..c5aa822 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -3,8 +3,6 @@ //! This module defines traits for various operators and their properties, //! providing a foundation for implementing algebraic structures in Rust. //! -//! ## Binary Operations and Their Properties -//! //! An algebraic structure consists of a set with one or more binary operations. //! Let 𝑆 be a set (Self) and β€’ be a binary operation on 𝑆. //! Here are the key properties a binary operation may possess, organized from simplest to most complex: From 4f8003968543099e4f4713f8ceafca40112db408 Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Fri, 12 Jul 2024 20:40:52 -0400 Subject: [PATCH 05/21] fix: add generic binary operation --- src/lib.rs | 16 ++++++++-------- src/operator.rs | 39 +++++++++++++++++++++------------------ 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 69f2aea..4c69222 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -143,9 +143,9 @@ impl AdditiveQuasigroup for T where T: AdditiveMagma {} /// /// # Properties /// - Associativity: βˆ€ a, b, c ∈ Self, (a + b) + c = a + (b + c) -pub trait AdditiveSemigroup: AdditiveMagma + Associativity {} +pub trait AdditiveSemigroup: AdditiveMagma + Associative {} -impl AdditiveSemigroup for T where T: AdditiveMagma + Associativity {} +impl AdditiveSemigroup for T where T: AdditiveMagma + Associative {} /// Represents an additive quasigroup with an identity element (zero). /// @@ -182,9 +182,9 @@ impl AdditiveGroup for T where T: AdditiveMonoid + AdditiveQuasigroup + Close /// # Properties /// - All Group properties /// - Commutativity: βˆ€ a, b ∈ Self, a + b = b + a -pub trait AdditiveAbelianGroup: AdditiveGroup + Commutativity {} +pub trait AdditiveAbelianGroup: AdditiveGroup + Commutative {} -impl AdditiveAbelianGroup for T where T: AdditiveGroup + Commutativity {} +impl AdditiveAbelianGroup for T where T: AdditiveGroup + Commutative {} /// Represents a set with a closed multiplication operation (magma). pub trait MultiplicativeMagma: Set + ClosedMul + ClosedMulAssign {} @@ -200,9 +200,9 @@ pub trait MultiplicativeQuasigroup: MultiplicativeMagma {} impl MultiplicativeQuasigroup for T where T: MultiplicativeMagma {} /// Represents an associative multiplicative magma. -pub trait MultiplicativeSemigroup: MultiplicativeMagma + Associativity {} +pub trait MultiplicativeSemigroup: MultiplicativeMagma + Associative {} -impl MultiplicativeSemigroup for T where T: MultiplicativeMagma + Associativity {} +impl MultiplicativeSemigroup for T where T: MultiplicativeMagma + Associative {} /// Represents a multiplicative quasigroup with an identity element (one). pub trait MultiplicativeLoop: MultiplicativeQuasigroup + ClosedOne {} @@ -230,9 +230,9 @@ pub trait MultiplicativeGroup: MultiplicativeMonoid + ClosedInv {} impl MultiplicativeGroup for T where T: MultiplicativeMonoid + ClosedInv {} /// Represents a multiplicative abelian (commutative) group. -pub trait MultiplicativeAbelianGroup: MultiplicativeGroup + Commutativity {} +pub trait MultiplicativeAbelianGroup: MultiplicativeGroup + Commutative {} -impl MultiplicativeAbelianGroup for T where T: MultiplicativeGroup + Commutativity {} +impl MultiplicativeAbelianGroup for T where T: MultiplicativeGroup + Commutative {} /// Represents a semiring. /// diff --git a/src/operator.rs b/src/operator.rs index c5aa822..36a8313 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -81,53 +81,56 @@ use std::ops::{ ShrAssign, }; +/// A generic trait for binary operations +pub trait BinaryOp: Sized { + type Output; + fn apply(&self, lhs: &Self, rhs: &Rhs) -> Self::Output; +} + /// Marker trait for commutative operations -pub trait Commutativity {} +pub trait Commutative: BinaryOp {} /// Marker trait for associative operations -pub trait Associativity {} +pub trait Associative: BinaryOp {} /// Marker trait for idempotent operations -pub trait Idempotence {} +pub trait Idempotent: BinaryOp {} -/// Marker trait for operations with inverses -pub trait Inverses {} +/// Marker trait for operations with inverses for all elements +pub trait Invertible {} /// Marker trait for operations with the cancellation property -pub trait Cancellation {} +pub trait Cancellative: BinaryOp {} /// Marker trait for operations with the divisibility property -pub trait Divisibility {} +pub trait Divisible {} /// Marker trait for regular operations -pub trait Regularity {} +pub trait Regular: BinaryOp {} /// Marker trait for alternative operations -pub trait Alternativity {} +pub trait Alternative: BinaryOp {} /// Marker trait for distributive operations -pub trait Distributivity {} +pub trait Distributive {} /// Marker trait for operations with the absorption property -pub trait Absorption {} +pub trait Absorptive {} /// Marker trait for monotonic operations -pub trait Monotonicity {} +pub trait Monotonic {} /// Marker trait for modular operations -pub trait Modularity {} +pub trait Modular {} /// Marker trait for switchable operations -pub trait Switchability {} - -/// Marker trait for min/max operations -pub trait MinMaxOps {} +pub trait Switchable {} /// Marker trait for defect operations pub trait DefectOp {} /// Marker trait for continuous operations -pub trait Continuity {} +pub trait Continuous {} /// Marker trait for solvable operations pub trait Solvability {} From 709bf78d63b08be86a8425b5277679db1d4018e6 Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Fri, 12 Jul 2024 22:51:22 -0400 Subject: [PATCH 06/21] feat: set and magma --- src/concrete.rs | 148 ++++++++++++++++++++++ src/lib.rs | 329 ++---------------------------------------------- src/magma.rs | 171 +++++++++++++++++++++++++ src/operator.rs | 3 - src/set.rs | 150 ++++++++++++++++++++++ 5 files changed, 476 insertions(+), 325 deletions(-) create mode 100644 src/concrete.rs create mode 100644 src/magma.rs create mode 100644 src/set.rs diff --git a/src/concrete.rs b/src/concrete.rs new file mode 100644 index 0000000..01d6de1 --- /dev/null +++ b/src/concrete.rs @@ -0,0 +1,148 @@ +// concrete.rs + +use crate::set::Set; +use std::ops::{Add, Mul}; + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct Z5(u8); + +impl Z5 { + pub fn new(value: u8) -> Self { + Z5(value % 5) + } +} + +impl Add for Z5 { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Z5::new(self.0 + rhs.0) + } +} + +impl Mul for Z5 { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + Z5::new(self.0 * rhs.0) + } +} + +impl Set for Z5 { + fn is_empty(&self) -> bool { + false + } + + fn contains(&self, element: &Z5) -> bool { + *self == *element + } + + fn empty() -> Self { + Z5(0) + } + + fn singleton(element: Z5) -> Self { + element + } + + fn union(&self, other: &Self) -> Self { + if self == other { + *self + } else { + Z5::new(self.0.min(other.0)) + } + } + + fn intersection(&self, other: &Self) -> Self { + if self == other { + *self + } else { + Z5::new(0) + } + } + + fn difference(&self, other: &Self) -> Self { + if self == other { + Z5::new(0) + } else { + *self + } + } + + fn symmetric_difference(&self, other: &Self) -> Self { + if self == other { + Z5::new(0) + } else { + Z5::new(self.0.max(other.0)) + } + } + + fn is_subset(&self, other: &Self) -> bool { + self == other + } + + fn is_equal(&self, other: &Self) -> bool { + self == other + } + + fn cardinality(&self) -> Option { + Some(1) + } + + fn is_finite(&self) -> bool { + true + } +} + +#[derive(Clone, PartialEq, Debug)] +pub struct InfiniteRealSet; + +impl Set for InfiniteRealSet { + fn is_empty(&self) -> bool { + false + } + + fn contains(&self, _element: &f64) -> bool { + true + } + + fn empty() -> Self { + InfiniteRealSet + } + + fn singleton(_element: f64) -> Self { + InfiniteRealSet + } + + fn union(&self, _other: &Self) -> Self { + InfiniteRealSet + } + + fn intersection(&self, _other: &Self) -> Self { + InfiniteRealSet + } + + fn difference(&self, _other: &Self) -> Self { + InfiniteRealSet + } + + fn symmetric_difference(&self, _other: &Self) -> Self { + InfiniteRealSet + } + + fn is_subset(&self, _other: &Self) -> bool { + true + } + + fn is_equal(&self, _other: &Self) -> bool { + true + } + + fn cardinality(&self) -> Option { + None + } + + fn is_finite(&self) -> bool { + false + } +} diff --git a/src/lib.rs b/src/lib.rs index 4c69222..5c48eef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -92,331 +92,16 @@ //! β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ //! ``` +mod magma; mod operator; +mod set; -pub use operator::*; - -/// Basic representation of a mathematical set, a collection of distinct objects. -/// -/// In set theory, a set is a well-defined collection of distinct objects. These objects -/// are called elements or members of the set. This trait provides methods to work with -/// sets in a way that aligns with fundamental set theory concepts. -/// -/// # Set Theory Concepts -/// -/// - **Membership**: An object `element` is a member of set `Self` if `element ∈ Self`. -/// - **Empty Set**: The unique set with no elements, denoted as βˆ…. -/// - **Subset**: A set `Self` is a subset of set `Other`, denoted as `Self βŠ† Other`, if every element of `Self` is also an element of `Other`. -/// - **Set Equality**: Two sets are equal if they have exactly the same elements. -/// -/// This trait is meant for sets representing numerics like the natural numbers, integers, real numbers, etc. -/// Represents a mathematical set rather than a broader collection type. -pub trait Set: Sized + Clone + PartialEq { - /// Checks if the given element is a member of the set. - fn contains(&self, element: &Self) -> bool; -} - -/// Represents a set with a closed addition operation (magma). -/// -/// A magma is the most basic algebraic structure, consisting of a set with a single binary operation -/// that is closed. -/// -/// # Properties -/// - Closure: βˆ€ a, b ∈ Self, a + b ∈ Self -pub trait AdditiveMagma: Set + ClosedAdd + ClosedAddAssign {} - -/// Represents an additive quasigroup. -/// -/// A quasigroup is a magma where division is always possible and unique. -/// -/// # Properties -/// - Latin Square Property: For any elements a and b, there exist unique elements x and y such that: -/// a + x = b and y + a = b -/// -/// TODO: Implement a method to enforce the Latin square property of the Cayley table. -/// This is challenging to express in Rust's type system and may require runtime checks. -pub trait AdditiveQuasigroup: AdditiveMagma {} - -impl AdditiveQuasigroup for T where T: AdditiveMagma {} - -/// Represents an associative additive magma. -/// -/// # Properties -/// - Associativity: βˆ€ a, b, c ∈ Self, (a + b) + c = a + (b + c) -pub trait AdditiveSemigroup: AdditiveMagma + Associative {} - -impl AdditiveSemigroup for T where T: AdditiveMagma + Associative {} - -/// Represents an additive quasigroup with an identity element (zero). -/// -/// # Properties -/// - Identity Element: βˆƒ 0 ∈ Self, βˆ€ a ∈ Self, 0 + a = a + 0 = a -pub trait AdditiveLoop: AdditiveQuasigroup + ClosedZero {} - -impl AdditiveLoop for T where T: AdditiveQuasigroup + ClosedZero {} - -/// Represents an additive semigroup with an identity element (zero). -/// -/// # Properties -/// - Associativity (from Semigroup) -/// - Identity Element: βˆƒ 0 ∈ Self, βˆ€ a ∈ Self, 0 + a = a + 0 = a -pub trait AdditiveMonoid: AdditiveSemigroup + ClosedZero {} - -impl AdditiveMonoid for T where T: AdditiveSemigroup + ClosedZero {} - -/// Represents an additive group. -/// -/// A group is a monoid where every element has an inverse. -/// -/// # Properties -/// - Associativity and Identity (from Monoid) -/// - Inverses: βˆ€ a ∈ Self, βˆƒ -a ∈ Self such that a + (-a) = (-a) + a = 0 -/// -/// Note: For groups, the quasigroup property is satisfied by the inverse element. -pub trait AdditiveGroup: AdditiveMonoid + AdditiveQuasigroup + ClosedNeg {} - -impl AdditiveGroup for T where T: AdditiveMonoid + AdditiveQuasigroup + ClosedNeg {} - -/// Represents an additive abelian (commutative) group. -/// -/// # Properties -/// - All Group properties -/// - Commutativity: βˆ€ a, b ∈ Self, a + b = b + a -pub trait AdditiveAbelianGroup: AdditiveGroup + Commutative {} - -impl AdditiveAbelianGroup for T where T: AdditiveGroup + Commutative {} - -/// Represents a set with a closed multiplication operation (magma). -pub trait MultiplicativeMagma: Set + ClosedMul + ClosedMulAssign {} - -impl MultiplicativeMagma for T where T: Set + ClosedMul + ClosedMulAssign {} - -/// Represents a multiplicative quasigroup. -/// -/// TODO: Implement a method to enforce the Latin square property of the Cayley table. -/// This is challenging to express in Rust's type system and may require runtime checks. -pub trait MultiplicativeQuasigroup: MultiplicativeMagma {} - -impl MultiplicativeQuasigroup for T where T: MultiplicativeMagma {} - -/// Represents an associative multiplicative magma. -pub trait MultiplicativeSemigroup: MultiplicativeMagma + Associative {} - -impl MultiplicativeSemigroup for T where T: MultiplicativeMagma + Associative {} - -/// Represents a multiplicative quasigroup with an identity element (one). -pub trait MultiplicativeLoop: MultiplicativeQuasigroup + ClosedOne {} - -impl MultiplicativeLoop for T where T: MultiplicativeQuasigroup + ClosedOne {} - -/// Represents a multiplicative monoid. -/// -/// A monoid is a semigroup with an identity element. -pub trait MultiplicativeMonoid: - MultiplicativeSemigroup + MultiplicativeQuasigroup + ClosedOne -{ -} - -impl MultiplicativeMonoid for T where - T: MultiplicativeSemigroup + MultiplicativeQuasigroup + ClosedOne -{ -} - -/// Represents a multiplicative group. -/// -/// A group is a monoid where every non-zero element has a multiplicative inverse. -pub trait MultiplicativeGroup: MultiplicativeMonoid + ClosedInv {} - -impl MultiplicativeGroup for T where T: MultiplicativeMonoid + ClosedInv {} - -/// Represents a multiplicative abelian (commutative) group. -pub trait MultiplicativeAbelianGroup: MultiplicativeGroup + Commutative {} - -impl MultiplicativeAbelianGroup for T where T: MultiplicativeGroup + Commutative {} +pub use set::*; -/// Represents a semiring. -/// -/// A semiring introduces a second binary operation. We now use + and * to distinguish between -/// the two operations. -/// -/// # Properties -/// - (Self, +) is a commutative monoid -/// - (Self, *) is a monoid -/// - Distributive property: a * (b + c) = (a * b) + (a * c) and (b + c) * a = (b * a) + (c * a) -/// - Multiplication by additive identity annihilates: 0 * a = a * 0 = 0 -pub trait Semiring: AdditiveAbelianGroup + MultiplicativeMonoid { - // TODO(Figure out how to check the distributive property holds) -} - -impl Semiring for T where T: AdditiveAbelianGroup + MultiplicativeMonoid {} - -/// Represents a ring. -/// -/// A ring is a semiring where the additive structure is an abelian group. -/// -/// # Properties -/// - All Semiring properties -/// - (Self, +) is an abelian group -pub trait Ring: Semiring + AdditiveGroup {} - -impl Ring for T where T: Semiring + AdditiveGroup {} - -/// Represents a commutative ring. -/// -/// A commutative ring is a ring where multiplication is commutative. -/// -/// # Properties -/// - All Ring properties -/// - Commutativity of multiplication: βˆ€ a, b ∈ Self, a * b = b * a -pub trait CommutativeRing: Ring + MultiplicativeAbelianGroup {} - -impl CommutativeRing for T where T: Ring + MultiplicativeAbelianGroup {} - -/// Represents an integral domain. -/// -/// An integral domain is a commutative ring with no zero divisors. -/// -/// # Properties -/// - All Commutative Ring properties -/// - No zero divisors: If a * b = 0, then a = 0 or b = 0 -pub trait IntegralDomain: CommutativeRing {} - -impl IntegralDomain for T where T: CommutativeRing {} - -/// Represents a Euclidean domain. -/// -/// A Euclidean domain is an integral domain equipped with a Euclidean function. -/// -/// # Properties -/// - All Integral Domain properties -/// - Euclidean function f: Self \ {0} β†’ β„• satisfying: -/// 1. βˆ€ a, b ∈ Self, b β‰  0, βˆƒ q, r ∈ Self such that a = bq + r, where r = 0 or f(r) < f(b) -/// 2. βˆ€ a, b ∈ Self, b β‰  0 β‡’ f(a) ≀ f(ab) -pub trait EuclideanDomain: IntegralDomain + ClosedRemEuclid {} - -impl EuclideanDomain for T where T: IntegralDomain + ClosedRemEuclid {} - -/// Represents a field. -/// -/// A field is a commutative ring where every non-zero element has a multiplicative inverse, -/// and the distributive property holds. -/// -/// # Properties -/// - All Integral Domain properties -/// - Multiplicative inverses for non-zero elements: -/// βˆ€ a ∈ Self, a β‰  0 β‡’ βˆƒ a⁻¹ ∈ Self such that a * a⁻¹ = a⁻¹ * a = 1 -/// - Distributive property: βˆ€ a, b, c ∈ Self, a * (b + c) = (a * b) + (a * c) -pub trait Field: IntegralDomain + MultiplicativeGroup {} - -impl Field for T where T: IntegralDomain + MultiplicativeGroup {} - -/// Represents a finite field. -/// -/// A finite field is a field with a finite number of elements. -/// -/// # Properties -/// - All Field properties -/// - |Self| = p^n where p is prime and n is a positive integer -pub trait FiniteField: Field { - /// Returns the order (number of elements) of the finite field. - fn order() -> usize; -} - -/// Represents the field of real numbers. -/// -/// The real field is the field of real numbers. -/// -/// # Properties -/// - All Field properties -/// - Totally ordered: βˆ€ a, b ∈ ℝ, exactly one of a < b, a = b, or a > b is true -/// - Order-compatible with operations -/// - Dedekind-complete: Every non-empty subset of ℝ with an upper bound has a least upper bound in ℝ -pub trait RealField: Field + PartialOrd {} +pub use operator::*; -impl RealField for T where T: Field + PartialOrd {} +pub use magma::*; +// Concrete implementations for tests #[cfg(test)] -mod tests { - use super::*; - use std::borrow::Cow; - use std::ops::Add; - use std::ops::AddAssign; - - #[derive(Debug, Clone, PartialEq)] - struct StringMagma<'a>(Cow<'a, str>); - - impl<'a> Set for StringMagma<'a> { - fn contains(&self, _: &Self) -> bool { - true // All strings are valid in our magma - } - } - - impl<'a> Add for StringMagma<'a> { - type Output = Self; - - fn add(self, other: Self) -> Self { - StringMagma(Cow::Owned(self.0.to_string() + &other.0)) - } - } - - impl<'a> AddAssign for StringMagma<'a> { - fn add_assign(&mut self, other: Self) { - self.0 = Cow::Owned(self.0.to_string() + &other.0); - } - } - - impl<'a> AdditiveMagma for StringMagma<'a> {} - - #[test] - fn test_magma_closure() { - let a = StringMagma(Cow::Borrowed("Hello")); - let b = StringMagma(Cow::Borrowed(" World")); - let _ = a + b; // This should compile and run without issues - } - - #[test] - fn test_magma_operation() { - let a = StringMagma(Cow::Borrowed("Hello")); - let b = StringMagma(Cow::Borrowed(" World")); - assert_eq!(a + b, StringMagma(Cow::Borrowed("Hello World"))); - } - - #[test] - fn test_magma_associativity_not_required() { - let a = StringMagma(Cow::Borrowed("A")); - let b = StringMagma(Cow::Borrowed("B")); - let c = StringMagma(Cow::Borrowed("C")); - - // String concatenation is associative, but magmas don't require this property - assert_eq!( - (a.clone() + b.clone()) + c.clone(), - a.clone() + (b.clone() + c.clone()) - ); - } - - #[test] - fn test_magma_commutativity_not_required() { - let a = StringMagma(Cow::Borrowed("Hello")); - let b = StringMagma(Cow::Borrowed(" World")); - - assert_ne!(a.clone() + b.clone(), b + a); - } - - #[test] - fn test_magma_add_assign() { - let mut a = StringMagma(Cow::Borrowed("Hello")); - let b = StringMagma(Cow::Borrowed(" World")); - a += b; - assert_eq!(a, StringMagma(Cow::Borrowed("Hello World"))); - } - - #[test] - fn test_magma_with_empty_string() { - let a = StringMagma(Cow::Borrowed("Hello")); - let e = StringMagma(Cow::Borrowed("")); - - // Empty string acts like an identity, but magmas don't require an identity - assert_eq!(a.clone() + e.clone(), a.clone()); - assert_eq!(e + a.clone(), a); - } -} +pub(crate) mod concrete; diff --git a/src/magma.rs b/src/magma.rs new file mode 100644 index 0000000..c292f55 --- /dev/null +++ b/src/magma.rs @@ -0,0 +1,171 @@ +use crate::{ClosedAdd, ClosedMul, Set}; + +/// Represents an Additive Magma, an algebraic structure with a set and a closed addition operation. +/// +/// An additive magma (M, +) consists of: +/// - A set M (represented by the Set trait) +/// - A binary addition operation +: M Γ— M β†’ M (represented by the ClosedAdd trait) +/// +/// Formal Definition: +/// Let (M, +) be an additive magma. Then: +/// βˆ€ a, b ∈ M, a + b ∈ M (closure property) +/// +/// Properties: +/// - Closure: For all a and b in M, the result of a + b is also in M. +/// +/// Note: An additive magma does not necessarily satisfy commutativity, associativity, or have an identity element. +pub trait AdditiveMagma: Set + ClosedAdd {} + +/// Represents a Multiplicative Magma, an algebraic structure with a set and a closed multiplication operation. +/// +/// A multiplicative magma (M, *) consists of: +/// - A set M (represented by the Set trait) +/// - A binary multiplication operation *: M Γ— M β†’ M (represented by the ClosedMul trait) +/// +/// Formal Definition: +/// Let (M, Γ—) be a multiplicative magma. Then: +/// βˆ€ a, b ∈ M, a Γ— b ∈ M (closure property) +/// +/// Properties: +/// - Closure: For all a and b in M, the result of a * b is also in M. +/// +/// Note: A multiplicative magma does not necessarily satisfy commutativity, associativity, or have an identity element. +pub trait MultiplicativeMagma: Set + ClosedMul {} + +#[cfg(test)] +mod tests { + use super::*; + use std::ops::{Add, Mul}; + + #[derive(Clone, PartialEq, Debug)] + struct StringMagma(String); + + impl Set for StringMagma { + fn is_empty(&self) -> bool { + self.0.is_empty() + } + + fn contains(&self, element: &String) -> bool { + self.0 == *element + } + + fn empty() -> Self { + StringMagma(String::new()) + } + + fn singleton(element: String) -> Self { + StringMagma(element) + } + + fn union(&self, other: &Self) -> Self { + StringMagma(self.0.clone() + &other.0) + } + + fn intersection(&self, other: &Self) -> Self { + if self == other { + self.clone() + } else { + Self::empty() + } + } + + fn difference(&self, other: &Self) -> Self { + if self == other { + Self::empty() + } else { + self.clone() + } + } + + fn symmetric_difference(&self, other: &Self) -> Self { + if self == other { + Self::empty() + } else { + self.union(other) + } + } + + fn is_subset(&self, other: &Self) -> bool { + self == other + } + + fn is_equal(&self, other: &Self) -> bool { + self == other + } + + fn cardinality(&self) -> Option { + Some(if self.is_empty() { 0 } else { 1 }) + } + + fn is_finite(&self) -> bool { + true + } + } + + impl Add for StringMagma { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + StringMagma(self.0 + &rhs.0) + } + } + + impl Mul for StringMagma { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + StringMagma(self.0.repeat(rhs.0.len().max(1))) + } + } + + impl AdditiveMagma for StringMagma {} + impl MultiplicativeMagma for StringMagma {} + + #[test] + fn test_additive_magma() { + let a = StringMagma("Hello".to_string()); + let b = StringMagma("World".to_string()); + + // Test closure property + let c = a.clone() + b.clone(); + assert_eq!(c, StringMagma("HelloWorld".to_string())); + assert!(c.contains(&"HelloWorld".to_string())); + + // Test non-commutativity + let d = b.clone() + a.clone(); + assert_eq!(d, StringMagma("WorldHello".to_string())); + assert_ne!(c, d); + + // Test non-associativity + let e = StringMagma("!".to_string()); + let f = (a.clone() + b.clone()) + e.clone(); + let g = a.clone() + (b.clone() + e.clone()); + assert_eq!(f, StringMagma("HelloWorld!".to_string())); + assert_eq!(g, StringMagma("HelloWorld!".to_string())); + assert_eq!(f, g); // In this case, it happens to be associative, but it's not guaranteed for all string concatenations + } + + #[test] + fn test_multiplicative_magma() { + let a = StringMagma("Hello".to_string()); + let b = StringMagma("Wor".to_string()); + let e = StringMagma("!".to_string()); + + // Test closure property + let c = a.clone() * b.clone(); + assert_eq!(c, StringMagma("HelloHelloHello".to_string())); + assert!(c.contains(&"HelloHelloHello".to_string())); + + // Test non-commutativity + let d = b.clone() * a.clone(); + assert_eq!(d, StringMagma("WorWorWorWorWor".to_string())); + assert_ne!(c, d); + + // Test non-associativity + let f = (a.clone() * b.clone()) * e.clone(); + let g = a.clone() * (b.clone() * e); + assert_eq!(f, StringMagma("HelloHelloHello".to_string())); + assert_eq!(g, StringMagma("HelloHelloHello".to_string())); + assert_eq!(f, g); // In this case, it happens to be associative, but it's not guaranteed for all string multiplications + } +} diff --git a/src/operator.rs b/src/operator.rs index 36a8313..cda08a6 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -102,9 +102,6 @@ pub trait Invertible {} /// Marker trait for operations with the cancellation property pub trait Cancellative: BinaryOp {} -/// Marker trait for operations with the divisibility property -pub trait Divisible {} - /// Marker trait for regular operations pub trait Regular: BinaryOp {} diff --git a/src/set.rs b/src/set.rs new file mode 100644 index 0000000..7d47779 --- /dev/null +++ b/src/set.rs @@ -0,0 +1,150 @@ +use std::fmt::Debug; + +/// Represents a mathematical set as defined in Zermelo-Fraenkel set theory with Choice (ZFC). +/// +/// # Formal Notation +/// - βˆ…: empty set +/// - ∈: element of +/// - βŠ†: subset of +/// - βˆͺ: union +/// - ∩: intersection +/// - \: set difference +/// - Ξ”: symmetric difference +/// - |A|: cardinality of set A +/// +/// # Axioms of ZFC +/// 1. Extensionality: βˆ€Aβˆ€B(βˆ€x(x ∈ A ↔ x ∈ B) β†’ A = B) +/// 2. Empty Set: βˆƒAβˆ€x(x βˆ‰ A) +/// 3. Pairing: βˆ€aβˆ€bβˆƒAβˆ€x(x ∈ A ↔ x = a ∨ x = b) +/// 4. Union: βˆ€FβˆƒAβˆ€x(x ∈ A ↔ βˆƒB(x ∈ B ∧ B ∈ F)) +/// 5. Power Set: βˆ€AβˆƒPβˆ€x(x ∈ P ↔ x βŠ† A) +/// 6. Infinity: βˆƒA(βˆ… ∈ A ∧ βˆ€x(x ∈ A β†’ x βˆͺ {x} ∈ A)) +/// 7. Separation: βˆ€AβˆƒBβˆ€x(x ∈ B ↔ x ∈ A ∧ Ο†(x)) for any formula Ο† +/// 8. Replacement: βˆ€A(βˆ€xβˆ€yβˆ€z((x ∈ A ∧ Ο†(x,y) ∧ Ο†(x,z)) β†’ y = z) β†’ βˆƒBβˆ€y(y ∈ B ↔ βˆƒx(x ∈ A ∧ Ο†(x,y)))) +/// 9. Foundation: βˆ€A(A β‰  βˆ… β†’ βˆƒx(x ∈ A ∧ x ∩ A = βˆ…)) +/// 10. Choice: βˆ€A(βˆ… βˆ‰ A β†’ βˆƒf:A β†’ βˆͺA βˆ€B∈A(f(B) ∈ B)) +pub trait Set: Sized + Clone + PartialEq + Debug { + /// Returns true if the set is empty (βˆ…). + /// βˆ€x(x βˆ‰ self) + fn is_empty(&self) -> bool; + + /// Checks if the given element is a member of the set. + /// element ∈ self + fn contains(&self, element: &T) -> bool; + + /// Creates an empty set (βˆ…). + /// βˆƒAβˆ€x(x βˆ‰ A) + fn empty() -> Self; + + /// Creates a singleton set containing the given element. + /// βˆƒAβˆ€x(x ∈ A ↔ x = element) + fn singleton(element: T) -> Self; + + /// Returns the union of this set with another set. + /// βˆ€x(x ∈ result ↔ x ∈ self ∨ x ∈ other) + fn union(&self, other: &Self) -> Self; + + /// Returns the intersection of this set with another set. + /// βˆ€x(x ∈ result ↔ x ∈ self ∧ x ∈ other) + fn intersection(&self, other: &Self) -> Self; + + /// Returns the difference of this set and another set (self - other). + /// βˆ€x(x ∈ result ↔ x ∈ self ∧ x βˆ‰ other) + fn difference(&self, other: &Self) -> Self; + + /// Returns the symmetric difference of this set and another set. + /// βˆ€x(x ∈ result ↔ (x ∈ self ∧ x βˆ‰ other) ∨ (x βˆ‰ self ∧ x ∈ other)) + fn symmetric_difference(&self, other: &Self) -> Self; + + /// Checks if this set is a subset of another set. + /// self βŠ† other ↔ βˆ€x(x ∈ self β†’ x ∈ other) + fn is_subset(&self, other: &Self) -> bool; + + /// Checks if two sets are equal (by the Axiom of Extensionality). + /// self = other ↔ βˆ€x(x ∈ self ↔ x ∈ other) + fn is_equal(&self, other: &Self) -> bool; + + /// Returns the cardinality of the set. Returns None if the set is infinite. + /// |self| if self is finite, None otherwise + fn cardinality(&self) -> Option; + + /// Returns true if the set is finite, false otherwise. + fn is_finite(&self) -> bool; +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::concrete::{InfiniteRealSet, Z5}; + + #[test] + fn test_z5_set_operations() { + let a = Z5::new(2); + let b = Z5::new(3); + let c = Z5::new(2); + + assert!(!a.is_empty()); + assert!(a.contains(&Z5::new(2))); + assert!(!a.contains(&Z5::new(3))); + + assert_eq!(Z5::empty(), Z5::new(0)); + assert_eq!(Z5::singleton(Z5::new(2)), a); + + assert_eq!(a.union(&b), Z5::new(2)); + assert_eq!(a.intersection(&b), Z5::new(0)); + assert_eq!(a.intersection(&c), a); + + assert_eq!(a.difference(&b), a); + assert_eq!(a.difference(&c), Z5::new(0)); + + assert_eq!(a.symmetric_difference(&b), Z5::new(3)); + assert_eq!(a.symmetric_difference(&c), Z5::new(0)); + + assert!(a.is_subset(&a)); + assert!(!a.is_subset(&b)); + + assert!(a.is_equal(&c)); + assert!(!a.is_equal(&b)); + + assert_eq!(a.cardinality(), Some(1)); + assert!(a.is_finite()); + } + + #[test] + fn test_infinite_real_set_operations() { + let a = InfiniteRealSet; + let b = InfiniteRealSet; + + assert!(!a.is_empty()); + assert!(a.contains(&3.14)); + assert!(a.contains(&-1000.0)); + + assert_eq!(InfiniteRealSet::empty(), InfiniteRealSet); + assert_eq!(InfiniteRealSet::singleton(3.14), InfiniteRealSet); + + assert_eq!(a.union(&b), InfiniteRealSet); + assert_eq!(a.intersection(&b), InfiniteRealSet); + assert_eq!(a.difference(&b), InfiniteRealSet); + assert_eq!(a.symmetric_difference(&b), InfiniteRealSet); + + assert!(a.is_subset(&b)); + assert!(a.is_equal(&b)); + + assert_eq!(a.cardinality(), None); + assert!(!a.is_finite()); + } + + #[test] + fn test_z5_edge_cases() { + let zero = Z5::new(0); + let five = Z5::new(5); + + assert_eq!(zero, five); + assert_eq!(Z5::new(7), Z5::new(2)); + + assert_eq!(zero.union(&five), zero); + assert_eq!(zero.intersection(&five), zero); + assert_eq!(zero.difference(&five), zero); + assert_eq!(zero.symmetric_difference(&five), zero); + } +} From d34906c2a876b664c38942d61551ae8373946273 Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Fri, 12 Jul 2024 23:24:39 -0400 Subject: [PATCH 07/21] fix: remove unneeded generics --- src/concrete.rs | 37 +++++---------- src/magma.rs | 116 ++++++++++++++++++------------------------------ src/set.rs | 10 +++-- 3 files changed, 59 insertions(+), 104 deletions(-) diff --git a/src/concrete.rs b/src/concrete.rs index 01d6de1..865f7bd 100644 --- a/src/concrete.rs +++ b/src/concrete.rs @@ -1,7 +1,4 @@ -// concrete.rs - use crate::set::Set; -use std::ops::{Add, Mul}; #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct Z5(u8); @@ -12,36 +9,22 @@ impl Z5 { } } -impl Add for Z5 { - type Output = Self; - - fn add(self, rhs: Self) -> Self::Output { - Z5::new(self.0 + rhs.0) - } -} - -impl Mul for Z5 { - type Output = Self; +impl Set for Z5 { + type Element = Z5; - fn mul(self, rhs: Self) -> Self::Output { - Z5::new(self.0 * rhs.0) - } -} - -impl Set for Z5 { fn is_empty(&self) -> bool { false } - fn contains(&self, element: &Z5) -> bool { - *self == *element + fn contains(&self, element: &Self::Element) -> bool { + self == element } fn empty() -> Self { Z5(0) } - fn singleton(element: Z5) -> Self { + fn singleton(element: Self::Element) -> Self { element } @@ -86,7 +69,7 @@ impl Set for Z5 { } fn cardinality(&self) -> Option { - Some(1) + Some(5) } fn is_finite(&self) -> bool { @@ -97,12 +80,14 @@ impl Set for Z5 { #[derive(Clone, PartialEq, Debug)] pub struct InfiniteRealSet; -impl Set for InfiniteRealSet { +impl Set for InfiniteRealSet { + type Element = f64; + fn is_empty(&self) -> bool { false } - fn contains(&self, _element: &f64) -> bool { + fn contains(&self, _element: &Self::Element) -> bool { true } @@ -110,7 +95,7 @@ impl Set for InfiniteRealSet { InfiniteRealSet } - fn singleton(_element: f64) -> Self { + fn singleton(_element: Self::Element) -> Self { InfiniteRealSet } diff --git a/src/magma.rs b/src/magma.rs index c292f55..45f6b3d 100644 --- a/src/magma.rs +++ b/src/magma.rs @@ -4,7 +4,7 @@ use crate::{ClosedAdd, ClosedMul, Set}; /// /// An additive magma (M, +) consists of: /// - A set M (represented by the Set trait) -/// - A binary addition operation +: M Γ— M β†’ M (represented by the ClosedAdd trait) +/// - A binary addition operation +: M Γ— M β†’ M /// /// Formal Definition: /// Let (M, +) be an additive magma. Then: @@ -14,13 +14,13 @@ use crate::{ClosedAdd, ClosedMul, Set}; /// - Closure: For all a and b in M, the result of a + b is also in M. /// /// Note: An additive magma does not necessarily satisfy commutativity, associativity, or have an identity element. -pub trait AdditiveMagma: Set + ClosedAdd {} +pub trait AdditiveMagma: Set + ClosedAdd {} /// Represents a Multiplicative Magma, an algebraic structure with a set and a closed multiplication operation. /// /// A multiplicative magma (M, *) consists of: /// - A set M (represented by the Set trait) -/// - A binary multiplication operation *: M Γ— M β†’ M (represented by the ClosedMul trait) +/// - A binary multiplication operation *: M Γ— M β†’ M /// /// Formal Definition: /// Let (M, Γ—) be a multiplicative magma. Then: @@ -30,7 +30,10 @@ pub trait AdditiveMagma: Set + ClosedAdd {} /// - Closure: For all a and b in M, the result of a * b is also in M. /// /// Note: A multiplicative magma does not necessarily satisfy commutativity, associativity, or have an identity element. -pub trait MultiplicativeMagma: Set + ClosedMul {} +pub trait MultiplicativeMagma: Set + ClosedMul {} + +impl AdditiveMagma for T where T: Set + ClosedAdd {} +impl MultiplicativeMagma for T where T: Set + ClosedMul {} #[cfg(test)] mod tests { @@ -40,21 +43,23 @@ mod tests { #[derive(Clone, PartialEq, Debug)] struct StringMagma(String); - impl Set for StringMagma { + impl Set for StringMagma { + type Element = char; + fn is_empty(&self) -> bool { self.0.is_empty() } - fn contains(&self, element: &String) -> bool { - self.0 == *element + fn contains(&self, element: &Self::Element) -> bool { + self.0.contains(*element) } fn empty() -> Self { StringMagma(String::new()) } - fn singleton(element: String) -> Self { - StringMagma(element) + fn singleton(element: Self::Element) -> Self { + StringMagma(element.to_string()) } fn union(&self, other: &Self) -> Self { @@ -62,39 +67,29 @@ mod tests { } fn intersection(&self, other: &Self) -> Self { - if self == other { - self.clone() - } else { - Self::empty() - } + StringMagma(self.0.chars().filter(|c| other.0.contains(*c)).collect()) } fn difference(&self, other: &Self) -> Self { - if self == other { - Self::empty() - } else { - self.clone() - } + StringMagma(self.0.chars().filter(|c| !other.0.contains(*c)).collect()) } fn symmetric_difference(&self, other: &Self) -> Self { - if self == other { - Self::empty() - } else { - self.union(other) - } + let union = self.union(other); + let intersection = self.intersection(other); + union.difference(&intersection) } fn is_subset(&self, other: &Self) -> bool { - self == other + self.0.chars().all(|c| other.0.contains(c)) } fn is_equal(&self, other: &Self) -> bool { - self == other + self.0 == other.0 } fn cardinality(&self) -> Option { - Some(if self.is_empty() { 0 } else { 1 }) + Some(self.0.len()) } fn is_finite(&self) -> bool { @@ -102,70 +97,43 @@ mod tests { } } - impl Add for StringMagma { + impl std::ops::Add for StringMagma { type Output = Self; - fn add(self, rhs: Self) -> Self::Output { - StringMagma(self.0 + &rhs.0) + fn add(self, other: Self) -> Self::Output { + StringMagma(self.0 + &other.0) } } - impl Mul for StringMagma { + impl std::ops::Mul for StringMagma { type Output = Self; - fn mul(self, rhs: Self) -> Self::Output { - StringMagma(self.0.repeat(rhs.0.len().max(1))) + fn mul(self, other: Self) -> Self::Output { + StringMagma(self.0.chars().chain(other.0.chars()).collect()) } } - impl AdditiveMagma for StringMagma {} - impl MultiplicativeMagma for StringMagma {} - #[test] fn test_additive_magma() { let a = StringMagma("Hello".to_string()); - let b = StringMagma("World".to_string()); - - // Test closure property - let c = a.clone() + b.clone(); - assert_eq!(c, StringMagma("HelloWorld".to_string())); - assert!(c.contains(&"HelloWorld".to_string())); - - // Test non-commutativity - let d = b.clone() + a.clone(); - assert_eq!(d, StringMagma("WorldHello".to_string())); - assert_ne!(c, d); - - // Test non-associativity - let e = StringMagma("!".to_string()); - let f = (a.clone() + b.clone()) + e.clone(); - let g = a.clone() + (b.clone() + e.clone()); - assert_eq!(f, StringMagma("HelloWorld!".to_string())); - assert_eq!(g, StringMagma("HelloWorld!".to_string())); - assert_eq!(f, g); // In this case, it happens to be associative, but it's not guaranteed for all string concatenations + let b = StringMagma(" World".to_string()); + let result = a + b; + assert_eq!(result, StringMagma("Hello World".to_string())); } #[test] fn test_multiplicative_magma() { let a = StringMagma("Hello".to_string()); - let b = StringMagma("Wor".to_string()); - let e = StringMagma("!".to_string()); - - // Test closure property - let c = a.clone() * b.clone(); - assert_eq!(c, StringMagma("HelloHelloHello".to_string())); - assert!(c.contains(&"HelloHelloHello".to_string())); - - // Test non-commutativity - let d = b.clone() * a.clone(); - assert_eq!(d, StringMagma("WorWorWorWorWor".to_string())); - assert_ne!(c, d); - - // Test non-associativity - let f = (a.clone() * b.clone()) * e.clone(); - let g = a.clone() * (b.clone() * e); - assert_eq!(f, StringMagma("HelloHelloHello".to_string())); - assert_eq!(g, StringMagma("HelloHelloHello".to_string())); - assert_eq!(f, g); // In this case, it happens to be associative, but it's not guaranteed for all string multiplications + let b = StringMagma("World".to_string()); + let result = a * b; + assert_eq!(result, StringMagma("HelloWorld".to_string())); + } + + #[test] + fn test_set_operations() { + let set = StringMagma("Hello".to_string()); + assert!(!set.is_empty()); + assert!(set.contains(&'H')); + assert!(!set.contains(&'W')); } } diff --git a/src/set.rs b/src/set.rs index 7d47779..66f4fb2 100644 --- a/src/set.rs +++ b/src/set.rs @@ -23,14 +23,16 @@ use std::fmt::Debug; /// 8. Replacement: βˆ€A(βˆ€xβˆ€yβˆ€z((x ∈ A ∧ Ο†(x,y) ∧ Ο†(x,z)) β†’ y = z) β†’ βˆƒBβˆ€y(y ∈ B ↔ βˆƒx(x ∈ A ∧ Ο†(x,y)))) /// 9. Foundation: βˆ€A(A β‰  βˆ… β†’ βˆƒx(x ∈ A ∧ x ∩ A = βˆ…)) /// 10. Choice: βˆ€A(βˆ… βˆ‰ A β†’ βˆƒf:A β†’ βˆͺA βˆ€B∈A(f(B) ∈ B)) -pub trait Set: Sized + Clone + PartialEq + Debug { +pub trait Set: Sized + Clone + PartialEq + Debug { + type Element; + /// Returns true if the set is empty (βˆ…). /// βˆ€x(x βˆ‰ self) fn is_empty(&self) -> bool; /// Checks if the given element is a member of the set. /// element ∈ self - fn contains(&self, element: &T) -> bool; + fn contains(&self, element: &Self::Element) -> bool; /// Creates an empty set (βˆ…). /// βˆƒAβˆ€x(x βˆ‰ A) @@ -38,7 +40,7 @@ pub trait Set: Sized + Clone + PartialEq + Debug { /// Creates a singleton set containing the given element. /// βˆƒAβˆ€x(x ∈ A ↔ x = element) - fn singleton(element: T) -> Self; + fn singleton(element: Self::Element) -> Self; /// Returns the union of this set with another set. /// βˆ€x(x ∈ result ↔ x ∈ self ∨ x ∈ other) @@ -106,7 +108,7 @@ mod tests { assert!(a.is_equal(&c)); assert!(!a.is_equal(&b)); - assert_eq!(a.cardinality(), Some(1)); + assert_eq!(a.cardinality(), Some(5)); assert!(a.is_finite()); } From fbf784d823e734b5e4361a3246972ebebbfc3bb5 Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Sat, 13 Jul 2024 00:31:48 -0400 Subject: [PATCH 08/21] add semigroup, monoid --- Cargo.toml | 2 +- src/abelian.rs | 1 + src/alg_loop.rs | 1 + src/concrete.rs | 2 +- src/cring.rs | 1 + src/euclidean_domain.rs | 1 + src/field.rs | 1 + src/field_extension.rs | 1 + src/finite_field.rs | 1 + src/group.rs | 1 + src/infinite_field.rs | 1 + src/integral_domain.rs | 1 + src/lib.rs | 31 +++++++- src/magma.rs | 5 +- src/monoid.rs | 165 ++++++++++++++++++++++++++++++++++++++++ src/operator.rs | 22 +++--- src/pid.rs | 1 + src/quasigroup.rs | 1 + src/ring.rs | 1 + src/semigroup.rs | 90 ++++++++++++++++++++++ src/semilattice.rs | 1 + src/semiring.rs | 1 + src/set.rs | 2 + src/uid.rs | 1 + 24 files changed, 315 insertions(+), 20 deletions(-) create mode 100644 src/abelian.rs create mode 100644 src/alg_loop.rs create mode 100644 src/cring.rs create mode 100644 src/euclidean_domain.rs create mode 100644 src/field.rs create mode 100644 src/field_extension.rs create mode 100644 src/finite_field.rs create mode 100644 src/group.rs create mode 100644 src/infinite_field.rs create mode 100644 src/integral_domain.rs create mode 100644 src/monoid.rs create mode 100644 src/pid.rs create mode 100644 src/quasigroup.rs create mode 100644 src/ring.rs create mode 100644 src/semigroup.rs create mode 100644 src/semilattice.rs create mode 100644 src/semiring.rs create mode 100644 src/uid.rs diff --git a/Cargo.toml b/Cargo.toml index 2524909..dc4048e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT" readme = "README.md" repository = "https://github.com/warlock-labs/noether" name = "noether" -version = "0.2.1" +version = "0.1.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/abelian.rs b/src/abelian.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/abelian.rs @@ -0,0 +1 @@ + diff --git a/src/alg_loop.rs b/src/alg_loop.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/alg_loop.rs @@ -0,0 +1 @@ + diff --git a/src/concrete.rs b/src/concrete.rs index 865f7bd..6900256 100644 --- a/src/concrete.rs +++ b/src/concrete.rs @@ -1,7 +1,7 @@ use crate::set::Set; #[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct Z5(u8); +pub struct Z5(pub(crate) u8); impl Z5 { pub fn new(value: u8) -> Self { diff --git a/src/cring.rs b/src/cring.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/cring.rs @@ -0,0 +1 @@ + diff --git a/src/euclidean_domain.rs b/src/euclidean_domain.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/euclidean_domain.rs @@ -0,0 +1 @@ + diff --git a/src/field.rs b/src/field.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/field.rs @@ -0,0 +1 @@ + diff --git a/src/field_extension.rs b/src/field_extension.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/field_extension.rs @@ -0,0 +1 @@ + diff --git a/src/finite_field.rs b/src/finite_field.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/finite_field.rs @@ -0,0 +1 @@ + diff --git a/src/group.rs b/src/group.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/group.rs @@ -0,0 +1 @@ + diff --git a/src/infinite_field.rs b/src/infinite_field.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/infinite_field.rs @@ -0,0 +1 @@ + diff --git a/src/integral_domain.rs b/src/integral_domain.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/integral_domain.rs @@ -0,0 +1 @@ + diff --git a/src/lib.rs b/src/lib.rs index 5c48eef..aeb2b7c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -92,16 +92,41 @@ //! β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ //! ``` +// Implemented traits mod magma; +mod monoid; mod operator; +mod semigroup; mod set; +// Not yet implemented +mod abelian; +mod alg_loop; +#[cfg(test)] +mod concrete; +mod cring; +mod euclidean_domain; +mod field; +mod field_extension; +mod finite_field; +mod group; +mod infinite_field; +mod integral_domain; +mod pid; +mod quasigroup; +mod ring; +mod semilattice; +mod semiring; +mod uid; + +// Library level re-exports + pub use set::*; pub use operator::*; pub use magma::*; -// Concrete implementations for tests -#[cfg(test)] -pub(crate) mod concrete; +pub use semigroup::*; + +pub use monoid::*; diff --git a/src/magma.rs b/src/magma.rs index 45f6b3d..36785b6 100644 --- a/src/magma.rs +++ b/src/magma.rs @@ -23,7 +23,7 @@ pub trait AdditiveMagma: Set + ClosedAdd {} /// - A binary multiplication operation *: M Γ— M β†’ M /// /// Formal Definition: -/// Let (M, Γ—) be a multiplicative magma. Then: +/// Let (M, *) be a multiplicative magma. Then: /// βˆ€ a, b ∈ M, a Γ— b ∈ M (closure property) /// /// Properties: @@ -37,8 +37,9 @@ impl MultiplicativeMagma for T where T: Set + ClosedMul {} #[cfg(test)] mod tests { + // Using a string here is an interesting way to test as the elements can form a set. + // However, we can make non-associative addition and multiplication operations. use super::*; - use std::ops::{Add, Mul}; #[derive(Clone, PartialEq, Debug)] struct StringMagma(String); diff --git a/src/monoid.rs b/src/monoid.rs new file mode 100644 index 0000000..1fa5831 --- /dev/null +++ b/src/monoid.rs @@ -0,0 +1,165 @@ +use crate::semigroup::{AdditiveSemigroup, MultiplicativeSemigroup}; +use crate::{ClosedOne, ClosedZero}; + +/// Represents an Additive Monoid, an algebraic structure with a set, an associative closed addition operation, and an identity element. +/// +/// An additive monoid (M, +, 0) consists of: +/// - A set M (represented by the Set trait) +/// - A binary addition operation +: M Γ— M β†’ M that is associative +/// - An identity element 0 ∈ M +/// +/// Formal Definition: +/// Let (M, +, 0) be an additive monoid. Then: +/// 1. βˆ€ a, b, c ∈ M, (a + b) + c = a + (b + c) (associativity) +/// 2. βˆ€ a ∈ M, a + 0 = 0 + a = a (identity) +/// +/// Properties: +/// - Closure: For all a and b in M, the result of a + b is also in M. +/// - Associativity: For all a, b, and c in M, (a + b) + c = a + (b + c). +/// - Identity: There exists an element 0 in M such that for every element a in M, a + 0 = 0 + a = a. +pub trait AdditiveMonoid: AdditiveSemigroup + ClosedZero {} + +/// Represents a Multiplicative Monoid, an algebraic structure with a set, an associative closed multiplication operation, and an identity element. +/// +/// A multiplicative monoid (M, βˆ™, 1) consists of: +/// - A set M (represented by the Set trait) +/// - A binary multiplication operation βˆ™: M Γ— M β†’ M that is associative +/// - An identity element 1 ∈ M +/// +/// Formal Definition: +/// Let (M, βˆ™, 1) be a multiplicative monoid. Then: +/// 1. βˆ€ a, b, c ∈ M, (a βˆ™ b) βˆ™ c = a βˆ™ (b βˆ™ c) (associativity) +/// 2. βˆ€ a ∈ M, a βˆ™ 1 = 1 βˆ™ a = a (identity) +/// +/// Properties: +/// - Closure: For all a and b in M, the result of a βˆ™ b is also in M. +/// - Associativity: For all a, b, and c in M, (a βˆ™ b) βˆ™ c = a βˆ™ (b βˆ™ c). +/// - Identity: There exists an element 1 in M such that for every element a in M, a βˆ™ 1 = 1 βˆ™ a = a. +pub trait MultiplicativeMonoid: MultiplicativeSemigroup + ClosedOne {} + +impl AdditiveMonoid for T where T: AdditiveSemigroup + ClosedZero {} + +impl MultiplicativeMonoid for T where T: MultiplicativeSemigroup + ClosedOne {} + +#[cfg(test)] +mod tests { + use std::ops::{Add, Mul}; + + use crate::concrete::Z5; + use crate::{AdditiveMonoid, Associative, MultiplicativeMonoid}; + use num_traits::{One, Zero}; + + // Implement necessary traits for Z5 + impl Add for Z5 { + type Output = Self; + fn add(self, other: Self) -> Self { + Z5::new(self.0 + other.0) + } + } + + impl Mul for Z5 { + type Output = Self; + fn mul(self, other: Self) -> Self { + Z5::new(self.0 * other.0) + } + } + + impl Zero for Z5 { + fn zero() -> Self { + Z5::new(0) + } + + fn is_zero(&self) -> bool { + self.0 == 0 + } + } + + impl One for Z5 { + fn one() -> Self { + Z5::new(1) + } + } + + impl Associative for Z5 {} + + #[test] + fn test_z5_additive_monoid() { + // Test associativity + let a = Z5::new(2); + let b = Z5::new(3); + let c = Z5::new(4); + assert_eq!((a + b) + c, a + (b + c)); + + // Test identity + let zero = Z5::zero(); + assert_eq!(a + zero, a); + assert_eq!(zero + a, a); + + // Test closure + let sum = a + b; + assert!(matches!(sum, Z5(_))); + } + + #[test] + fn test_z5_multiplicative_monoid() { + // Test associativity + let a = Z5::new(2); + let b = Z5::new(3); + let c = Z5::new(4); + assert_eq!((a * b) * c, a * (b * c)); + + // Test identity + let one = Z5::one(); + assert_eq!(a * one, a); + assert_eq!(one * a, a); + + // Test closure + let product = a * b; + assert!(matches!(product, Z5(_))); + } + + #[test] + fn test_z5_additive_monoid_properties() { + for i in 0..5 { + for j in 0..5 { + let a = Z5::new(i); + let b = Z5::new(j); + let zero = Z5::zero(); + + // Closure + assert!(matches!(a + b, Z5(_))); + + // Identity + assert_eq!(a + zero, a); + assert_eq!(zero + a, a); + } + } + } + + #[test] + fn test_z5_multiplicative_monoid_properties() { + for i in 0..5 { + for j in 0..5 { + let a = Z5::new(i); + let b = Z5::new(j); + let one = Z5::one(); + + // Closure + assert!(matches!(a * b, Z5(_))); + + // Identity + assert_eq!(a * one, a); + assert_eq!(one * a, a); + } + } + } + + #[test] + fn test_z5_implements_monoids() { + fn assert_additive_monoid() {} + fn assert_multiplicative_monoid() {} + + assert_additive_monoid::(); + assert_multiplicative_monoid::(); + } +} diff --git a/src/operator.rs b/src/operator.rs index cda08a6..081cb64 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -81,41 +81,37 @@ use std::ops::{ ShrAssign, }; -/// A generic trait for binary operations -pub trait BinaryOp: Sized { - type Output; - fn apply(&self, lhs: &Self, rhs: &Rhs) -> Self::Output; -} +// TODO(These marker traits could actually mean something and check things) /// Marker trait for commutative operations -pub trait Commutative: BinaryOp {} +pub trait Commutative {} /// Marker trait for associative operations -pub trait Associative: BinaryOp {} +pub trait Associative {} /// Marker trait for idempotent operations -pub trait Idempotent: BinaryOp {} +pub trait Idempotent {} /// Marker trait for operations with inverses for all elements pub trait Invertible {} /// Marker trait for operations with the cancellation property -pub trait Cancellative: BinaryOp {} +pub trait Cancellative {} /// Marker trait for regular operations -pub trait Regular: BinaryOp {} +pub trait Regular {} /// Marker trait for alternative operations -pub trait Alternative: BinaryOp {} +pub trait Alternative {} /// Marker trait for distributive operations -pub trait Distributive {} +pub trait Distributive {} /// Marker trait for operations with the absorption property pub trait Absorptive {} /// Marker trait for monotonic operations -pub trait Monotonic {} +pub trait Monotonic {} /// Marker trait for modular operations pub trait Modular {} diff --git a/src/pid.rs b/src/pid.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/pid.rs @@ -0,0 +1 @@ + diff --git a/src/quasigroup.rs b/src/quasigroup.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/quasigroup.rs @@ -0,0 +1 @@ + diff --git a/src/ring.rs b/src/ring.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/ring.rs @@ -0,0 +1 @@ + diff --git a/src/semigroup.rs b/src/semigroup.rs new file mode 100644 index 0000000..64de908 --- /dev/null +++ b/src/semigroup.rs @@ -0,0 +1,90 @@ +use crate::magma::{AdditiveMagma, MultiplicativeMagma}; +use crate::operator::{ClosedAdd, ClosedMul}; +use crate::Associative; + +/// If this trait is implemented, the object implements Additive Semigroup, an +/// algebraic structure with a set and an associative closed addition operation. +/// +/// An additive semigroup (S, +) consists of: +/// - A set S +/// - A binary operation +: S Γ— S β†’ S that is associative +/// +/// Formal Definition: +/// Let (S, +) be an additive semigroup. Then: +/// βˆ€ a, b, c ∈ S, (a + b) + c = a + (b + c) (associativity) +/// +/// Properties: +/// - Closure: βˆ€ a, b ∈ S, a + b ∈ S +/// - Associativity: βˆ€ a, b, c ∈ S, (a + b) + c = a + (b + c) +pub trait AdditiveSemigroup: AdditiveMagma + ClosedAdd + Associative {} + +/// If this trait is implemented, the object implements a Multiplicative Semigroup, an algebraic +/// structure with a set and an associative closed multiplication operation. +/// +/// A multiplicative semigroup (S, *) consists of: +/// - A set S +/// - A binary operation βˆ™: S Γ— S β†’ S that is associative +/// +/// Formal Definition: +/// Let (S, *) be a multiplicative semigroup. Then: +/// βˆ€ a, b, c ∈ S, (a * b) * c = a * (b * c) (associativity) +/// +/// Properties: +/// - Closure: βˆ€ a, b ∈ S, a * b ∈ S +/// - Associativity: βˆ€ a, b, c ∈ S, (a * b) βˆ™ c = a * (b * c) +pub trait MultiplicativeSemigroup: MultiplicativeMagma + ClosedMul + Associative {} + +// Blanket implementations +impl AdditiveSemigroup for T where T: AdditiveMagma + ClosedAdd + Associative {} +impl MultiplicativeSemigroup for T where T: MultiplicativeMagma + ClosedMul + Associative {} + +#[cfg(test)] +mod tests { + use super::*; + use std::ops::{Add, Mul}; + + // Test structures + #[derive(Clone, PartialEq, Debug)] + struct IntegerAdditiveSemigroup(i32); + + #[derive(Clone, PartialEq, Debug)] + struct StringMultiplicativeSemigroup(String); + + impl Associative for IntegerAdditiveSemigroup {} + + // Implement the necessary traits for IntegerAdditiveSemigroup + impl Add for IntegerAdditiveSemigroup { + type Output = Self; + fn add(self, other: Self) -> Self { + IntegerAdditiveSemigroup(self.0 + other.0) + } + } + + // Implement necessary traits for StringMultiplicativeSemigroup + impl Mul for StringMultiplicativeSemigroup { + type Output = Self; + fn mul(self, other: Self) -> Self { + StringMultiplicativeSemigroup(self.0 + &other.0) + } + } + + #[test] + fn test_additive_semigroup() { + let a = IntegerAdditiveSemigroup(2); + let b = IntegerAdditiveSemigroup(3); + let c = IntegerAdditiveSemigroup(4); + + // Test associativity + assert_eq!((a.clone() + b.clone()) + c.clone(), a + (b + c)); + } + + #[test] + fn test_multiplicative_semigroup() { + let a = StringMultiplicativeSemigroup("a".to_string()); + let b = StringMultiplicativeSemigroup("b".to_string()); + let c = StringMultiplicativeSemigroup("c".to_string()); + + // Test associativity + assert_eq!((a.clone() * b.clone()) * c.clone(), a * (b * c)); + } +} diff --git a/src/semilattice.rs b/src/semilattice.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/semilattice.rs @@ -0,0 +1 @@ + diff --git a/src/semiring.rs b/src/semiring.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/semiring.rs @@ -0,0 +1 @@ + diff --git a/src/set.rs b/src/set.rs index 66f4fb2..93e4ae3 100644 --- a/src/set.rs +++ b/src/set.rs @@ -23,6 +23,8 @@ use std::fmt::Debug; /// 8. Replacement: βˆ€A(βˆ€xβˆ€yβˆ€z((x ∈ A ∧ Ο†(x,y) ∧ Ο†(x,z)) β†’ y = z) β†’ βˆƒBβˆ€y(y ∈ B ↔ βˆƒx(x ∈ A ∧ Ο†(x,y)))) /// 9. Foundation: βˆ€A(A β‰  βˆ… β†’ βˆƒx(x ∈ A ∧ x ∩ A = βˆ…)) /// 10. Choice: βˆ€A(βˆ… βˆ‰ A β†’ βˆƒf:A β†’ βˆͺA βˆ€B∈A(f(B) ∈ B)) +/// +/// TODO(There is significant reasoning to do here about what might be covered by std traits, partial equivalence relations, etc.) pub trait Set: Sized + Clone + PartialEq + Debug { type Element; diff --git a/src/uid.rs b/src/uid.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/uid.rs @@ -0,0 +1 @@ + From f3c07a9a7ca5ac853d0adbac405e042e2e3688ee Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Sat, 13 Jul 2024 01:23:51 -0400 Subject: [PATCH 09/21] feat: structure up to ring --- src/abelian.rs | 126 +++++++++++++++++++++++++++++++++++++++++++++++ src/concrete.rs | 63 ++++++++++++++++++++++++ src/group.rs | 114 ++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 6 ++- src/magma.rs | 10 ++-- src/monoid.rs | 36 +------------- src/ring.rs | 104 ++++++++++++++++++++++++++++++++++++++ src/semigroup.rs | 10 ++-- src/semiring.rs | 112 +++++++++++++++++++++++++++++++++++++++++ 9 files changed, 535 insertions(+), 46 deletions(-) diff --git a/src/abelian.rs b/src/abelian.rs index 8b13789..712e064 100644 --- a/src/abelian.rs +++ b/src/abelian.rs @@ -1 +1,127 @@ +use crate::group::{AdditiveGroup, MultiplicativeGroup}; +use crate::Commutative; +/// Represents an Additive Abelian Group, an algebraic structure with a commutative addition operation. +/// +/// An additive abelian group (G, +) is an additive group that also satisfies: +/// - Commutativity: βˆ€ a, b ∈ G, a + b = b + a +/// +/// Formal Definition: +/// Let (G, +) be an additive abelian group. Then: +/// 1. βˆ€ a, b, c ∈ G, (a + b) + c = a + (b + c) (associativity) +/// 2. βˆƒ 0 ∈ G, βˆ€ a ∈ G, 0 + a = a + 0 = a (identity) +/// 3. βˆ€ a ∈ G, βˆƒ -a ∈ G, a + (-a) = (-a) + a = 0 (inverse) +/// 4. βˆ€ a, b ∈ G, a + b = b + a (commutativity) +pub trait AdditiveAbelianGroup: AdditiveGroup + Commutative {} + +/// Represents a Multiplicative Abelian Group, an algebraic structure with a commutative multiplication operation. +/// +/// A multiplicative abelian group (G, βˆ™) is a multiplicative group that also satisfies: +/// - Commutativity: βˆ€ a, b ∈ G, a βˆ™ b = b βˆ™ a +/// +/// Formal Definition: +/// Let (G, βˆ™) be a multiplicative abelian group. Then: +/// 1. βˆ€ a, b, c ∈ G, (a βˆ™ b) βˆ™ c = a βˆ™ (b βˆ™ c) (associativity) +/// 2. βˆƒ 1 ∈ G, βˆ€ a ∈ G, 1 βˆ™ a = a βˆ™ 1 = a (identity) +/// 3. βˆ€ a ∈ G, βˆƒ a⁻¹ ∈ G, a βˆ™ a⁻¹ = a⁻¹ βˆ™ a = 1 (inverse) +/// 4. βˆ€ a, b ∈ G, a βˆ™ b = b βˆ™ a (commutativity) +pub trait MultiplicativeAbelianGroup: MultiplicativeGroup + Commutative {} + +impl AdditiveAbelianGroup for T where T: AdditiveGroup + Commutative {} +impl MultiplicativeAbelianGroup for T where T: MultiplicativeGroup + Commutative {} + +#[cfg(test)] +mod tests { + use super::*; + use crate::concrete::Z5; + use num_traits::{Zero, One, Inv}; + + #[test] + fn test_z5_additive_abelian_group() { + // Test commutativity + for i in 0..5 { + for j in 0..5 { + let a = Z5::new(i); + let b = Z5::new(j); + assert_eq!(a + b, b + a); + } + } + + // Test associativity (inherited from AdditiveGroup) + for i in 0..5 { + for j in 0..5 { + for k in 0..5 { + let a = Z5::new(i); + let b = Z5::new(j); + let c = Z5::new(k); + assert_eq!((a + b) + c, a + (b + c)); + } + } + } + + // Test identity (inherited from AdditiveGroup) + let zero = Z5::zero(); + for i in 0..5 { + let a = Z5::new(i); + assert_eq!(a + zero, a); + assert_eq!(zero + a, a); + } + + // Test inverse (inherited from AdditiveGroup) + for i in 0..5 { + let a = Z5::new(i); + let neg_a = -a; + assert_eq!(a + neg_a, zero); + assert_eq!(neg_a + a, zero); + } + } + + #[test] + fn test_z5_multiplicative_abelian_group() { + // Test commutativity + for i in 1..5 { // Skip 0 as it's not part of the multiplicative group + for j in 1..5 { + let a = Z5::new(i); + let b = Z5::new(j); + assert_eq!(a * b, b * a); + } + } + + // Test associativity (inherited from MultiplicativeGroup) + for i in 1..5 { + for j in 1..5 { + for k in 1..5 { + let a = Z5::new(i); + let b = Z5::new(j); + let c = Z5::new(k); + assert_eq!((a * b) * c, a * (b * c)); + } + } + } + + // Test identity (inherited from MultiplicativeGroup) + let one = Z5::one(); + for i in 1..5 { + let a = Z5::new(i); + assert_eq!(a * one, a); + assert_eq!(one * a, a); + } + + // Test inverse (inherited from MultiplicativeGroup) + for i in 1..5 { + let a = Z5::new(i); + let inv_a = a.inv(); + assert_eq!(a * inv_a, one); + assert_eq!(inv_a * a, one); + } + } + + #[test] + fn test_z5_implements_abelian_groups() { + fn assert_additive_abelian_group() {} + fn assert_multiplicative_abelian_group() {} + + assert_additive_abelian_group::(); + assert_multiplicative_abelian_group::(); + } +} diff --git a/src/concrete.rs b/src/concrete.rs index 6900256..6b60766 100644 --- a/src/concrete.rs +++ b/src/concrete.rs @@ -1,3 +1,6 @@ +use std::ops::{Add, Mul, Neg}; +use num_traits::{Inv, One, Zero}; +use crate::{Associative, Commutative, Distributive}; use crate::set::Set; #[derive(Clone, Copy, PartialEq, Eq, Debug)] @@ -77,6 +80,66 @@ impl Set for Z5 { } } +// Implement necessary traits for Z5 +impl Add for Z5 { + type Output = Self; + fn add(self, other: Self) -> Self { + Z5::new(self.0 + other.0) + } +} + +impl Mul for Z5 { + type Output = Self; + fn mul(self, other: Self) -> Self { + Z5::new(self.0 * other.0) + } +} + +impl Zero for Z5 { + fn zero() -> Self { + Z5::new(0) + } + + fn is_zero(&self) -> bool { + self.0 == 0 + } +} + +impl One for Z5 { + fn one() -> Self { + Z5::new(1) + } +} + +impl Neg for Z5 { + type Output = Self; + + fn neg(self) -> Self { + Z5::new(5 - self.0) + } +} + +impl Inv for Z5 { + type Output = Self; + + fn inv(self) -> Self { + match self.0 { + 1 => Z5::new(1), + 2 => Z5::new(3), + 3 => Z5::new(2), + 4 => Z5::new(4), + 0 => panic!("Cannot invert zero in Z5"), + _ => unreachable!(), + } + } +} + +impl Associative for Z5 {} + +impl Commutative for Z5 {} + +impl Distributive for Z5 {} + #[derive(Clone, PartialEq, Debug)] pub struct InfiniteRealSet; diff --git a/src/group.rs b/src/group.rs index 8b13789..94925d7 100644 --- a/src/group.rs +++ b/src/group.rs @@ -1 +1,115 @@ +use crate::{ClosedInv, ClosedNeg}; +use crate::monoid::{AdditiveMonoid, MultiplicativeMonoid}; +/// Represents an Additive Group, an algebraic structure with a set, an associative closed addition operation, +/// an identity element, and inverses for all elements. +/// +/// An additive group (G, +) consists of: +/// - A set G +/// - A binary operation +: G Γ— G β†’ G that is associative +/// - An identity element 0 ∈ G +/// - For each a ∈ G, an inverse element -a ∈ G such that a + (-a) = (-a) + a = 0 +/// +/// Formal Definition: +/// Let (G, +) be an additive group. Then: +/// 1. βˆ€ a, b, c ∈ G, (a + b) + c = a + (b + c) (associativity) +/// 2. βˆƒ 0 ∈ G, βˆ€ a ∈ G, 0 + a = a + 0 = a (identity) +/// 3. βˆ€ a ∈ G, βˆƒ -a ∈ G, a + (-a) = (-a) + a = 0 (inverse) +pub trait AdditiveGroup: AdditiveMonoid + ClosedNeg {} + +/// Represents a Multiplicative Group, an algebraic structure with a set, an associative closed multiplication operation, +/// an identity element, and inverses for all elements. +/// +/// A multiplicative group (G, βˆ™) consists of: +/// - A set G +/// - A binary operation βˆ™: G Γ— G β†’ G that is associative +/// - An identity element 1 ∈ G +/// - For each a ∈ G, an inverse element a⁻¹ ∈ G such that a βˆ™ a⁻¹ = a⁻¹ βˆ™ a = 1 +/// +/// Formal Definition: +/// Let (G, βˆ™) be a multiplicative group. Then: +/// 1. βˆ€ a, b, c ∈ G, (a βˆ™ b) βˆ™ c = a βˆ™ (b βˆ™ c) (associativity) +/// 2. βˆƒ 1 ∈ G, βˆ€ a ∈ G, 1 βˆ™ a = a βˆ™ 1 = a (identity) +/// 3. βˆ€ a ∈ G, βˆƒ a⁻¹ ∈ G, a βˆ™ a⁻¹ = a⁻¹ βˆ™ a = 1 (inverse) +pub trait MultiplicativeGroup: MultiplicativeMonoid + ClosedInv {} + +impl AdditiveGroup for T where T: AdditiveMonoid + ClosedNeg {} +impl MultiplicativeGroup for T where T: MultiplicativeMonoid + ClosedInv {} + +#[cfg(test)] +mod tests { + use crate::concrete::Z5; + use num_traits::{Zero, One, Inv}; + use crate::group::{AdditiveGroup, MultiplicativeGroup}; + + #[test] + fn test_z5_additive_group() { + // Test associativity + for i in 0..5 { + for j in 0..5 { + for k in 0..5 { + let a = Z5::new(i); + let b = Z5::new(j); + let c = Z5::new(k); + assert_eq!((a + b) + c, a + (b + c)); + } + } + } + + // Test identity + let zero = Z5::zero(); + for i in 0..5 { + let a = Z5::new(i); + assert_eq!(a + zero, a); + assert_eq!(zero + a, a); + } + + // Test inverse + for i in 0..5 { + let a = Z5::new(i); + let neg_a = -a; + assert_eq!(a + neg_a, zero); + assert_eq!(neg_a + a, zero); + } + } + + #[test] + fn test_z5_multiplicative_group() { + // Test associativity + for i in 1..5 { // Skip 0 as it's not part of the multiplicative group + for j in 1..5 { + for k in 1..5 { + let a = Z5::new(i); + let b = Z5::new(j); + let c = Z5::new(k); + assert_eq!((a * b) * c, a * (b * c)); + } + } + } + + // Test identity + let one = Z5::one(); + for i in 1..5 { + let a = Z5::new(i); + assert_eq!(a * one, a); + assert_eq!(one * a, a); + } + + // Test inverse + for i in 1..5 { + let a = Z5::new(i); + let inv_a = a.inv(); + assert_eq!(a * inv_a, one); + assert_eq!(inv_a * a, one); + } + } + + #[test] + fn test_z5_implements_groups() { + fn assert_additive_group() {} + fn assert_multiplicative_group() {} + + assert_additive_group::(); + assert_multiplicative_group::(); + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index aeb2b7c..dbd6dfe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,7 +11,7 @@ //! structs based on the properties they satisfy, and be applied in most cases for //! anything from scalar values to n-dimensional arrays. //! -//! ## Hierarchy of Scalar Algebraic Structures +//! ## Hierarchy of Algebraic Structures //! //! ```text //! β”Œβ”€β”€β”€β”€β”€β” @@ -130,3 +130,7 @@ pub use magma::*; pub use semigroup::*; pub use monoid::*; + +pub use group::*; + +pub use abelian::*; diff --git a/src/magma.rs b/src/magma.rs index 36785b6..3eca1d8 100644 --- a/src/magma.rs +++ b/src/magma.rs @@ -18,16 +18,16 @@ pub trait AdditiveMagma: Set + ClosedAdd {} /// Represents a Multiplicative Magma, an algebraic structure with a set and a closed multiplication operation. /// -/// A multiplicative magma (M, *) consists of: +/// A multiplicative magma (M, βˆ™) consists of: /// - A set M (represented by the Set trait) -/// - A binary multiplication operation *: M Γ— M β†’ M +/// - A binary multiplication operation βˆ™: M βˆ™ M β†’ M /// /// Formal Definition: -/// Let (M, *) be a multiplicative magma. Then: -/// βˆ€ a, b ∈ M, a Γ— b ∈ M (closure property) +/// Let (M, βˆ™) be a multiplicative magma. Then: +/// βˆ€ a, b ∈ M, a βˆ™ b ∈ M (closure property) /// /// Properties: -/// - Closure: For all a and b in M, the result of a * b is also in M. +/// - Closure: For all a and b in M, the result of a βˆ™ b is also in M. /// /// Note: A multiplicative magma does not necessarily satisfy commutativity, associativity, or have an identity element. pub trait MultiplicativeMagma: Set + ClosedMul {} diff --git a/src/monoid.rs b/src/monoid.rs index 1fa5831..7f8b51b 100644 --- a/src/monoid.rs +++ b/src/monoid.rs @@ -43,45 +43,11 @@ impl MultiplicativeMonoid for T where T: MultiplicativeSemigroup + ClosedOne #[cfg(test)] mod tests { - use std::ops::{Add, Mul}; use crate::concrete::Z5; - use crate::{AdditiveMonoid, Associative, MultiplicativeMonoid}; + use crate::{AdditiveMonoid, MultiplicativeMonoid}; use num_traits::{One, Zero}; - // Implement necessary traits for Z5 - impl Add for Z5 { - type Output = Self; - fn add(self, other: Self) -> Self { - Z5::new(self.0 + other.0) - } - } - - impl Mul for Z5 { - type Output = Self; - fn mul(self, other: Self) -> Self { - Z5::new(self.0 * other.0) - } - } - - impl Zero for Z5 { - fn zero() -> Self { - Z5::new(0) - } - - fn is_zero(&self) -> bool { - self.0 == 0 - } - } - - impl One for Z5 { - fn one() -> Self { - Z5::new(1) - } - } - - impl Associative for Z5 {} - #[test] fn test_z5_additive_monoid() { // Test associativity diff --git a/src/ring.rs b/src/ring.rs index 8b13789..aeca17d 100644 --- a/src/ring.rs +++ b/src/ring.rs @@ -1 +1,105 @@ +use crate::{AdditiveAbelianGroup, Distributive, MultiplicativeMonoid}; +/// Represents a Ring, an algebraic structure with two binary operations (addition and multiplication) +/// that satisfy certain axioms. +/// +/// A ring (R, +, Β·) consists of: +/// - A set R +/// - Two binary operations + (addition) and Β· (multiplication) on R +/// +/// Formal Definition: +/// Let (R, +, Β·) be a ring. Then: +/// 1. (R, +) is an abelian group: +/// a. βˆ€ a, b, c ∈ R, (a + b) + c = a + (b + c) (associativity) +/// b. βˆ€ a, b ∈ R, a + b = b + a (commutativity) +/// c. βˆƒ 0 ∈ R, βˆ€ a ∈ R, a + 0 = 0 + a = a (identity) +/// d. βˆ€ a ∈ R, βˆƒ -a ∈ R, a + (-a) = (-a) + a = 0 (inverse) +/// 2. (R, Β·) is a monoid: +/// a. βˆ€ a, b, c ∈ R, (a Β· b) Β· c = a Β· (b Β· c) (associativity) +/// b. βˆƒ 1 ∈ R, βˆ€ a ∈ R, 1 Β· a = a Β· 1 = a (identity) +/// 3. Multiplication is distributive over addition: +/// a. βˆ€ a, b, c ∈ R, a Β· (b + c) = (a Β· b) + (a Β· c) (left distributivity) +/// b. βˆ€ a, b, c ∈ R, (a + b) Β· c = (a Β· c) + (b Β· c) (right distributivity) +pub trait Ring: AdditiveAbelianGroup + MultiplicativeMonoid + Distributive {} + +impl Ring for T where T: AdditiveAbelianGroup + MultiplicativeMonoid + Distributive {} + + +#[cfg(test)] +mod tests { + use super::*; + use crate::concrete::Z5; + use num_traits::{Zero, One}; + + #[test] + fn test_z5_ring() { + // Test additive abelian group properties + for i in 0..5 { + for j in 0..5 { + let a = Z5::new(i); + let b = Z5::new(j); + + // Commutativity + assert_eq!(a + b, b + a); + + // Associativity + let c = Z5::new((i + j) % 5); + assert_eq!((a + b) + c, a + (b + c)); + } + } + + // Test additive identity and inverse + let zero = Z5::zero(); + for i in 0..5 { + let a = Z5::new(i); + assert_eq!(a + zero, a); + assert_eq!(zero + a, a); + let neg_a = -a; + assert_eq!(a + neg_a, zero); + assert_eq!(neg_a + a, zero); + } + + // Test multiplicative monoid properties + for i in 0..5 { + for j in 0..5 { + let a = Z5::new(i); + let b = Z5::new(j); + + // Associativity + let c = Z5::new((i * j) % 5); + assert_eq!((a * b) * c, a * (b * c)); + } + } + + // Test multiplicative identity + let one = Z5::one(); + for i in 0..5 { + let a = Z5::new(i); + assert_eq!(a * one, a); + assert_eq!(one * a, a); + } + + // Test distributivity + for i in 0..5 { + for j in 0..5 { + for k in 0..5 { + let a = Z5::new(i); + let b = Z5::new(j); + let c = Z5::new(k); + + // Left distributivity + assert_eq!(a * (b + c), (a * b) + (a * c)); + + // Right distributivity + assert_eq!((a + b) * c, (a * c) + (b * c)); + } + } + } + } + + #[test] + fn test_z5_implements_ring() { + fn assert_ring() {} + assert_ring::(); + } +} diff --git a/src/semigroup.rs b/src/semigroup.rs index 64de908..ea1c605 100644 --- a/src/semigroup.rs +++ b/src/semigroup.rs @@ -21,17 +21,17 @@ pub trait AdditiveSemigroup: AdditiveMagma + ClosedAdd + Associative {} /// If this trait is implemented, the object implements a Multiplicative Semigroup, an algebraic /// structure with a set and an associative closed multiplication operation. /// -/// A multiplicative semigroup (S, *) consists of: +/// A multiplicative semigroup (S, βˆ™) consists of: /// - A set S /// - A binary operation βˆ™: S Γ— S β†’ S that is associative /// /// Formal Definition: -/// Let (S, *) be a multiplicative semigroup. Then: -/// βˆ€ a, b, c ∈ S, (a * b) * c = a * (b * c) (associativity) +/// Let (S, βˆ™) be a multiplicative semigroup. Then: +/// βˆ€ a, b, c ∈ S, (a βˆ™ b) βˆ™ c = a βˆ™ (b βˆ™ c) (associativity) /// /// Properties: -/// - Closure: βˆ€ a, b ∈ S, a * b ∈ S -/// - Associativity: βˆ€ a, b, c ∈ S, (a * b) βˆ™ c = a * (b * c) +/// - Closure: βˆ€ a, b ∈ S, a βˆ™ b ∈ S +/// - Associativity: βˆ€ a, b, c ∈ S, (a βˆ™ b) βˆ™ c = a βˆ™ (b βˆ™ c) pub trait MultiplicativeSemigroup: MultiplicativeMagma + ClosedMul + Associative {} // Blanket implementations diff --git a/src/semiring.rs b/src/semiring.rs index 8b13789..a86b182 100644 --- a/src/semiring.rs +++ b/src/semiring.rs @@ -1 +1,113 @@ +use crate::monoid::{AdditiveMonoid, MultiplicativeMonoid}; +use crate::abelian::AdditiveAbelianGroup; +use crate::Distributive; +/// Represents a Semiring, an algebraic structure with two binary operations (addition and multiplication) +/// that satisfy certain axioms. +/// +/// A semiring (S, +, Β·, 0, 1) consists of: +/// - A set S +/// - Two binary operations + (addition) and Β· (multiplication) on S +/// - Two distinguished elements 0 (zero) and 1 (one) of S +/// +/// Formal Definition: +/// Let (S, +, Β·, 0, 1) be a semiring. Then: +/// 1. (S, +, 0) is a commutative monoid: +/// a. βˆ€ a, b, c ∈ S, (a + b) + c = a + (b + c) (associativity) +/// b. βˆ€ a, b ∈ S, a + b = b + a (commutativity) +/// c. βˆ€ a ∈ S, a + 0 = a = 0 + a (identity) +/// 2. (S, Β·, 1) is a monoid: +/// a. βˆ€ a, b, c ∈ S, (a Β· b) Β· c = a Β· (b Β· c) (associativity) +/// b. βˆ€ a ∈ S, a Β· 1 = a = 1 Β· a (identity) +/// 3. Multiplication distributes over addition: +/// a. βˆ€ a, b, c ∈ S, a Β· (b + c) = (a Β· b) + (a Β· c) (left distributivity) +/// b. βˆ€ a, b, c ∈ S, (a + b) Β· c = (a Β· c) + (b Β· c) (right distributivity) +/// 4. Multiplication by 0 annihilates S: +/// βˆ€ a ∈ S, 0 Β· a = 0 = a Β· 0 +pub trait Semiring: AdditiveMonoid + MultiplicativeMonoid + Distributive {} + +impl Semiring for T where T: AdditiveMonoid + MultiplicativeMonoid + Distributive {} + + +#[cfg(test)] +mod tests { + use super::*; + use crate::concrete::Z5; + use num_traits::{Zero, One}; + + #[test] + fn test_z5_semiring() { + // Test additive abelian group properties + for i in 0..5 { + for j in 0..5 { + let a = Z5::new(i); + let b = Z5::new(j); + + // Commutativity + assert_eq!(a + b, b + a); + + // Associativity + let c = Z5::new((i + j) % 5); + assert_eq!((a + b) + c, a + (b + c)); + } + } + + // Test additive identity + let zero = Z5::zero(); + for i in 0..5 { + let a = Z5::new(i); + assert_eq!(a + zero, a); + assert_eq!(zero + a, a); + } + + // Test multiplicative monoid properties + for i in 0..5 { + for j in 0..5 { + let a = Z5::new(i); + let b = Z5::new(j); + + // Associativity + let c = Z5::new((i * j) % 5); + assert_eq!((a * b) * c, a * (b * c)); + } + } + + // Test multiplicative identity + let one = Z5::one(); + for i in 0..5 { + let a = Z5::new(i); + assert_eq!(a * one, a); + assert_eq!(one * a, a); + } + + // Test distributivity + for i in 0..5 { + for j in 0..5 { + for k in 0..5 { + let a = Z5::new(i); + let b = Z5::new(j); + let c = Z5::new(k); + + // Left distributivity + assert_eq!(a * (b + c), (a * b) + (a * c)); + + // Right distributivity + assert_eq!((a + b) * c, (a * c) + (b * c)); + } + } + } + + // Test multiplication by zero + for i in 0..5 { + let a = Z5::new(i); + assert_eq!(a * zero, zero); + assert_eq!(zero * a, zero); + } + } + + #[test] + fn test_z5_implements_semiring() { + fn assert_semiring() {} + assert_semiring::(); + } +} \ No newline at end of file From 7c40218696c2be499a7574b4ee42c9f18055c471 Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Sat, 13 Jul 2024 03:21:09 -0400 Subject: [PATCH 10/21] feat: up to UFD --- src/abelian.rs | 5 +- src/alg_loop.rs | 1 - src/commutative_ring.rs | 103 +++++++++++++++++++++++++++++++++++ src/concrete.rs | 116 +++++++++++++++++++++++++++++++--------- src/cring.rs | 1 - src/group.rs | 9 ++-- src/integral_domain.rs | 53 ++++++++++++++++++ src/lib.rs | 44 ++++++++++----- src/pid.rs | 102 +++++++++++++++++++++++++++++++++++ src/quasigroup.rs | 1 - src/ring.rs | 3 +- src/semilattice.rs | 1 - src/semiring.rs | 6 +-- src/ufd.rs | 87 ++++++++++++++++++++++++++++++ src/uid.rs | 1 - 15 files changed, 477 insertions(+), 56 deletions(-) delete mode 100644 src/alg_loop.rs create mode 100644 src/commutative_ring.rs delete mode 100644 src/cring.rs delete mode 100644 src/quasigroup.rs delete mode 100644 src/semilattice.rs create mode 100644 src/ufd.rs delete mode 100644 src/uid.rs diff --git a/src/abelian.rs b/src/abelian.rs index 712e064..b1d6024 100644 --- a/src/abelian.rs +++ b/src/abelian.rs @@ -34,7 +34,7 @@ impl MultiplicativeAbelianGroup for T where T: MultiplicativeGroup + Commutat mod tests { use super::*; use crate::concrete::Z5; - use num_traits::{Zero, One, Inv}; + use num_traits::{Inv, One, Zero}; #[test] fn test_z5_additive_abelian_group() { @@ -79,7 +79,8 @@ mod tests { #[test] fn test_z5_multiplicative_abelian_group() { // Test commutativity - for i in 1..5 { // Skip 0 as it's not part of the multiplicative group + for i in 1..5 { + // Skip 0 as it's not part of the multiplicative group for j in 1..5 { let a = Z5::new(i); let b = Z5::new(j); diff --git a/src/alg_loop.rs b/src/alg_loop.rs deleted file mode 100644 index 8b13789..0000000 --- a/src/alg_loop.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/commutative_ring.rs b/src/commutative_ring.rs new file mode 100644 index 0000000..110257b --- /dev/null +++ b/src/commutative_ring.rs @@ -0,0 +1,103 @@ +use crate::ring::Ring; +use crate::Commutative; + +/// Represents a Commutative Ring, an algebraic structure where multiplication is commutative. +/// +/// A commutative ring (R, +, Β·) is a ring that also satisfies: +/// - Commutativity of multiplication: βˆ€ a, b ∈ R, a Β· b = b Β· a +/// +/// Formal Definition: +/// Let (R, +, Β·) be a commutative ring. Then: +/// 1. (R, +, Β·) is a ring +/// 2. βˆ€ a, b ∈ R, a Β· b = b Β· a (commutativity of multiplication) +pub trait CommutativeRing: Ring + Commutative {} + +impl CommutativeRing for T where T: Ring + Commutative {} + +#[cfg(test)] +mod tests { + use super::*; + use crate::concrete::Z5; + use num_traits::{One, Zero}; + + #[test] + fn test_z5_commutative_ring() { + // Test commutativity of multiplication + for i in 0..5 { + for j in 0..5 { + let a = Z5::new(i); + let b = Z5::new(j); + assert_eq!(a * b, b * a); + } + } + } + + #[test] + fn test_z5_ring_properties() { + // Test additive properties + for i in 0..5 { + for j in 0..5 { + let a = Z5::new(i); + let b = Z5::new(j); + + // Commutativity of addition + assert_eq!(a + b, b + a); + + // Associativity of addition + let c = Z5::new((i + j) % 5); + assert_eq!((a + b) + c, a + (b + c)); + } + } + + // Test multiplicative properties + for i in 0..5 { + for j in 0..5 { + let a = Z5::new(i); + let b = Z5::new(j); + + // Associativity of multiplication + let c = Z5::new((i * j) % 5); + assert_eq!((a * b) * c, a * (b * c)); + } + } + + // Test distributive property + for i in 0..5 { + for j in 0..5 { + for k in 0..5 { + let a = Z5::new(i); + let b = Z5::new(j); + let c = Z5::new(k); + + assert_eq!(a * (b + c), (a * b) + (a * c)); + assert_eq!((b + c) * a, (b * a) + (c * a)); + } + } + } + + // Test additive identity and inverse + let zero = Z5::zero(); + for i in 0..5 { + let a = Z5::new(i); + assert_eq!(a + zero, a); + assert_eq!(zero + a, a); + let neg_a = -a; + assert_eq!(a + neg_a, zero); + assert_eq!(neg_a + a, zero); + } + + // Test multiplicative identity + let one = Z5::one(); + for i in 0..5 { + let a = Z5::new(i); + assert_eq!(a * one, a); + assert_eq!(one * a, a); + } + } + + #[test] + fn test_z5_implements_commutative_ring() { + fn assert_commutative_ring() {} + assert_commutative_ring::(); + } +} diff --git a/src/concrete.rs b/src/concrete.rs index 6b60766..f6ee0c9 100644 --- a/src/concrete.rs +++ b/src/concrete.rs @@ -1,7 +1,11 @@ -use std::ops::{Add, Mul, Neg}; -use num_traits::{Inv, One, Zero}; -use crate::{Associative, Commutative, Distributive}; use crate::set::Set; +use crate::{Associative, Commutative, Distributive}; +use num_traits::{Euclid, Inv, One, Zero}; +use std::cmp::Ordering; +use std::ops::{Add, Div, Mul, Neg, Rem, Sub}; + +// This is a very sloppy and not optimal implementation of Z5. +// But seems correct overall. #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct Z5(pub(crate) u8); @@ -80,18 +84,67 @@ impl Set for Z5 { } } -// Implement necessary traits for Z5 impl Add for Z5 { type Output = Self; - fn add(self, other: Self) -> Self { - Z5::new(self.0 + other.0) + + fn add(self, rhs: Self) -> Self::Output { + Z5::new((self.0 + rhs.0) % 5) } } impl Mul for Z5 { type Output = Self; - fn mul(self, other: Self) -> Self { - Z5::new(self.0 * other.0) + + fn mul(self, rhs: Self) -> Self::Output { + Z5::new((self.0 * rhs.0) % 5) + } +} + +impl Neg for Z5 { + type Output = Self; + + fn neg(self) -> Self::Output { + Z5::new(5 - self.0) + } +} + +impl Inv for Z5 { + type Output = Self; + + fn inv(self) -> Self::Output { + if self.0 == 0 { + panic!("Cannot invert zero in Z5"); + } + for i in 1..5 { + if (self.0 * i) % 5 == 1 { + return Z5::new(i); + } + } + unreachable!() + } +} + +impl Div for Z5 { + type Output = Self; + + fn div(self, rhs: Self) -> Self::Output { + self * rhs.inv() + } +} + +impl Sub for Z5 { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + Z5::new((self.0 + 5 - rhs.0) % 5) + } +} + +impl Rem for Z5 { + type Output = Self; + + fn rem(self, rhs: Self) -> Self::Output { + Z5::new(self.0 % rhs.0) } } @@ -111,33 +164,46 @@ impl One for Z5 { } } -impl Neg for Z5 { - type Output = Self; +impl Euclid for Z5 { + fn div_euclid(&self, v: &Self) -> Self { + if v.is_zero() { + panic!("attempt to divide by zero"); + } + let q = (self.0 as i32 * v.inv().0 as i32) % 5; + Z5::new(q as u8) + } - fn neg(self) -> Self { - Z5::new(5 - self.0) + fn rem_euclid(&self, v: &Self) -> Self { + if v.is_zero() { + panic!("attempt to divide by zero"); + } + let r = self.0 % v.0; + Z5::new(r) } } -impl Inv for Z5 { - type Output = Self; +impl Z5 { + pub fn div_rem_euclid(&self, v: &Self) -> (Self, Self) { + let q = self.div_euclid(v); + let r = *self - q * *v; + (q, r) + } +} - fn inv(self) -> Self { - match self.0 { - 1 => Z5::new(1), - 2 => Z5::new(3), - 3 => Z5::new(2), - 4 => Z5::new(4), - 0 => panic!("Cannot invert zero in Z5"), - _ => unreachable!(), - } +impl PartialOrd for Z5 { + fn partial_cmp(&self, other: &Self) -> Option { + self.0.partial_cmp(&other.0) } } -impl Associative for Z5 {} +impl Ord for Z5 { + fn cmp(&self, other: &Self) -> Ordering { + self.0.cmp(&other.0) + } +} +impl Associative for Z5 {} impl Commutative for Z5 {} - impl Distributive for Z5 {} #[derive(Clone, PartialEq, Debug)] diff --git a/src/cring.rs b/src/cring.rs deleted file mode 100644 index 8b13789..0000000 --- a/src/cring.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/group.rs b/src/group.rs index 94925d7..ba96018 100644 --- a/src/group.rs +++ b/src/group.rs @@ -1,5 +1,5 @@ -use crate::{ClosedInv, ClosedNeg}; use crate::monoid::{AdditiveMonoid, MultiplicativeMonoid}; +use crate::{ClosedInv, ClosedNeg}; /// Represents an Additive Group, an algebraic structure with a set, an associative closed addition operation, /// an identity element, and inverses for all elements. @@ -39,8 +39,8 @@ impl MultiplicativeGroup for T where T: MultiplicativeMonoid + ClosedInv {} #[cfg(test)] mod tests { use crate::concrete::Z5; - use num_traits::{Zero, One, Inv}; use crate::group::{AdditiveGroup, MultiplicativeGroup}; + use num_traits::{Inv, One, Zero}; #[test] fn test_z5_additive_group() { @@ -76,7 +76,8 @@ mod tests { #[test] fn test_z5_multiplicative_group() { // Test associativity - for i in 1..5 { // Skip 0 as it's not part of the multiplicative group + for i in 1..5 { + // Skip 0 as it's not part of the multiplicative group for j in 1..5 { for k in 1..5 { let a = Z5::new(i); @@ -112,4 +113,4 @@ mod tests { assert_additive_group::(); assert_multiplicative_group::(); } -} \ No newline at end of file +} diff --git a/src/integral_domain.rs b/src/integral_domain.rs index 8b13789..163874f 100644 --- a/src/integral_domain.rs +++ b/src/integral_domain.rs @@ -1 +1,54 @@ +use crate::ring::Ring; +use crate::ClosedDiv; +use std::ops::Div; +/// Represents an Integral Domain, a commutative ring with no zero divisors. +/// +/// An integral domain (D, +, Β·) consists of: +/// - A set D +/// - Two binary operations + (addition) and Β· (multiplication) on D +/// - Two distinguished elements 0 (zero) and 1 (unity) of D +/// +/// Formal Definition: +/// Let (D, +, Β·) be an integral domain. Then: +/// 1. (D, +, Β·) is a commutative ring +/// 2. D has no zero divisors: +/// βˆ€ a, b ∈ D, if a Β· b = 0, then a = 0 or b = 0 +/// 3. The zero element is distinct from the unity: +/// 0 β‰  1 +pub trait IntegralDomain: Ring + ClosedDiv {} + +impl IntegralDomain for T where T: Ring + Div {} + +#[cfg(test)] +mod tests { + use super::*; + use crate::concrete::Z5; + use num_traits::{One, Zero}; + use std::panic::{catch_unwind, AssertUnwindSafe}; + + #[test] + fn test_z5_implements_integral_domain() { + fn assert_integral_domain() {} + assert_integral_domain::(); + } + + #[test] + fn test_unity_not_zero() { + let zero = Z5::zero(); + let one = Z5::one(); + assert_ne!(zero, one); + } + + #[test] + fn test_z5_division_by_zero() { + let a = Z5::new(1); + let zero = Z5::zero(); + + let result = catch_unwind(AssertUnwindSafe(|| { + let _ = a / zero; + })); + + assert!(result.is_err(), "Division by zero should panic"); + } +} diff --git a/src/lib.rs b/src/lib.rs index dbd6dfe..c3167fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -92,19 +92,13 @@ //! β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ //! ``` -// Implemented traits -mod magma; -mod monoid; -mod operator; -mod semigroup; -mod set; - -// Not yet implemented -mod abelian; -mod alg_loop; +// Concrete implemetations for tests #[cfg(test)] mod concrete; -mod cring; + +// Implemented traits +mod abelian; +mod commutative_ring; mod euclidean_domain; mod field; mod field_extension; @@ -112,12 +106,22 @@ mod finite_field; mod group; mod infinite_field; mod integral_domain; +mod magma; +mod monoid; +mod operator; mod pid; -mod quasigroup; mod ring; -mod semilattice; +mod semigroup; mod semiring; -mod uid; +mod set; +mod ufd; + +// Not yet implemented +// mod alg_loop; +// mod quasigroup; +// mod semilattice; +// mod module; +// mod vector_space; // Library level re-exports @@ -134,3 +138,15 @@ pub use monoid::*; pub use group::*; pub use abelian::*; + +pub use semiring::*; + +pub use ring::*; + +pub use commutative_ring::*; + +pub use integral_domain::*; + +pub use ufd::*; + +pub use pid::*; diff --git a/src/pid.rs b/src/pid.rs index 8b13789..bcda407 100644 --- a/src/pid.rs +++ b/src/pid.rs @@ -1 +1,103 @@ +use crate::UniqueFactorizationDomain; +use num_traits::Euclid; +/// Represents a Principal Ideal Domain (PID), an integral domain where every ideal is principal. +/// +/// A Principal Ideal Domain (R, +, Β·) is an integral domain that satisfies: +/// 1. (R, +, Β·) is an integral domain +/// 2. Every ideal in R is principal (can be generated by a single element) +/// +/// Formal Definition: +/// Let R be an integral domain. R is a PID if for every ideal I βŠ† R, there exists an element a ∈ R +/// such that I = (a) = {ra | r ∈ R}. +pub trait PrincipalIdealDomain: UniqueFactorizationDomain + Euclid {} + +impl PrincipalIdealDomain for T where T: UniqueFactorizationDomain + Euclid {} + +#[cfg(test)] +mod tests { + use crate::concrete::Z5; + use crate::ClosedRemEuclid; + use crate::PrincipalIdealDomain; + use num_traits::Zero; + + #[test] + fn test_z5_implements_pid() { + fn assert_pid() {} + assert_pid::(); + } + + #[test] + fn test_z5_euclidean_division() { + for i in 0..5 { + for j in 1..5 { + // Avoid division by zero + let a = Z5::new(i); + let b = Z5::new(j); + let (q, r) = a.div_rem_euclid(&b); + assert_eq!(a, q * b + r); + assert!(r.is_zero() || r < b); + } + } + } + + #[test] + fn test_z5_gcd() { + for i in 0..5 { + for j in 0..5 { + let a = Z5::new(i); + let b = Z5::new(j); + let g = gcd(a, b); + + // Check that g divides both a and b + if !g.is_zero() { + assert_eq!(a.rem_euclid(g), Z5::zero()); + assert_eq!(b.rem_euclid(g), Z5::zero()); + } + + // Check that g is the greatest such divisor + for k in 1..5 { + let d = Z5::new(k); + if !d.is_zero() + && a.rem_euclid(d) == Z5::zero() + && b.rem_euclid(d) == Z5::zero() + { + // In Z5, we need to check if d is a multiple of g + assert!(d.rem_euclid(g) == Z5::zero()); + } + } + } + } + } + + fn gcd(a: Z5, b: Z5) -> Z5 { + if b.is_zero() { + a + } else { + gcd(b, a.rem_euclid(b)) + } + } + + #[test] + fn test_z5_principal_ideals() { + for i in 0..5 { + let a = Z5::new(i); + let ideal = generate_ideal(a); + assert!(is_principal_ideal(&ideal)); + } + } + + fn generate_ideal(a: Z5) -> Vec { + (0..5).map(|i| a * Z5::new(i)).collect() + } + + fn is_principal_ideal(ideal: &[Z5]) -> bool { + if ideal.is_empty() { + return true; // The zero ideal is principal + } + let binding = Z5::zero(); + let generator = ideal.iter().find(|&&x| !x.is_zero()).unwrap_or(&binding); + let generated_ideal = generate_ideal(*generator); + ideal.iter().all(|elem| generated_ideal.contains(elem)) + } +} diff --git a/src/quasigroup.rs b/src/quasigroup.rs deleted file mode 100644 index 8b13789..0000000 --- a/src/quasigroup.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/ring.rs b/src/ring.rs index aeca17d..7e01d3f 100644 --- a/src/ring.rs +++ b/src/ring.rs @@ -24,12 +24,11 @@ pub trait Ring: AdditiveAbelianGroup + MultiplicativeMonoid + Distributive {} impl Ring for T where T: AdditiveAbelianGroup + MultiplicativeMonoid + Distributive {} - #[cfg(test)] mod tests { use super::*; use crate::concrete::Z5; - use num_traits::{Zero, One}; + use num_traits::{One, Zero}; #[test] fn test_z5_ring() { diff --git a/src/semilattice.rs b/src/semilattice.rs deleted file mode 100644 index 8b13789..0000000 --- a/src/semilattice.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/semiring.rs b/src/semiring.rs index a86b182..83969d4 100644 --- a/src/semiring.rs +++ b/src/semiring.rs @@ -1,5 +1,4 @@ use crate::monoid::{AdditiveMonoid, MultiplicativeMonoid}; -use crate::abelian::AdditiveAbelianGroup; use crate::Distributive; /// Represents a Semiring, an algebraic structure with two binary operations (addition and multiplication) @@ -28,12 +27,11 @@ pub trait Semiring: AdditiveMonoid + MultiplicativeMonoid + Distributive {} impl Semiring for T where T: AdditiveMonoid + MultiplicativeMonoid + Distributive {} - #[cfg(test)] mod tests { use super::*; use crate::concrete::Z5; - use num_traits::{Zero, One}; + use num_traits::{One, Zero}; #[test] fn test_z5_semiring() { @@ -110,4 +108,4 @@ mod tests { fn assert_semiring() {} assert_semiring::(); } -} \ No newline at end of file +} diff --git a/src/ufd.rs b/src/ufd.rs new file mode 100644 index 0000000..fce317f --- /dev/null +++ b/src/ufd.rs @@ -0,0 +1,87 @@ +use crate::integral_domain::IntegralDomain; + +/// Represents a Unique Factorization Domain (UFD), an integral domain where every non-zero +/// non-unit element has a unique factorization into irreducible elements. +/// +/// A UFD (R, +, Β·) is an integral domain that satisfies: +/// 1. Every non-zero non-unit element can be factored into irreducible elements. +/// 2. This factorization is unique up to order and associates. +/// +/// Formal Definition: +/// Let R be an integral domain. R is a UFD if: +/// 1. For every non-zero non-unit a ∈ R, there exist irreducible elements p₁, ..., pβ‚™ such that +/// a = p₁ Β· ... Β· pβ‚™ +/// 2. If a = p₁ Β· ... Β· pβ‚™ = q₁ Β· ... Β· qβ‚˜ are two factorizations of a into irreducible elements, +/// then n = m and there exists a bijection Οƒ: {1, ..., n} β†’ {1, ..., n} such that pα΅’ is +/// associated to qβ‚›α΅’ for all i. +pub trait UniqueFactorizationDomain: IntegralDomain {} + +impl UniqueFactorizationDomain for T where T: IntegralDomain {} + +#[cfg(test)] +mod tests { + use super::*; + use crate::concrete::Z5; + use num_traits::{One, Zero}; + + fn is_irreducible(a: &Z5) -> bool { + !a.is_zero() && !a.is_one() + } + + fn factor(a: &Z5) -> Vec { + if a.is_zero() || a.is_one() { + vec![*a] + } else { + vec![*a] // In Z5, all non-zero, non-one elements are irreducible + } + } + + fn are_associates(a: &Z5, b: &Z5) -> bool { + !a.is_zero() && !b.is_zero() + } + + fn check_unique_factorization(a: &Z5) -> bool { + let factorization = factor(a); + + if a.is_zero() || a.is_one() { + factorization.len() == 1 && factorization[0] == *a + } else { + factorization.len() == 1 && is_irreducible(&factorization[0]) + } + } + + #[test] + fn test_z5_ufd() { + // Test irreducibility + assert!(!is_irreducible(&Z5::new(0))); + assert!(!is_irreducible(&Z5::new(1))); + assert!(is_irreducible(&Z5::new(2))); + assert!(is_irreducible(&Z5::new(3))); + assert!(is_irreducible(&Z5::new(4))); + + // Test factorization + assert_eq!(factor(&Z5::new(0)), vec![Z5::new(0)]); + assert_eq!(factor(&Z5::new(1)), vec![Z5::new(1)]); + assert_eq!(factor(&Z5::new(2)), vec![Z5::new(2)]); + assert_eq!(factor(&Z5::new(3)), vec![Z5::new(3)]); + assert_eq!(factor(&Z5::new(4)), vec![Z5::new(4)]); + + // Test associates + for i in 1..5 { + for j in 1..5 { + assert!(are_associates(&Z5::new(i), &Z5::new(j))); + } + } + + // Test unique factorization + for i in 0..5 { + assert!(check_unique_factorization(&Z5::new(i))); + } + } + + #[test] + fn test_z5_implements_ufd() { + fn assert_ufd() {} + assert_ufd::(); + } +} diff --git a/src/uid.rs b/src/uid.rs deleted file mode 100644 index 8b13789..0000000 --- a/src/uid.rs +++ /dev/null @@ -1 +0,0 @@ - From cf3e8db18243f41c5fefc6d5e814f17bf88dcecb Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Sat, 13 Jul 2024 04:02:35 -0400 Subject: [PATCH 11/21] feat: rough cut of all --- src/concrete.rs | 3 +- src/euclidean_domain.rs | 33 ++++++++++++++ src/extension_tower.rs | 98 +++++++++++++++++++++++++++++++++++++++++ src/field.rs | 16 +++++++ src/field_extension.rs | 88 ++++++++++++++++++++++++++++++++++++ src/finite_field.rs | 51 +++++++++++++++++++++ src/infinite_field.rs | 1 - src/lib.rs | 16 ++++++- src/pid.rs | 12 +++-- src/real_field.rs | 55 +++++++++++++++++++++++ 10 files changed, 361 insertions(+), 12 deletions(-) create mode 100644 src/extension_tower.rs delete mode 100644 src/infinite_field.rs create mode 100644 src/real_field.rs diff --git a/src/concrete.rs b/src/concrete.rs index f6ee0c9..12026a1 100644 --- a/src/concrete.rs +++ b/src/concrete.rs @@ -177,8 +177,7 @@ impl Euclid for Z5 { if v.is_zero() { panic!("attempt to divide by zero"); } - let r = self.0 % v.0; - Z5::new(r) + Z5::new(self.0 % v.0) } } diff --git a/src/euclidean_domain.rs b/src/euclidean_domain.rs index 8b13789..b889095 100644 --- a/src/euclidean_domain.rs +++ b/src/euclidean_domain.rs @@ -1 +1,34 @@ +use crate::PrincipalIdealDomain; +/// Represents a Euclidean Domain, an integral domain with a Euclidean function. +/// +/// A Euclidean Domain (R, +, Β·, Ο†) is a principal ideal domain equipped with a +/// Euclidean function Ο†: R\{0} β†’ β„•β‚€ that satisfies certain properties. +/// +/// Formal Definition: +/// Let (R, +, Β·) be an integral domain and Ο†: R\{0} β†’ β„•β‚€ a function. R is a Euclidean domain if: +/// 1. βˆ€a, b ∈ R, b β‰  0, βˆƒ!q, r ∈ R : a = bq + r ∧ (r = 0 ∨ Ο†(r) < Ο†(b)) (Division with Remainder) +/// 2. βˆ€a, b ∈ R\{0} : Ο†(a) ≀ Ο†(ab) (Multiplicative Property) +pub trait EuclideanDomain: PrincipalIdealDomain { + /// The Euclidean function Ο†: R\{0} β†’ β„•β‚€ + /// Returns None if the input is zero. + fn euclidean_function(&self) -> Option; + + /// Computes the greatest common divisor (GCD) using the Euclidean algorithm. + fn gcd(mut a: Self, mut b: Self) -> Self + where + Self: Sized + Clone, + { + if b.is_zero() { + return a; + } + + while !b.is_zero() { + let r = a.rem_euclid(&b); + a = b; + b = r; + } + + a + } +} diff --git a/src/extension_tower.rs b/src/extension_tower.rs new file mode 100644 index 0000000..9f02ec7 --- /dev/null +++ b/src/extension_tower.rs @@ -0,0 +1,98 @@ +use crate::field_extension::FieldExtension; + +/// Represents a tower of field extensions. +/// +/// For a tower of fields Fβ‚€ βŠ† F₁ βŠ† Fβ‚‚ βŠ† ... βŠ† Fβ‚™, +/// where each Fα΅’β‚Šβ‚ is an extension field of Fα΅’ for i = 0, 1, ..., n-1. +pub trait FieldExtensionTower: FieldExtension { + /// The type representing each level in the tower. + type Level: FieldExtension; + + /// Returns the number of extensions in the tower. + /// For an infinite tower, this returns None. + fn height() -> Option; + + /// Returns the base field of the entire tower (Fβ‚€). + fn base_field() -> Self::BaseField; + + /// Returns the top field of the tower (Fβ‚™). + fn top_field() -> Self::Level; + + /// Returns an iterator over all fields in the tower, from bottom to top. + /// Yields Fβ‚€, F₁, Fβ‚‚, ..., Fβ‚™ in order. + fn fields() -> Box>; + + /// Returns the field at a specific level in the tower. + /// Level 0 is the base field, level height()-1 is the top field. + fn field_at_level(level: usize) -> Option; + + /// Returns an iterator over the degrees of each extension in the tower. + /// Yields [F₁:Fβ‚€], [Fβ‚‚:F₁], ..., [Fβ‚™:Fₙ₋₁]. + fn extension_degrees() -> Box>>; + + /// Computes the absolute degree of the entire tower extension. + /// [Fβ‚™:Fβ‚€] = [Fβ‚™:Fₙ₋₁] Β· [Fₙ₋₁:Fβ‚™β‚‹β‚‚] Β· ... Β· [Fβ‚‚:F₁] Β· [F₁:Fβ‚€] + fn absolute_degree() -> Option { + self.extension_degrees() + .fold(Some(1), |acc, deg| { + acc.and_then(|a| deg.map(|d| a * d)) + }) + } + + /// Returns an iterator over the minimal polynomials of each extension in the tower. + /// Each minimal polynomial is represented as a vector of coefficients in ascending order of degree. + fn minimal_polynomials() -> Box>>; + + /// Embeds an element from any field in the tower into the top field. + fn embed_to_top(element: &Self::Level, from_level: usize) -> Self::Level; + + /// Attempts to project an element from the top field to a lower level in the tower. + /// Returns None if the element cannot be represented in the lower field. + fn project_from_top(element: &Self::Level, to_level: usize) -> Option; + + /// Checks if the entire tower consists of normal extensions. + fn is_normal() -> bool { + self.fields().all(|field| field.is_normal()) + } + + /// Checks if the entire tower consists of separable extensions. + fn is_separable() -> bool { + self.fields().all(|field| field.is_separable()) + } + + /// Checks if the entire tower consists of algebraic extensions. + fn is_algebraic() -> bool { + self.fields().all(|field| field.is_algebraic()) + } + + /// Checks if the tower is Galois (normal and separable). + fn is_galois() -> bool { + self.is_normal() && self.is_separable() + } + + /// Computes the compositum of this tower with another tower over the same base field. + /// Returns a new tower representing the smallest field containing both towers. + fn compositum(other: &Self) -> Self; + + /// Attempts to find an isomorphic simple extension for this tower. + /// Returns None if no such simple extension exists or cannot be computed. + fn to_simple_extension() -> Option; + + /// Checks if this tower is a refinement of another tower. + /// A refinement means this tower includes all the fields of the other tower, possibly with additional fields in between. + fn is_refinement_of(other: &Self) -> bool; + + /// Returns an iterator over all intermediate fields between the base and top fields. + /// This can be an exponentially large set for some towers. + fn intermediate_fields() -> Box>; + + /// Checks if the tower satisfies the axioms for a valid field extension tower. + fn check_tower_axioms() -> bool { + // Implementation would check: + // 1. Each level is a valid field extension of the previous level + // 2. The tower is properly nested (each field is a subfield of the next) + // 3. Degree multiplicativity holds + // 4. Other consistency checks + unimplemented!("Axiom checking not implemented") + } +} \ No newline at end of file diff --git a/src/field.rs b/src/field.rs index 8b13789..80166c7 100644 --- a/src/field.rs +++ b/src/field.rs @@ -1 +1,17 @@ +use crate::EuclideanDomain; +use crate::{ClosedDiv}; +/// Represents a Field, an algebraic structure that is a Euclidean domain where every non-zero element +/// has a multiplicative inverse. +/// +/// A field (F, +, Β·) consists of: +/// - A set F +/// - Two binary operations + (addition) and Β· (multiplication) on F +/// +/// Formal Definition: +/// Let (F, +, Β·) be a field. Then: +/// 1. (F, +, Β·) is a Euclidean domain +/// 2. Every non-zero element has a multiplicative inverse +/// 3. 0 β‰  1 (the additive identity is not equal to the multiplicative identity) +pub trait Field: EuclideanDomain + ClosedDiv { +} diff --git a/src/field_extension.rs b/src/field_extension.rs index 8b13789..6286619 100644 --- a/src/field_extension.rs +++ b/src/field_extension.rs @@ -1 +1,89 @@ +use std::fmt::Debug; +use crate::Field; +/// Represents a field extension. +/// +/// Let K and L be fields. A field extension L/K is defined as: +/// - K is a subfield of L +/// - The operations of L, when restricted to K, are the same as the operations of K +/// - L is a vector space over K +/// +/// Notation: +/// - K: base field +/// - L: extension field +/// - [L:K]: degree of the extension +pub trait FieldExtension: Field { + /// The base field of the extension. + /// Mathematically, this is K in the extension L/K. + type BaseField: Field; + + /// Returns the degree of the field extension. + /// Mathematically, this is [L:K], the dimension of L as a vector space over K. + /// For infinite extensions, this returns None. + /// + /// [L:K] = dim_K(L) + fn degree() -> Option; + + /// Embeds an element from the base field into the extension field. + /// This represents the natural inclusion map i: K β†’ L. + /// + /// βˆ€ k ∈ K, i(k) ∈ L + fn embed(element: Self::BaseField) -> Self; + + /// Attempts to represent an element of the extension field as an element of the base field. + /// This is the inverse of the embed function, where possible. + /// Returns None if the element is not in the image of K in L. + /// + /// For l ∈ L, if βˆƒ k ∈ K such that i(k) = l, return Some(k), else None + fn project(&self) -> Option; + + /// Returns a basis of the extension field as a vector space over the base field. + /// For a finite extension of degree n, this returns {v₁, ..., vβ‚™} where: + /// βˆ€ l ∈ L, βˆƒ unique k₁, ..., kβ‚™ ∈ K such that l = k₁v₁ + ... + kβ‚™vβ‚™ + /// + /// For infinite extensions, this returns an infinite iterator. + fn basis() -> Box>; + + /// Expresses an element of the extension field as a linear combination of basis elements. + /// For l ∈ L, returns [k₁, ..., kβ‚™] ∈ K^n such that l = k₁v₁ + ... + kβ‚™vβ‚™ + /// where {v₁, ..., vβ‚™} is the basis of L over K. + fn decompose(&self) -> Vec; + + /// Constructs an element of the extension field from its decomposition in terms of the basis. + /// Given [k₁, ..., kβ‚™] ∈ K^n, returns k₁v₁ + ... + kβ‚™vβ‚™ ∈ L + /// where {v₁, ..., vβ‚™} is the basis of L over K. + fn compose(coefficients: &[Self::BaseField]) -> Self; + + /// Returns the minimal polynomial of the extension over the base field. + /// For a simple algebraic extension L = K(Ξ±), this is the monic irreducible polynomial + /// p(X) ∈ K[X] such that p(Ξ±) = 0. + /// + /// The coefficients are given in ascending order of degree: + /// [aβ‚€, a₁, ..., aβ‚™] represents p(X) = aβ‚€ + a₁X + ... + aβ‚™X^n + fn minimal_polynomial() -> Vec; + + /// Checks if this extension is normal. + /// A field extension L/K is normal if L is the splitting field of a polynomial over K. + /// + /// βˆƒ p(X) ∈ K[X] such that L = K(α₁, ..., Ξ±β‚™) where α₁, ..., Ξ±β‚™ are all roots of p(X) + fn is_normal() -> bool; + + /// Checks if this extension is separable. + /// A field extension L/K is separable if the minimal polynomial of every element of L over K + /// is separable (has no repeated roots in its splitting field). + /// + /// βˆ€ Ξ± ∈ L, the minimal polynomial of Ξ± over K has distinct roots in its splitting field + fn is_separable() -> bool; + + /// Checks if this extension is algebraic. + /// A field extension L/K is algebraic if every element of L is algebraic over K. + /// + /// βˆ€ Ξ± ∈ L, βˆƒ non-zero p(X) ∈ K[X] such that p(Ξ±) = 0 + fn is_algebraic() -> bool; + + /// Checks if the field extension axioms hold. + /// This method would implement checks for the field extension properties. + /// The exact checks would depend on whether the extension is finite or infinite, + /// and might be computationally infeasible for some extensions. + fn check_field_extension_axioms() -> bool; +} diff --git a/src/finite_field.rs b/src/finite_field.rs index 8b13789..ff5feae 100644 --- a/src/finite_field.rs +++ b/src/finite_field.rs @@ -1 +1,52 @@ +use crate::Field; +/// Represents a Finite Prime Field, a field with a finite number of elements where the number of elements is prime. +/// +/// A finite prime field β„€/pβ„€ (also denoted as 𝔽_p or GF(p)) consists of: +/// - A set of p elements {0, 1, 2, ..., p-1}, where p is prime +/// - Addition and multiplication operations modulo p +/// +/// Formal Definition: +/// Let p be a prime number. Then: +/// 1. The set is {0, 1, 2, ..., p-1} +/// 2. Addition: a +_p b = (a + b) mod p +/// 3. Multiplication: a Β·_p b = (a Β· b) mod p +/// 4. The additive identity is 0 +/// 5. The multiplicative identity is 1 +/// 6. Every non-zero element has a unique multiplicative inverse +pub trait FinitePrimeField: Field { + /// Returns the characteristic of the field, which is the prime number p. + fn characteristic() -> u64; + + /// Returns the number of elements in the field, which is equal to the characteristic for prime fields. + fn order() -> u64 { + Self::characteristic() + } + + /// Checks if the given integer is a primitive element (generator) of the multiplicative group. + fn is_primitive_element(element: &Self) -> bool; + + /// Computes the multiplicative inverse using Fermat's Little Theorem: a^(p-1) ≑ 1 (mod p) + /// Therefore, a^(p-2) is the multiplicative inverse of a. + fn mul_inverse(&self) -> Option { + if self.is_zero() { + None + } else { + Some(self.pow(Self::characteristic() - 2)) + } + } + + /// Raises the element to a power using exponentiation by squaring. + fn pow(&self, mut exponent: u64) -> Self { + let mut base = self.clone(); + let mut result = Self::one(); + while exponent > 0 { + if exponent % 2 == 1 { + result = result * base.clone(); + } + base = base.clone() * base; + exponent /= 2; + } + result + } +} diff --git a/src/infinite_field.rs b/src/infinite_field.rs deleted file mode 100644 index 8b13789..0000000 --- a/src/infinite_field.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/lib.rs b/src/lib.rs index c3167fc..484b596 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,7 +104,7 @@ mod field; mod field_extension; mod finite_field; mod group; -mod infinite_field; +mod real_field; mod integral_domain; mod magma; mod monoid; @@ -115,7 +115,7 @@ mod semigroup; mod semiring; mod set; mod ufd; - +mod extension_tower; // Not yet implemented // mod alg_loop; // mod quasigroup; @@ -150,3 +150,15 @@ pub use integral_domain::*; pub use ufd::*; pub use pid::*; + +pub use euclidean_domain::*; + +pub use field::*; + +pub use real_field::*; + +pub use field_extension::*; + +pub use finite_field::*; + +pub use extension_tower::*; diff --git a/src/pid.rs b/src/pid.rs index bcda407..80427d2 100644 --- a/src/pid.rs +++ b/src/pid.rs @@ -58,12 +58,8 @@ mod tests { // Check that g is the greatest such divisor for k in 1..5 { let d = Z5::new(k); - if !d.is_zero() - && a.rem_euclid(d) == Z5::zero() - && b.rem_euclid(d) == Z5::zero() - { - // In Z5, we need to check if d is a multiple of g - assert!(d.rem_euclid(g) == Z5::zero()); + if !d.is_zero() && a.rem_euclid(d) == Z5::zero() && b.rem_euclid(d) == Z5::zero() { + assert!(g.0 >= d.0); } } } @@ -71,7 +67,9 @@ mod tests { } fn gcd(a: Z5, b: Z5) -> Z5 { - if b.is_zero() { + if a.is_zero() && b.is_zero() { + Z5::zero() + } else if b.is_zero() { a } else { gcd(b, a.rem_euclid(b)) diff --git a/src/real_field.rs b/src/real_field.rs new file mode 100644 index 0000000..a5b0dc5 --- /dev/null +++ b/src/real_field.rs @@ -0,0 +1,55 @@ +use crate::Field; + +/// Represents a Real Field, an ordered field that satisfies the completeness axiom. +/// +/// A real field (F, +, Β·, ≀) consists of: +/// - A set F +/// - Two binary operations + (addition) and Β· (multiplication) +/// - A total order relation ≀ +/// +/// Formal Definition: +/// 1. (F, +, Β·) is a field +/// 2. (F, ≀) is a totally ordered set +/// 3. The order is compatible with field operations +/// 4. F satisfies the completeness axiom +pub trait RealField: Field + PartialOrd + Ord { + /// Returns the absolute value of the number. + fn abs(&self) -> Self; + + /// Returns the square root of the number, if it exists. + fn sqrt(&self) -> Option; + + /// Computes the natural logarithm of the number. + fn ln(&self) -> Self; + + /// Raises e (Euler's number) to the power of self. + fn exp(&self) -> Self; + + /// Computes the sine of the number (assumed to be in radians). + fn sin(&self) -> Self; + + /// Computes the cosine of the number (assumed to be in radians). + fn cos(&self) -> Self; + + /// Computes the tangent of the number (assumed to be in radians). + fn tan(&self) -> Self; + + /// Returns the smallest integer greater than or equal to the number. + fn ceil(&self) -> Self; + + /// Returns the largest integer less than or equal to the number. + fn floor(&self) -> Self; + + /// Rounds the number to the nearest integer. + fn round(&self) -> Self; + + /// Checks if the number is finite (not infinite and not NaN). + fn is_finite(&self) -> bool; + + /// Checks if the number is infinite. + fn is_infinite(&self) -> bool; + + /// Checks if the number is NaN (Not a Number). + fn is_nan(&self) -> bool; +} + From 7773e6c957a5197fc39e16a857ca9bea448051bd Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Sat, 13 Jul 2024 04:44:27 -0400 Subject: [PATCH 12/21] feat: prototype implementations --- src/concrete_finite.rs | 306 +++++++++++++++++++++++++ src/concrete_polynomial.rs | 441 +++++++++++++++++++++++++++++++++++++ src/euclidean_domain.rs | 21 +- src/extension_tower.rs | 23 +- src/field.rs | 7 +- src/field_extension.rs | 1 - src/finite_field.rs | 2 +- src/lib.rs | 6 +- src/pid.rs | 36 +-- src/real_field.rs | 1 - 10 files changed, 764 insertions(+), 80 deletions(-) create mode 100644 src/concrete_finite.rs create mode 100644 src/concrete_polynomial.rs diff --git a/src/concrete_finite.rs b/src/concrete_finite.rs new file mode 100644 index 0000000..ec0d2ba --- /dev/null +++ b/src/concrete_finite.rs @@ -0,0 +1,306 @@ +use crate::{Associative, Commutative, Distributive, EuclideanDomain, Field, FiniteField, Set}; +use num_traits::{Inv, One, Zero}; +use std::fmt::{self, Debug, Display}; +use std::ops::{Add, Div, Mul, Neg, Rem, Sub}; + +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct FinitePrimeField { + value: u64, +} + +impl FinitePrimeField

{ + pub fn new(value: u64) -> Self { + assert!(Self::is_prime(P), "P must be prime"); + Self { value: value % P } + } + + fn is_prime(n: u64) -> bool { + if n <= 1 { + return false; + } + if n == 2 { + return true; + } + if n % 2 == 0 { + return false; + } + let sqrt_n = (n as f64).sqrt() as u64; + for i in (3..=sqrt_n).step_by(2) { + if n % i == 0 { + return false; + } + } + true + } + + pub fn value(&self) -> u64 { + self.value + } +} + +impl Debug for FinitePrimeField

{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}(mod {})", self.value, P) + } +} + +impl Display for FinitePrimeField

{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.value) + } +} + +impl Add for FinitePrimeField

{ + type Output = Self; + fn add(self, rhs: Self) -> Self::Output { + Self::new(self.value + rhs.value) + } +} + +impl Sub for FinitePrimeField

{ + type Output = Self; + fn sub(self, rhs: Self) -> Self::Output { + Self::new(self.value + P - rhs.value) + } +} + +impl Mul for FinitePrimeField

{ + type Output = Self; + fn mul(self, rhs: Self) -> Self::Output { + Self::new(self.value * rhs.value) + } +} + +impl Div for FinitePrimeField

{ + type Output = Self; + fn div(self, rhs: Self) -> Self::Output { + self * rhs.inv() + } +} + +impl Neg for FinitePrimeField

{ + type Output = Self; + fn neg(self) -> Self::Output { + Self::new(P - self.value) + } +} + +impl Rem for FinitePrimeField

{ + type Output = Self; + fn rem(self, rhs: Self) -> Self::Output { + Self::new(self.value % rhs.value) + } +} + +impl Zero for FinitePrimeField

{ + fn zero() -> Self { + Self::new(0) + } + + fn is_zero(&self) -> bool { + self.value == 0 + } +} + +impl One for FinitePrimeField

{ + fn one() -> Self { + Self::new(1) + } +} + +impl Inv for FinitePrimeField

{ + type Output = Self; + + fn inv(self) -> Self::Output { + if self.is_zero() { + panic!("attempt to invert zero"); + } + self.pow(P - 2) + } +} + +impl Set for FinitePrimeField

{ + type Element = Self; + + fn is_empty(&self) -> bool { + false + } + + fn contains(&self, element: &Self::Element) -> bool { + element.value < P + } + + fn empty() -> Self { + Self::zero() + } + + fn singleton(element: Self::Element) -> Self { + element + } + + fn union(&self, _other: &Self) -> Self { + *self + } + + fn intersection(&self, other: &Self) -> Self { + if self == other { + *self + } else { + Self::empty() + } + } + + fn difference(&self, other: &Self) -> Self { + if self == other { + Self::empty() + } else { + *self + } + } + + fn symmetric_difference(&self, other: &Self) -> Self { + if self == other { + Self::empty() + } else { + *self + } + } + + fn is_subset(&self, _other: &Self) -> bool { + true + } + + fn is_equal(&self, other: &Self) -> bool { + self == other + } + + fn cardinality(&self) -> Option { + Some(P as usize) + } + + fn is_finite(&self) -> bool { + true + } +} + +impl Commutative for FinitePrimeField

{} +impl Associative for FinitePrimeField

{} +impl Distributive for FinitePrimeField

{} + +impl num_traits::Euclid for FinitePrimeField

{ + fn div_euclid(&self, v: &Self) -> Self { + *self / *v + } + + fn rem_euclid(&self, v: &Self) -> Self { + *self % *v + } +} + +impl EuclideanDomain for FinitePrimeField

{ + fn gcd(a: Self, b: Self) -> Self { + if b.is_zero() { + a + } else { + Self::gcd(b, a % b) + } + } +} + +impl Field for FinitePrimeField

{} + +impl FiniteField for FinitePrimeField

{ + fn characteristic() -> u64 { + P + } + + fn order() -> u64 { + P + } + + fn is_primitive_element(element: &Self) -> bool { + if element.is_zero() { + return false; + } + let mut x = *element; + for _ in 1..P - 1 { + if x.is_one() { + return false; + } + x = x * *element; + } + x.is_one() + } + + fn pow(&self, mut exponent: u64) -> Self { + let mut base = *self; + let mut result = Self::one(); + while exponent > 0 { + if exponent % 2 == 1 { + result = result * base; + } + exponent /= 2; + base = base * base; + } + result + } + + fn mul_inverse(&self) -> Option { + if self.is_zero() { + None + } else { + Some(self.inv()) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + type F5 = FinitePrimeField<5>; + + #[test] + fn test_finite_prime_field_arithmetic() { + let a = F5::new(2); + let b = F5::new(3); + + assert_eq!(a + b, F5::new(0)); + assert_eq!(a - b, F5::new(4)); + assert_eq!(a * b, F5::new(1)); + assert_eq!(a / b, F5::new(4)); + assert_eq!(-a, F5::new(3)); + } + + #[test] + fn test_finite_prime_field_pow() { + type F7 = FinitePrimeField<7>; + + let a = F7::new(3); + assert_eq!(a.pow(0), F7::one()); + assert_eq!(a.pow(1), a); + assert_eq!(a.pow(2), F7::new(2)); + assert_eq!(a.pow(6), F7::one()); + } + + #[test] + fn test_finite_prime_field_inv() { + type F11 = FinitePrimeField<11>; + + let a = F11::new(2); + assert_eq!(a.inv(), F11::new(6)); + assert_eq!(F11::zero().mul_inverse(), None); + } + + #[test] + fn test_finite_prime_field_primitive_element() { + assert!(F5::is_primitive_element(&F5::new(2))); + assert!(!F5::is_primitive_element(&F5::new(1))); + } + + #[test] + #[should_panic(expected = "P must be prime")] + fn test_non_prime_field() { + let _ = FinitePrimeField::<4>::new(1); + } +} diff --git a/src/concrete_polynomial.rs b/src/concrete_polynomial.rs new file mode 100644 index 0000000..5128aa5 --- /dev/null +++ b/src/concrete_polynomial.rs @@ -0,0 +1,441 @@ +use crate::{Associative, Commutative, Distributive, EuclideanDomain, Field, FiniteField, Set}; +use num_traits::{One, Zero}; +use std::fmt; +use std::fmt::{Debug, Display}; +use std::ops::{Add, Div, Mul, Neg, Rem, Sub}; + +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct PolynomialField { + coeffs: [F; N], +} + +impl PolynomialField { + pub fn new(coeffs: [F; N]) -> Self { + Self { coeffs } + } + + pub fn degree(&self) -> usize { + self.coeffs + .iter() + .rev() + .position(|&c| !c.is_zero()) + .map_or(0, |p| N - 1 - p) + } + + pub fn leading_coefficient(&self) -> F { + self.coeffs[self.degree()] + } + + pub fn modulus() -> Self { + let mut coeffs = [F::zero(); N]; + coeffs[0] = F::one(); + coeffs[1] = F::one(); + coeffs[N - 1] = F::one(); + Self::new(coeffs) + } + + fn inv(&self) -> Self { + if self.is_zero() { + panic!("attempt to invert zero"); + } + // Use Fermat's Little Theorem for inversion: a^(p^n - 2) mod p^n + self.pow(Self::order() - 2) + } + + fn pow(&self, mut exponent: u64) -> Self { + let mut base = *self; + let mut result = Self::one(); + while exponent > 0 { + if exponent & 1 == 1 { + result = result * base; + } + base = base * base; + exponent >>= 1; + } + result + } +} + +impl Debug for PolynomialField { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "PolynomialField(")?; + let terms: Vec = self + .coeffs + .iter() + .enumerate() + .rev() + .filter(|(_, &c)| !c.is_zero()) + .map(|(i, c)| match i { + 0 => format!("{:?}", c), + 1 => format!("{:?}x", c), + _ => format!("{:?}x^{}", c, i), + }) + .collect(); + write!(f, "{})", terms.join(" + ")) + } +} + +impl Display for PolynomialField { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +impl Add for PolynomialField { + type Output = Self; + fn add(self, rhs: Self) -> Self::Output { + let mut coeffs = [F::zero(); N]; + for i in 0..N { + coeffs[i] = self.coeffs[i] + rhs.coeffs[i]; + } + Self::new(coeffs) + } +} + +impl Sub for PolynomialField { + type Output = Self; + fn sub(self, rhs: Self) -> Self::Output { + let mut coeffs = [F::zero(); N]; + for i in 0..N { + coeffs[i] = self.coeffs[i] - rhs.coeffs[i]; + } + Self::new(coeffs) + } +} + +impl Mul for PolynomialField { + type Output = Self; + fn mul(self, rhs: Self) -> Self::Output { + let mut result = [F::zero(); N]; + for i in 0..N { + for j in 0..N { + if i + j < N { + result[i + j] = result[i + j] + self.coeffs[i] * rhs.coeffs[j]; + } + } + } + Self::new(result) % Self::modulus() + } +} + +impl Div for PolynomialField { + type Output = Self; + fn div(self, rhs: Self) -> Self::Output { + self * rhs.inv() + } +} + +impl Neg for PolynomialField { + type Output = Self; + fn neg(self) -> Self::Output { + let mut coeffs = [F::zero(); N]; + for i in 0..N { + coeffs[i] = -self.coeffs[i]; + } + Self::new(coeffs) + } +} + +impl Rem for PolynomialField { + type Output = Self; + fn rem(self, rhs: Self) -> Self::Output { + let mut r = self; + while r.degree() >= rhs.degree() { + let lead_r = r.leading_coefficient(); + let lead_rhs = rhs.leading_coefficient(); + let mut t = Self::zero(); + t.coeffs[r.degree() - rhs.degree()] = lead_r / lead_rhs; + r = r - (t * rhs); + } + r + } +} + +impl Zero for PolynomialField { + fn zero() -> Self { + Self::new([F::zero(); N]) + } + + fn is_zero(&self) -> bool { + self.coeffs.iter().all(|&c| c.is_zero()) + } +} + +impl One for PolynomialField { + fn one() -> Self { + let mut coeffs = [F::zero(); N]; + coeffs[0] = F::one(); + Self::new(coeffs) + } +} + +impl Set for PolynomialField { + type Element = Self; + + fn is_empty(&self) -> bool { + false + } + fn contains(&self, _element: &Self::Element) -> bool { + true + } + fn empty() -> Self { + Self::zero() + } + fn singleton(element: Self::Element) -> Self { + element + } + fn union(&self, _other: &Self) -> Self { + *self + } + fn intersection(&self, other: &Self) -> Self { + if self == other { + *self + } else { + Self::empty() + } + } + fn difference(&self, other: &Self) -> Self { + if self == other { + Self::empty() + } else { + *self + } + } + fn symmetric_difference(&self, other: &Self) -> Self { + if self == other { + Self::empty() + } else { + *self + } + } + fn is_subset(&self, _other: &Self) -> bool { + true + } + fn is_equal(&self, other: &Self) -> bool { + self == other + } + fn cardinality(&self) -> Option { + Some(F::order().pow(N as u32) as usize) + } + fn is_finite(&self) -> bool { + true + } +} + +impl Commutative for PolynomialField {} +impl Associative for PolynomialField {} +impl Distributive for PolynomialField {} + +impl num_traits::Euclid for PolynomialField { + fn div_euclid(&self, v: &Self) -> Self { + *self / *v + } + fn rem_euclid(&self, v: &Self) -> Self { + *self % *v + } +} + +impl EuclideanDomain for PolynomialField { + fn gcd(mut a: Self, mut b: Self) -> Self { + while !b.is_zero() { + let r = a % b; + a = b; + b = r; + } + a + } +} + +impl Field for PolynomialField {} + +impl FiniteField for PolynomialField { + fn characteristic() -> u64 { + F::characteristic() + } + + fn order() -> u64 { + F::order().pow(N as u32) + } + + fn is_primitive_element(element: &Self) -> bool { + if element.is_zero() || element.is_one() { + return false; + } + let order = Self::order(); + let mut x = *element; + for i in 1..100 { + // Limit iterations for practicality + if x.is_one() { + return i == order - 1; + } + x = x * *element; + if i % 10 == 0 && x == *element { + return false; + } + } + false // Assume not primitive if not determined after 100 iterations + } + + fn pow(&self, exponent: u64) -> Self { + self.pow(exponent) + } + + fn mul_inverse(&self) -> Option { + if self.is_zero() { + None + } else { + Some(self.inv()) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::concrete_finite::FinitePrimeField; + use std::time::{Duration, Instant}; + + type F5 = FinitePrimeField<5>; + type F5_3 = PolynomialField; + + fn run_with_timeout(f: F, timeout: Duration) -> R + where + F: FnOnce() -> R + Send + 'static, + R: Send + 'static, + { + use std::sync::mpsc::channel; + use std::thread; + + let (tx, rx) = channel(); + let handle = thread::spawn(move || { + let result = f(); + tx.send(result).unwrap(); + }); + + match rx.recv_timeout(timeout) { + Ok(result) => { + handle.join().unwrap(); + result + } + Err(_) => panic!("Test timed out after {:?}", timeout), + } + } + + #[test] + fn test_polynomial_field_arithmetic() { + run_with_timeout( + || { + let a = F5_3::new([F5::new(1), F5::new(2), F5::new(3)]); + let b = F5_3::new([F5::new(4), F5::new(0), F5::new(1)]); + + let sum = a + b; + let diff = a - b; + let prod = a * b; + let quot = a / b; + + assert_eq!(sum, F5_3::new([F5::new(0), F5::new(2), F5::new(4)])); + assert_eq!(diff, F5_3::new([F5::new(2), F5::new(2), F5::new(2)])); + assert_eq!(prod, F5_3::new([F5::new(4), F5::new(3), F5::new(2)])); + assert_eq!(quot * b, a); + }, + Duration::from_secs(1), + ); + } + + #[test] + fn test_polynomial_field_inv() { + run_with_timeout( + || { + let a = F5_3::new([F5::new(1), F5::new(2), F5::new(3)]); + let a_inv = a.inv(); + assert_eq!(a * a_inv, F5_3::one()); + }, + Duration::from_secs(1), + ); + } + + #[test] + fn test_polynomial_field_pow() { + run_with_timeout( + || { + let a = F5_3::new([F5::new(2), F5::new(1), F5::new(0)]); + assert_eq!(a.pow(0), F5_3::one()); + assert_eq!(a.pow(1), a); + assert_eq!(a.pow(5), a * a * a * a * a); + }, + Duration::from_secs(1), + ); + } + + #[test] + fn test_polynomial_field_primitive_element() { + run_with_timeout( + || { + let a = F5_3::new([F5::new(2), F5::new(1), F5::new(0)]); + let is_primitive = F5_3::is_primitive_element(&a); + println!("Is primitive element: {}", is_primitive); + }, + Duration::from_secs(1), + ); + } + + #[test] + fn test_field_properties() { + run_with_timeout( + || { + let a = F5_3::new([F5::new(1), F5::new(2), F5::new(3)]); + let b = F5_3::new([F5::new(4), F5::new(0), F5::new(1)]); + let c = F5_3::new([F5::new(2), F5::new(1), F5::new(0)]); + + assert_eq!((a + b) + c, a + (b + c)); + assert_eq!((a * b) * c, a * (b * c)); + assert_eq!(a + b, b + a); + assert_eq!(a * b, b * a); + assert_eq!(a * (b + c), (a * b) + (a * c)); + assert_eq!(a + F5_3::zero(), a); + assert_eq!(a * F5_3::one(), a); + assert_eq!(a + (-a), F5_3::zero()); + assert_eq!(a * a.inv(), F5_3::one()); + }, + Duration::from_secs(1), + ); + } + + #[test] + fn test_field_order() { + let order = F5_3::order(); + assert_eq!(order, 125); // 5^3 = 125 + } + + #[test] + fn test_polynomial_degree() { + run_with_timeout( + || { + let a = F5_3::new([F5::new(1), F5::new(2), F5::new(3)]); + assert_eq!(a.degree(), 2); + let b = F5_3::new([F5::new(1), F5::new(2), F5::new(0)]); + assert_eq!(b.degree(), 1); + let c = F5_3::new([F5::new(1), F5::new(0), F5::new(0)]); + assert_eq!(c.degree(), 0); + let d = F5_3::zero(); + assert_eq!(d.degree(), 0); + }, + Duration::from_secs(1), + ); + } + + // ... [Include the rest of the tests from the previous response] ... + + #[test] + fn test_polynomial_large_exponent() { + run_with_timeout( + || { + let a = F5_3::new([F5::new(2), F5::new(1), F5::new(0)]); + let large_exp = 1_000_000_007; // A large prime number + let result = a.pow(large_exp); + assert!(!result.is_zero()); + }, + Duration::from_secs(5), + ); // Allow more time for this test + } +} diff --git a/src/euclidean_domain.rs b/src/euclidean_domain.rs index b889095..03723ea 100644 --- a/src/euclidean_domain.rs +++ b/src/euclidean_domain.rs @@ -10,25 +10,6 @@ use crate::PrincipalIdealDomain; /// 1. βˆ€a, b ∈ R, b β‰  0, βˆƒ!q, r ∈ R : a = bq + r ∧ (r = 0 ∨ Ο†(r) < Ο†(b)) (Division with Remainder) /// 2. βˆ€a, b ∈ R\{0} : Ο†(a) ≀ Ο†(ab) (Multiplicative Property) pub trait EuclideanDomain: PrincipalIdealDomain { - /// The Euclidean function Ο†: R\{0} β†’ β„•β‚€ - /// Returns None if the input is zero. - fn euclidean_function(&self) -> Option; - /// Computes the greatest common divisor (GCD) using the Euclidean algorithm. - fn gcd(mut a: Self, mut b: Self) -> Self - where - Self: Sized + Clone, - { - if b.is_zero() { - return a; - } - - while !b.is_zero() { - let r = a.rem_euclid(&b); - a = b; - b = r; - } - - a - } + fn gcd(a: Self, b: Self) -> Self; } diff --git a/src/extension_tower.rs b/src/extension_tower.rs index 9f02ec7..aad6e0d 100644 --- a/src/extension_tower.rs +++ b/src/extension_tower.rs @@ -32,11 +32,8 @@ pub trait FieldExtensionTower: FieldExtension { /// Computes the absolute degree of the entire tower extension. /// [Fβ‚™:Fβ‚€] = [Fβ‚™:Fₙ₋₁] Β· [Fₙ₋₁:Fβ‚™β‚‹β‚‚] Β· ... Β· [Fβ‚‚:F₁] Β· [F₁:Fβ‚€] - fn absolute_degree() -> Option { - self.extension_degrees() - .fold(Some(1), |acc, deg| { - acc.and_then(|a| deg.map(|d| a * d)) - }) + fn absolute_degree(&self) -> Option { + Self::extension_degrees().fold(Some(1), |acc, deg| acc.and_then(|a| deg.map(|d| a * d))) } /// Returns an iterator over the minimal polynomials of each extension in the tower. @@ -51,22 +48,16 @@ pub trait FieldExtensionTower: FieldExtension { fn project_from_top(element: &Self::Level, to_level: usize) -> Option; /// Checks if the entire tower consists of normal extensions. - fn is_normal() -> bool { - self.fields().all(|field| field.is_normal()) - } + fn is_normal(&self) -> bool; /// Checks if the entire tower consists of separable extensions. - fn is_separable() -> bool { - self.fields().all(|field| field.is_separable()) - } + fn is_separable(&self) -> bool; /// Checks if the entire tower consists of algebraic extensions. - fn is_algebraic() -> bool { - self.fields().all(|field| field.is_algebraic()) - } + fn is_algebraic(&self) -> bool; /// Checks if the tower is Galois (normal and separable). - fn is_galois() -> bool { + fn is_galois(&self) -> bool { self.is_normal() && self.is_separable() } @@ -95,4 +86,4 @@ pub trait FieldExtensionTower: FieldExtension { // 4. Other consistency checks unimplemented!("Axiom checking not implemented") } -} \ No newline at end of file +} diff --git a/src/field.rs b/src/field.rs index 80166c7..9d406a1 100644 --- a/src/field.rs +++ b/src/field.rs @@ -1,5 +1,5 @@ -use crate::EuclideanDomain; -use crate::{ClosedDiv}; +use crate::ClosedDiv; +use crate::{ClosedSub, EuclideanDomain}; /// Represents a Field, an algebraic structure that is a Euclidean domain where every non-zero element /// has a multiplicative inverse. @@ -13,5 +13,4 @@ use crate::{ClosedDiv}; /// 1. (F, +, Β·) is a Euclidean domain /// 2. Every non-zero element has a multiplicative inverse /// 3. 0 β‰  1 (the additive identity is not equal to the multiplicative identity) -pub trait Field: EuclideanDomain + ClosedDiv { -} +pub trait Field: EuclideanDomain + ClosedDiv + ClosedSub {} diff --git a/src/field_extension.rs b/src/field_extension.rs index 6286619..69cc4c1 100644 --- a/src/field_extension.rs +++ b/src/field_extension.rs @@ -1,4 +1,3 @@ -use std::fmt::Debug; use crate::Field; /// Represents a field extension. diff --git a/src/finite_field.rs b/src/finite_field.rs index ff5feae..95cf297 100644 --- a/src/finite_field.rs +++ b/src/finite_field.rs @@ -14,7 +14,7 @@ use crate::Field; /// 4. The additive identity is 0 /// 5. The multiplicative identity is 1 /// 6. Every non-zero element has a unique multiplicative inverse -pub trait FinitePrimeField: Field { +pub trait FiniteField: Field { /// Returns the characteristic of the field, which is the prime number p. fn characteristic() -> u64; diff --git a/src/lib.rs b/src/lib.rs index 484b596..35a6d54 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -99,23 +99,25 @@ mod concrete; // Implemented traits mod abelian; mod commutative_ring; +mod concrete_finite; +mod concrete_polynomial; mod euclidean_domain; +mod extension_tower; mod field; mod field_extension; mod finite_field; mod group; -mod real_field; mod integral_domain; mod magma; mod monoid; mod operator; mod pid; +mod real_field; mod ring; mod semigroup; mod semiring; mod set; mod ufd; -mod extension_tower; // Not yet implemented // mod alg_loop; // mod quasigroup; diff --git a/src/pid.rs b/src/pid.rs index 80427d2..880b998 100644 --- a/src/pid.rs +++ b/src/pid.rs @@ -17,7 +17,6 @@ impl PrincipalIdealDomain for T where T: UniqueFactorizationDomain + Euclid { #[cfg(test)] mod tests { use crate::concrete::Z5; - use crate::ClosedRemEuclid; use crate::PrincipalIdealDomain; use num_traits::Zero; @@ -41,40 +40,7 @@ mod tests { } } - #[test] - fn test_z5_gcd() { - for i in 0..5 { - for j in 0..5 { - let a = Z5::new(i); - let b = Z5::new(j); - let g = gcd(a, b); - - // Check that g divides both a and b - if !g.is_zero() { - assert_eq!(a.rem_euclid(g), Z5::zero()); - assert_eq!(b.rem_euclid(g), Z5::zero()); - } - - // Check that g is the greatest such divisor - for k in 1..5 { - let d = Z5::new(k); - if !d.is_zero() && a.rem_euclid(d) == Z5::zero() && b.rem_euclid(d) == Z5::zero() { - assert!(g.0 >= d.0); - } - } - } - } - } - - fn gcd(a: Z5, b: Z5) -> Z5 { - if a.is_zero() && b.is_zero() { - Z5::zero() - } else if b.is_zero() { - a - } else { - gcd(b, a.rem_euclid(b)) - } - } + // TODO(Test GCD) #[test] fn test_z5_principal_ideals() { diff --git a/src/real_field.rs b/src/real_field.rs index a5b0dc5..471db4c 100644 --- a/src/real_field.rs +++ b/src/real_field.rs @@ -52,4 +52,3 @@ pub trait RealField: Field + PartialOrd + Ord { /// Checks if the number is NaN (Not a Number). fn is_nan(&self) -> bool; } - From 5d042323cb84001f85245166aa5126f67ccdd28d Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Sat, 13 Jul 2024 06:11:09 -0400 Subject: [PATCH 13/21] feat: abstract traits --- src/abelian.rs | 128 ----- src/commutative_ring.rs | 103 ---- src/concrete.rs | 261 --------- src/concrete_finite.rs | 306 ----------- src/concrete_polynomial.rs | 441 --------------- src/euclidean_domain.rs | 15 - src/extension_tower.rs | 89 --- src/field.rs | 16 - src/field_extension.rs | 88 --- src/finite_field.rs | 52 -- src/group.rs | 116 ---- src/integral_domain.rs | 54 -- src/lib.rs | 1056 ++++++++++++++++++++++++++++++++++-- src/magma.rs | 140 ----- src/monoid.rs | 131 ----- src/operator.rs | 368 ------------- src/pid.rs | 67 --- src/real_field.rs | 54 -- src/ring.rs | 104 ---- src/semigroup.rs | 90 --- src/semiring.rs | 111 ---- src/set.rs | 154 ------ src/ufd.rs | 87 --- 23 files changed, 1005 insertions(+), 3026 deletions(-) delete mode 100644 src/abelian.rs delete mode 100644 src/commutative_ring.rs delete mode 100644 src/concrete.rs delete mode 100644 src/concrete_finite.rs delete mode 100644 src/concrete_polynomial.rs delete mode 100644 src/euclidean_domain.rs delete mode 100644 src/extension_tower.rs delete mode 100644 src/field.rs delete mode 100644 src/field_extension.rs delete mode 100644 src/finite_field.rs delete mode 100644 src/group.rs delete mode 100644 src/integral_domain.rs delete mode 100644 src/magma.rs delete mode 100644 src/monoid.rs delete mode 100644 src/operator.rs delete mode 100644 src/pid.rs delete mode 100644 src/real_field.rs delete mode 100644 src/ring.rs delete mode 100644 src/semigroup.rs delete mode 100644 src/semiring.rs delete mode 100644 src/set.rs delete mode 100644 src/ufd.rs diff --git a/src/abelian.rs b/src/abelian.rs deleted file mode 100644 index b1d6024..0000000 --- a/src/abelian.rs +++ /dev/null @@ -1,128 +0,0 @@ -use crate::group::{AdditiveGroup, MultiplicativeGroup}; -use crate::Commutative; - -/// Represents an Additive Abelian Group, an algebraic structure with a commutative addition operation. -/// -/// An additive abelian group (G, +) is an additive group that also satisfies: -/// - Commutativity: βˆ€ a, b ∈ G, a + b = b + a -/// -/// Formal Definition: -/// Let (G, +) be an additive abelian group. Then: -/// 1. βˆ€ a, b, c ∈ G, (a + b) + c = a + (b + c) (associativity) -/// 2. βˆƒ 0 ∈ G, βˆ€ a ∈ G, 0 + a = a + 0 = a (identity) -/// 3. βˆ€ a ∈ G, βˆƒ -a ∈ G, a + (-a) = (-a) + a = 0 (inverse) -/// 4. βˆ€ a, b ∈ G, a + b = b + a (commutativity) -pub trait AdditiveAbelianGroup: AdditiveGroup + Commutative {} - -/// Represents a Multiplicative Abelian Group, an algebraic structure with a commutative multiplication operation. -/// -/// A multiplicative abelian group (G, βˆ™) is a multiplicative group that also satisfies: -/// - Commutativity: βˆ€ a, b ∈ G, a βˆ™ b = b βˆ™ a -/// -/// Formal Definition: -/// Let (G, βˆ™) be a multiplicative abelian group. Then: -/// 1. βˆ€ a, b, c ∈ G, (a βˆ™ b) βˆ™ c = a βˆ™ (b βˆ™ c) (associativity) -/// 2. βˆƒ 1 ∈ G, βˆ€ a ∈ G, 1 βˆ™ a = a βˆ™ 1 = a (identity) -/// 3. βˆ€ a ∈ G, βˆƒ a⁻¹ ∈ G, a βˆ™ a⁻¹ = a⁻¹ βˆ™ a = 1 (inverse) -/// 4. βˆ€ a, b ∈ G, a βˆ™ b = b βˆ™ a (commutativity) -pub trait MultiplicativeAbelianGroup: MultiplicativeGroup + Commutative {} - -impl AdditiveAbelianGroup for T where T: AdditiveGroup + Commutative {} -impl MultiplicativeAbelianGroup for T where T: MultiplicativeGroup + Commutative {} - -#[cfg(test)] -mod tests { - use super::*; - use crate::concrete::Z5; - use num_traits::{Inv, One, Zero}; - - #[test] - fn test_z5_additive_abelian_group() { - // Test commutativity - for i in 0..5 { - for j in 0..5 { - let a = Z5::new(i); - let b = Z5::new(j); - assert_eq!(a + b, b + a); - } - } - - // Test associativity (inherited from AdditiveGroup) - for i in 0..5 { - for j in 0..5 { - for k in 0..5 { - let a = Z5::new(i); - let b = Z5::new(j); - let c = Z5::new(k); - assert_eq!((a + b) + c, a + (b + c)); - } - } - } - - // Test identity (inherited from AdditiveGroup) - let zero = Z5::zero(); - for i in 0..5 { - let a = Z5::new(i); - assert_eq!(a + zero, a); - assert_eq!(zero + a, a); - } - - // Test inverse (inherited from AdditiveGroup) - for i in 0..5 { - let a = Z5::new(i); - let neg_a = -a; - assert_eq!(a + neg_a, zero); - assert_eq!(neg_a + a, zero); - } - } - - #[test] - fn test_z5_multiplicative_abelian_group() { - // Test commutativity - for i in 1..5 { - // Skip 0 as it's not part of the multiplicative group - for j in 1..5 { - let a = Z5::new(i); - let b = Z5::new(j); - assert_eq!(a * b, b * a); - } - } - - // Test associativity (inherited from MultiplicativeGroup) - for i in 1..5 { - for j in 1..5 { - for k in 1..5 { - let a = Z5::new(i); - let b = Z5::new(j); - let c = Z5::new(k); - assert_eq!((a * b) * c, a * (b * c)); - } - } - } - - // Test identity (inherited from MultiplicativeGroup) - let one = Z5::one(); - for i in 1..5 { - let a = Z5::new(i); - assert_eq!(a * one, a); - assert_eq!(one * a, a); - } - - // Test inverse (inherited from MultiplicativeGroup) - for i in 1..5 { - let a = Z5::new(i); - let inv_a = a.inv(); - assert_eq!(a * inv_a, one); - assert_eq!(inv_a * a, one); - } - } - - #[test] - fn test_z5_implements_abelian_groups() { - fn assert_additive_abelian_group() {} - fn assert_multiplicative_abelian_group() {} - - assert_additive_abelian_group::(); - assert_multiplicative_abelian_group::(); - } -} diff --git a/src/commutative_ring.rs b/src/commutative_ring.rs deleted file mode 100644 index 110257b..0000000 --- a/src/commutative_ring.rs +++ /dev/null @@ -1,103 +0,0 @@ -use crate::ring::Ring; -use crate::Commutative; - -/// Represents a Commutative Ring, an algebraic structure where multiplication is commutative. -/// -/// A commutative ring (R, +, Β·) is a ring that also satisfies: -/// - Commutativity of multiplication: βˆ€ a, b ∈ R, a Β· b = b Β· a -/// -/// Formal Definition: -/// Let (R, +, Β·) be a commutative ring. Then: -/// 1. (R, +, Β·) is a ring -/// 2. βˆ€ a, b ∈ R, a Β· b = b Β· a (commutativity of multiplication) -pub trait CommutativeRing: Ring + Commutative {} - -impl CommutativeRing for T where T: Ring + Commutative {} - -#[cfg(test)] -mod tests { - use super::*; - use crate::concrete::Z5; - use num_traits::{One, Zero}; - - #[test] - fn test_z5_commutative_ring() { - // Test commutativity of multiplication - for i in 0..5 { - for j in 0..5 { - let a = Z5::new(i); - let b = Z5::new(j); - assert_eq!(a * b, b * a); - } - } - } - - #[test] - fn test_z5_ring_properties() { - // Test additive properties - for i in 0..5 { - for j in 0..5 { - let a = Z5::new(i); - let b = Z5::new(j); - - // Commutativity of addition - assert_eq!(a + b, b + a); - - // Associativity of addition - let c = Z5::new((i + j) % 5); - assert_eq!((a + b) + c, a + (b + c)); - } - } - - // Test multiplicative properties - for i in 0..5 { - for j in 0..5 { - let a = Z5::new(i); - let b = Z5::new(j); - - // Associativity of multiplication - let c = Z5::new((i * j) % 5); - assert_eq!((a * b) * c, a * (b * c)); - } - } - - // Test distributive property - for i in 0..5 { - for j in 0..5 { - for k in 0..5 { - let a = Z5::new(i); - let b = Z5::new(j); - let c = Z5::new(k); - - assert_eq!(a * (b + c), (a * b) + (a * c)); - assert_eq!((b + c) * a, (b * a) + (c * a)); - } - } - } - - // Test additive identity and inverse - let zero = Z5::zero(); - for i in 0..5 { - let a = Z5::new(i); - assert_eq!(a + zero, a); - assert_eq!(zero + a, a); - let neg_a = -a; - assert_eq!(a + neg_a, zero); - assert_eq!(neg_a + a, zero); - } - - // Test multiplicative identity - let one = Z5::one(); - for i in 0..5 { - let a = Z5::new(i); - assert_eq!(a * one, a); - assert_eq!(one * a, a); - } - } - - #[test] - fn test_z5_implements_commutative_ring() { - fn assert_commutative_ring() {} - assert_commutative_ring::(); - } -} diff --git a/src/concrete.rs b/src/concrete.rs deleted file mode 100644 index 12026a1..0000000 --- a/src/concrete.rs +++ /dev/null @@ -1,261 +0,0 @@ -use crate::set::Set; -use crate::{Associative, Commutative, Distributive}; -use num_traits::{Euclid, Inv, One, Zero}; -use std::cmp::Ordering; -use std::ops::{Add, Div, Mul, Neg, Rem, Sub}; - -// This is a very sloppy and not optimal implementation of Z5. -// But seems correct overall. - -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct Z5(pub(crate) u8); - -impl Z5 { - pub fn new(value: u8) -> Self { - Z5(value % 5) - } -} - -impl Set for Z5 { - type Element = Z5; - - fn is_empty(&self) -> bool { - false - } - - fn contains(&self, element: &Self::Element) -> bool { - self == element - } - - fn empty() -> Self { - Z5(0) - } - - fn singleton(element: Self::Element) -> Self { - element - } - - fn union(&self, other: &Self) -> Self { - if self == other { - *self - } else { - Z5::new(self.0.min(other.0)) - } - } - - fn intersection(&self, other: &Self) -> Self { - if self == other { - *self - } else { - Z5::new(0) - } - } - - fn difference(&self, other: &Self) -> Self { - if self == other { - Z5::new(0) - } else { - *self - } - } - - fn symmetric_difference(&self, other: &Self) -> Self { - if self == other { - Z5::new(0) - } else { - Z5::new(self.0.max(other.0)) - } - } - - fn is_subset(&self, other: &Self) -> bool { - self == other - } - - fn is_equal(&self, other: &Self) -> bool { - self == other - } - - fn cardinality(&self) -> Option { - Some(5) - } - - fn is_finite(&self) -> bool { - true - } -} - -impl Add for Z5 { - type Output = Self; - - fn add(self, rhs: Self) -> Self::Output { - Z5::new((self.0 + rhs.0) % 5) - } -} - -impl Mul for Z5 { - type Output = Self; - - fn mul(self, rhs: Self) -> Self::Output { - Z5::new((self.0 * rhs.0) % 5) - } -} - -impl Neg for Z5 { - type Output = Self; - - fn neg(self) -> Self::Output { - Z5::new(5 - self.0) - } -} - -impl Inv for Z5 { - type Output = Self; - - fn inv(self) -> Self::Output { - if self.0 == 0 { - panic!("Cannot invert zero in Z5"); - } - for i in 1..5 { - if (self.0 * i) % 5 == 1 { - return Z5::new(i); - } - } - unreachable!() - } -} - -impl Div for Z5 { - type Output = Self; - - fn div(self, rhs: Self) -> Self::Output { - self * rhs.inv() - } -} - -impl Sub for Z5 { - type Output = Self; - - fn sub(self, rhs: Self) -> Self::Output { - Z5::new((self.0 + 5 - rhs.0) % 5) - } -} - -impl Rem for Z5 { - type Output = Self; - - fn rem(self, rhs: Self) -> Self::Output { - Z5::new(self.0 % rhs.0) - } -} - -impl Zero for Z5 { - fn zero() -> Self { - Z5::new(0) - } - - fn is_zero(&self) -> bool { - self.0 == 0 - } -} - -impl One for Z5 { - fn one() -> Self { - Z5::new(1) - } -} - -impl Euclid for Z5 { - fn div_euclid(&self, v: &Self) -> Self { - if v.is_zero() { - panic!("attempt to divide by zero"); - } - let q = (self.0 as i32 * v.inv().0 as i32) % 5; - Z5::new(q as u8) - } - - fn rem_euclid(&self, v: &Self) -> Self { - if v.is_zero() { - panic!("attempt to divide by zero"); - } - Z5::new(self.0 % v.0) - } -} - -impl Z5 { - pub fn div_rem_euclid(&self, v: &Self) -> (Self, Self) { - let q = self.div_euclid(v); - let r = *self - q * *v; - (q, r) - } -} - -impl PartialOrd for Z5 { - fn partial_cmp(&self, other: &Self) -> Option { - self.0.partial_cmp(&other.0) - } -} - -impl Ord for Z5 { - fn cmp(&self, other: &Self) -> Ordering { - self.0.cmp(&other.0) - } -} - -impl Associative for Z5 {} -impl Commutative for Z5 {} -impl Distributive for Z5 {} - -#[derive(Clone, PartialEq, Debug)] -pub struct InfiniteRealSet; - -impl Set for InfiniteRealSet { - type Element = f64; - - fn is_empty(&self) -> bool { - false - } - - fn contains(&self, _element: &Self::Element) -> bool { - true - } - - fn empty() -> Self { - InfiniteRealSet - } - - fn singleton(_element: Self::Element) -> Self { - InfiniteRealSet - } - - fn union(&self, _other: &Self) -> Self { - InfiniteRealSet - } - - fn intersection(&self, _other: &Self) -> Self { - InfiniteRealSet - } - - fn difference(&self, _other: &Self) -> Self { - InfiniteRealSet - } - - fn symmetric_difference(&self, _other: &Self) -> Self { - InfiniteRealSet - } - - fn is_subset(&self, _other: &Self) -> bool { - true - } - - fn is_equal(&self, _other: &Self) -> bool { - true - } - - fn cardinality(&self) -> Option { - None - } - - fn is_finite(&self) -> bool { - false - } -} diff --git a/src/concrete_finite.rs b/src/concrete_finite.rs deleted file mode 100644 index ec0d2ba..0000000 --- a/src/concrete_finite.rs +++ /dev/null @@ -1,306 +0,0 @@ -use crate::{Associative, Commutative, Distributive, EuclideanDomain, Field, FiniteField, Set}; -use num_traits::{Inv, One, Zero}; -use std::fmt::{self, Debug, Display}; -use std::ops::{Add, Div, Mul, Neg, Rem, Sub}; - -#[derive(Clone, Copy, PartialEq, Eq)] -pub struct FinitePrimeField { - value: u64, -} - -impl FinitePrimeField

{ - pub fn new(value: u64) -> Self { - assert!(Self::is_prime(P), "P must be prime"); - Self { value: value % P } - } - - fn is_prime(n: u64) -> bool { - if n <= 1 { - return false; - } - if n == 2 { - return true; - } - if n % 2 == 0 { - return false; - } - let sqrt_n = (n as f64).sqrt() as u64; - for i in (3..=sqrt_n).step_by(2) { - if n % i == 0 { - return false; - } - } - true - } - - pub fn value(&self) -> u64 { - self.value - } -} - -impl Debug for FinitePrimeField

{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}(mod {})", self.value, P) - } -} - -impl Display for FinitePrimeField

{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.value) - } -} - -impl Add for FinitePrimeField

{ - type Output = Self; - fn add(self, rhs: Self) -> Self::Output { - Self::new(self.value + rhs.value) - } -} - -impl Sub for FinitePrimeField

{ - type Output = Self; - fn sub(self, rhs: Self) -> Self::Output { - Self::new(self.value + P - rhs.value) - } -} - -impl Mul for FinitePrimeField

{ - type Output = Self; - fn mul(self, rhs: Self) -> Self::Output { - Self::new(self.value * rhs.value) - } -} - -impl Div for FinitePrimeField

{ - type Output = Self; - fn div(self, rhs: Self) -> Self::Output { - self * rhs.inv() - } -} - -impl Neg for FinitePrimeField

{ - type Output = Self; - fn neg(self) -> Self::Output { - Self::new(P - self.value) - } -} - -impl Rem for FinitePrimeField

{ - type Output = Self; - fn rem(self, rhs: Self) -> Self::Output { - Self::new(self.value % rhs.value) - } -} - -impl Zero for FinitePrimeField

{ - fn zero() -> Self { - Self::new(0) - } - - fn is_zero(&self) -> bool { - self.value == 0 - } -} - -impl One for FinitePrimeField

{ - fn one() -> Self { - Self::new(1) - } -} - -impl Inv for FinitePrimeField

{ - type Output = Self; - - fn inv(self) -> Self::Output { - if self.is_zero() { - panic!("attempt to invert zero"); - } - self.pow(P - 2) - } -} - -impl Set for FinitePrimeField

{ - type Element = Self; - - fn is_empty(&self) -> bool { - false - } - - fn contains(&self, element: &Self::Element) -> bool { - element.value < P - } - - fn empty() -> Self { - Self::zero() - } - - fn singleton(element: Self::Element) -> Self { - element - } - - fn union(&self, _other: &Self) -> Self { - *self - } - - fn intersection(&self, other: &Self) -> Self { - if self == other { - *self - } else { - Self::empty() - } - } - - fn difference(&self, other: &Self) -> Self { - if self == other { - Self::empty() - } else { - *self - } - } - - fn symmetric_difference(&self, other: &Self) -> Self { - if self == other { - Self::empty() - } else { - *self - } - } - - fn is_subset(&self, _other: &Self) -> bool { - true - } - - fn is_equal(&self, other: &Self) -> bool { - self == other - } - - fn cardinality(&self) -> Option { - Some(P as usize) - } - - fn is_finite(&self) -> bool { - true - } -} - -impl Commutative for FinitePrimeField

{} -impl Associative for FinitePrimeField

{} -impl Distributive for FinitePrimeField

{} - -impl num_traits::Euclid for FinitePrimeField

{ - fn div_euclid(&self, v: &Self) -> Self { - *self / *v - } - - fn rem_euclid(&self, v: &Self) -> Self { - *self % *v - } -} - -impl EuclideanDomain for FinitePrimeField

{ - fn gcd(a: Self, b: Self) -> Self { - if b.is_zero() { - a - } else { - Self::gcd(b, a % b) - } - } -} - -impl Field for FinitePrimeField

{} - -impl FiniteField for FinitePrimeField

{ - fn characteristic() -> u64 { - P - } - - fn order() -> u64 { - P - } - - fn is_primitive_element(element: &Self) -> bool { - if element.is_zero() { - return false; - } - let mut x = *element; - for _ in 1..P - 1 { - if x.is_one() { - return false; - } - x = x * *element; - } - x.is_one() - } - - fn pow(&self, mut exponent: u64) -> Self { - let mut base = *self; - let mut result = Self::one(); - while exponent > 0 { - if exponent % 2 == 1 { - result = result * base; - } - exponent /= 2; - base = base * base; - } - result - } - - fn mul_inverse(&self) -> Option { - if self.is_zero() { - None - } else { - Some(self.inv()) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - type F5 = FinitePrimeField<5>; - - #[test] - fn test_finite_prime_field_arithmetic() { - let a = F5::new(2); - let b = F5::new(3); - - assert_eq!(a + b, F5::new(0)); - assert_eq!(a - b, F5::new(4)); - assert_eq!(a * b, F5::new(1)); - assert_eq!(a / b, F5::new(4)); - assert_eq!(-a, F5::new(3)); - } - - #[test] - fn test_finite_prime_field_pow() { - type F7 = FinitePrimeField<7>; - - let a = F7::new(3); - assert_eq!(a.pow(0), F7::one()); - assert_eq!(a.pow(1), a); - assert_eq!(a.pow(2), F7::new(2)); - assert_eq!(a.pow(6), F7::one()); - } - - #[test] - fn test_finite_prime_field_inv() { - type F11 = FinitePrimeField<11>; - - let a = F11::new(2); - assert_eq!(a.inv(), F11::new(6)); - assert_eq!(F11::zero().mul_inverse(), None); - } - - #[test] - fn test_finite_prime_field_primitive_element() { - assert!(F5::is_primitive_element(&F5::new(2))); - assert!(!F5::is_primitive_element(&F5::new(1))); - } - - #[test] - #[should_panic(expected = "P must be prime")] - fn test_non_prime_field() { - let _ = FinitePrimeField::<4>::new(1); - } -} diff --git a/src/concrete_polynomial.rs b/src/concrete_polynomial.rs deleted file mode 100644 index 5128aa5..0000000 --- a/src/concrete_polynomial.rs +++ /dev/null @@ -1,441 +0,0 @@ -use crate::{Associative, Commutative, Distributive, EuclideanDomain, Field, FiniteField, Set}; -use num_traits::{One, Zero}; -use std::fmt; -use std::fmt::{Debug, Display}; -use std::ops::{Add, Div, Mul, Neg, Rem, Sub}; - -#[derive(Clone, Copy, PartialEq, Eq)] -pub struct PolynomialField { - coeffs: [F; N], -} - -impl PolynomialField { - pub fn new(coeffs: [F; N]) -> Self { - Self { coeffs } - } - - pub fn degree(&self) -> usize { - self.coeffs - .iter() - .rev() - .position(|&c| !c.is_zero()) - .map_or(0, |p| N - 1 - p) - } - - pub fn leading_coefficient(&self) -> F { - self.coeffs[self.degree()] - } - - pub fn modulus() -> Self { - let mut coeffs = [F::zero(); N]; - coeffs[0] = F::one(); - coeffs[1] = F::one(); - coeffs[N - 1] = F::one(); - Self::new(coeffs) - } - - fn inv(&self) -> Self { - if self.is_zero() { - panic!("attempt to invert zero"); - } - // Use Fermat's Little Theorem for inversion: a^(p^n - 2) mod p^n - self.pow(Self::order() - 2) - } - - fn pow(&self, mut exponent: u64) -> Self { - let mut base = *self; - let mut result = Self::one(); - while exponent > 0 { - if exponent & 1 == 1 { - result = result * base; - } - base = base * base; - exponent >>= 1; - } - result - } -} - -impl Debug for PolynomialField { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "PolynomialField(")?; - let terms: Vec = self - .coeffs - .iter() - .enumerate() - .rev() - .filter(|(_, &c)| !c.is_zero()) - .map(|(i, c)| match i { - 0 => format!("{:?}", c), - 1 => format!("{:?}x", c), - _ => format!("{:?}x^{}", c, i), - }) - .collect(); - write!(f, "{})", terms.join(" + ")) - } -} - -impl Display for PolynomialField { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - -impl Add for PolynomialField { - type Output = Self; - fn add(self, rhs: Self) -> Self::Output { - let mut coeffs = [F::zero(); N]; - for i in 0..N { - coeffs[i] = self.coeffs[i] + rhs.coeffs[i]; - } - Self::new(coeffs) - } -} - -impl Sub for PolynomialField { - type Output = Self; - fn sub(self, rhs: Self) -> Self::Output { - let mut coeffs = [F::zero(); N]; - for i in 0..N { - coeffs[i] = self.coeffs[i] - rhs.coeffs[i]; - } - Self::new(coeffs) - } -} - -impl Mul for PolynomialField { - type Output = Self; - fn mul(self, rhs: Self) -> Self::Output { - let mut result = [F::zero(); N]; - for i in 0..N { - for j in 0..N { - if i + j < N { - result[i + j] = result[i + j] + self.coeffs[i] * rhs.coeffs[j]; - } - } - } - Self::new(result) % Self::modulus() - } -} - -impl Div for PolynomialField { - type Output = Self; - fn div(self, rhs: Self) -> Self::Output { - self * rhs.inv() - } -} - -impl Neg for PolynomialField { - type Output = Self; - fn neg(self) -> Self::Output { - let mut coeffs = [F::zero(); N]; - for i in 0..N { - coeffs[i] = -self.coeffs[i]; - } - Self::new(coeffs) - } -} - -impl Rem for PolynomialField { - type Output = Self; - fn rem(self, rhs: Self) -> Self::Output { - let mut r = self; - while r.degree() >= rhs.degree() { - let lead_r = r.leading_coefficient(); - let lead_rhs = rhs.leading_coefficient(); - let mut t = Self::zero(); - t.coeffs[r.degree() - rhs.degree()] = lead_r / lead_rhs; - r = r - (t * rhs); - } - r - } -} - -impl Zero for PolynomialField { - fn zero() -> Self { - Self::new([F::zero(); N]) - } - - fn is_zero(&self) -> bool { - self.coeffs.iter().all(|&c| c.is_zero()) - } -} - -impl One for PolynomialField { - fn one() -> Self { - let mut coeffs = [F::zero(); N]; - coeffs[0] = F::one(); - Self::new(coeffs) - } -} - -impl Set for PolynomialField { - type Element = Self; - - fn is_empty(&self) -> bool { - false - } - fn contains(&self, _element: &Self::Element) -> bool { - true - } - fn empty() -> Self { - Self::zero() - } - fn singleton(element: Self::Element) -> Self { - element - } - fn union(&self, _other: &Self) -> Self { - *self - } - fn intersection(&self, other: &Self) -> Self { - if self == other { - *self - } else { - Self::empty() - } - } - fn difference(&self, other: &Self) -> Self { - if self == other { - Self::empty() - } else { - *self - } - } - fn symmetric_difference(&self, other: &Self) -> Self { - if self == other { - Self::empty() - } else { - *self - } - } - fn is_subset(&self, _other: &Self) -> bool { - true - } - fn is_equal(&self, other: &Self) -> bool { - self == other - } - fn cardinality(&self) -> Option { - Some(F::order().pow(N as u32) as usize) - } - fn is_finite(&self) -> bool { - true - } -} - -impl Commutative for PolynomialField {} -impl Associative for PolynomialField {} -impl Distributive for PolynomialField {} - -impl num_traits::Euclid for PolynomialField { - fn div_euclid(&self, v: &Self) -> Self { - *self / *v - } - fn rem_euclid(&self, v: &Self) -> Self { - *self % *v - } -} - -impl EuclideanDomain for PolynomialField { - fn gcd(mut a: Self, mut b: Self) -> Self { - while !b.is_zero() { - let r = a % b; - a = b; - b = r; - } - a - } -} - -impl Field for PolynomialField {} - -impl FiniteField for PolynomialField { - fn characteristic() -> u64 { - F::characteristic() - } - - fn order() -> u64 { - F::order().pow(N as u32) - } - - fn is_primitive_element(element: &Self) -> bool { - if element.is_zero() || element.is_one() { - return false; - } - let order = Self::order(); - let mut x = *element; - for i in 1..100 { - // Limit iterations for practicality - if x.is_one() { - return i == order - 1; - } - x = x * *element; - if i % 10 == 0 && x == *element { - return false; - } - } - false // Assume not primitive if not determined after 100 iterations - } - - fn pow(&self, exponent: u64) -> Self { - self.pow(exponent) - } - - fn mul_inverse(&self) -> Option { - if self.is_zero() { - None - } else { - Some(self.inv()) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::concrete_finite::FinitePrimeField; - use std::time::{Duration, Instant}; - - type F5 = FinitePrimeField<5>; - type F5_3 = PolynomialField; - - fn run_with_timeout(f: F, timeout: Duration) -> R - where - F: FnOnce() -> R + Send + 'static, - R: Send + 'static, - { - use std::sync::mpsc::channel; - use std::thread; - - let (tx, rx) = channel(); - let handle = thread::spawn(move || { - let result = f(); - tx.send(result).unwrap(); - }); - - match rx.recv_timeout(timeout) { - Ok(result) => { - handle.join().unwrap(); - result - } - Err(_) => panic!("Test timed out after {:?}", timeout), - } - } - - #[test] - fn test_polynomial_field_arithmetic() { - run_with_timeout( - || { - let a = F5_3::new([F5::new(1), F5::new(2), F5::new(3)]); - let b = F5_3::new([F5::new(4), F5::new(0), F5::new(1)]); - - let sum = a + b; - let diff = a - b; - let prod = a * b; - let quot = a / b; - - assert_eq!(sum, F5_3::new([F5::new(0), F5::new(2), F5::new(4)])); - assert_eq!(diff, F5_3::new([F5::new(2), F5::new(2), F5::new(2)])); - assert_eq!(prod, F5_3::new([F5::new(4), F5::new(3), F5::new(2)])); - assert_eq!(quot * b, a); - }, - Duration::from_secs(1), - ); - } - - #[test] - fn test_polynomial_field_inv() { - run_with_timeout( - || { - let a = F5_3::new([F5::new(1), F5::new(2), F5::new(3)]); - let a_inv = a.inv(); - assert_eq!(a * a_inv, F5_3::one()); - }, - Duration::from_secs(1), - ); - } - - #[test] - fn test_polynomial_field_pow() { - run_with_timeout( - || { - let a = F5_3::new([F5::new(2), F5::new(1), F5::new(0)]); - assert_eq!(a.pow(0), F5_3::one()); - assert_eq!(a.pow(1), a); - assert_eq!(a.pow(5), a * a * a * a * a); - }, - Duration::from_secs(1), - ); - } - - #[test] - fn test_polynomial_field_primitive_element() { - run_with_timeout( - || { - let a = F5_3::new([F5::new(2), F5::new(1), F5::new(0)]); - let is_primitive = F5_3::is_primitive_element(&a); - println!("Is primitive element: {}", is_primitive); - }, - Duration::from_secs(1), - ); - } - - #[test] - fn test_field_properties() { - run_with_timeout( - || { - let a = F5_3::new([F5::new(1), F5::new(2), F5::new(3)]); - let b = F5_3::new([F5::new(4), F5::new(0), F5::new(1)]); - let c = F5_3::new([F5::new(2), F5::new(1), F5::new(0)]); - - assert_eq!((a + b) + c, a + (b + c)); - assert_eq!((a * b) * c, a * (b * c)); - assert_eq!(a + b, b + a); - assert_eq!(a * b, b * a); - assert_eq!(a * (b + c), (a * b) + (a * c)); - assert_eq!(a + F5_3::zero(), a); - assert_eq!(a * F5_3::one(), a); - assert_eq!(a + (-a), F5_3::zero()); - assert_eq!(a * a.inv(), F5_3::one()); - }, - Duration::from_secs(1), - ); - } - - #[test] - fn test_field_order() { - let order = F5_3::order(); - assert_eq!(order, 125); // 5^3 = 125 - } - - #[test] - fn test_polynomial_degree() { - run_with_timeout( - || { - let a = F5_3::new([F5::new(1), F5::new(2), F5::new(3)]); - assert_eq!(a.degree(), 2); - let b = F5_3::new([F5::new(1), F5::new(2), F5::new(0)]); - assert_eq!(b.degree(), 1); - let c = F5_3::new([F5::new(1), F5::new(0), F5::new(0)]); - assert_eq!(c.degree(), 0); - let d = F5_3::zero(); - assert_eq!(d.degree(), 0); - }, - Duration::from_secs(1), - ); - } - - // ... [Include the rest of the tests from the previous response] ... - - #[test] - fn test_polynomial_large_exponent() { - run_with_timeout( - || { - let a = F5_3::new([F5::new(2), F5::new(1), F5::new(0)]); - let large_exp = 1_000_000_007; // A large prime number - let result = a.pow(large_exp); - assert!(!result.is_zero()); - }, - Duration::from_secs(5), - ); // Allow more time for this test - } -} diff --git a/src/euclidean_domain.rs b/src/euclidean_domain.rs deleted file mode 100644 index 03723ea..0000000 --- a/src/euclidean_domain.rs +++ /dev/null @@ -1,15 +0,0 @@ -use crate::PrincipalIdealDomain; - -/// Represents a Euclidean Domain, an integral domain with a Euclidean function. -/// -/// A Euclidean Domain (R, +, Β·, Ο†) is a principal ideal domain equipped with a -/// Euclidean function Ο†: R\{0} β†’ β„•β‚€ that satisfies certain properties. -/// -/// Formal Definition: -/// Let (R, +, Β·) be an integral domain and Ο†: R\{0} β†’ β„•β‚€ a function. R is a Euclidean domain if: -/// 1. βˆ€a, b ∈ R, b β‰  0, βˆƒ!q, r ∈ R : a = bq + r ∧ (r = 0 ∨ Ο†(r) < Ο†(b)) (Division with Remainder) -/// 2. βˆ€a, b ∈ R\{0} : Ο†(a) ≀ Ο†(ab) (Multiplicative Property) -pub trait EuclideanDomain: PrincipalIdealDomain { - /// Computes the greatest common divisor (GCD) using the Euclidean algorithm. - fn gcd(a: Self, b: Self) -> Self; -} diff --git a/src/extension_tower.rs b/src/extension_tower.rs deleted file mode 100644 index aad6e0d..0000000 --- a/src/extension_tower.rs +++ /dev/null @@ -1,89 +0,0 @@ -use crate::field_extension::FieldExtension; - -/// Represents a tower of field extensions. -/// -/// For a tower of fields Fβ‚€ βŠ† F₁ βŠ† Fβ‚‚ βŠ† ... βŠ† Fβ‚™, -/// where each Fα΅’β‚Šβ‚ is an extension field of Fα΅’ for i = 0, 1, ..., n-1. -pub trait FieldExtensionTower: FieldExtension { - /// The type representing each level in the tower. - type Level: FieldExtension; - - /// Returns the number of extensions in the tower. - /// For an infinite tower, this returns None. - fn height() -> Option; - - /// Returns the base field of the entire tower (Fβ‚€). - fn base_field() -> Self::BaseField; - - /// Returns the top field of the tower (Fβ‚™). - fn top_field() -> Self::Level; - - /// Returns an iterator over all fields in the tower, from bottom to top. - /// Yields Fβ‚€, F₁, Fβ‚‚, ..., Fβ‚™ in order. - fn fields() -> Box>; - - /// Returns the field at a specific level in the tower. - /// Level 0 is the base field, level height()-1 is the top field. - fn field_at_level(level: usize) -> Option; - - /// Returns an iterator over the degrees of each extension in the tower. - /// Yields [F₁:Fβ‚€], [Fβ‚‚:F₁], ..., [Fβ‚™:Fₙ₋₁]. - fn extension_degrees() -> Box>>; - - /// Computes the absolute degree of the entire tower extension. - /// [Fβ‚™:Fβ‚€] = [Fβ‚™:Fₙ₋₁] Β· [Fₙ₋₁:Fβ‚™β‚‹β‚‚] Β· ... Β· [Fβ‚‚:F₁] Β· [F₁:Fβ‚€] - fn absolute_degree(&self) -> Option { - Self::extension_degrees().fold(Some(1), |acc, deg| acc.and_then(|a| deg.map(|d| a * d))) - } - - /// Returns an iterator over the minimal polynomials of each extension in the tower. - /// Each minimal polynomial is represented as a vector of coefficients in ascending order of degree. - fn minimal_polynomials() -> Box>>; - - /// Embeds an element from any field in the tower into the top field. - fn embed_to_top(element: &Self::Level, from_level: usize) -> Self::Level; - - /// Attempts to project an element from the top field to a lower level in the tower. - /// Returns None if the element cannot be represented in the lower field. - fn project_from_top(element: &Self::Level, to_level: usize) -> Option; - - /// Checks if the entire tower consists of normal extensions. - fn is_normal(&self) -> bool; - - /// Checks if the entire tower consists of separable extensions. - fn is_separable(&self) -> bool; - - /// Checks if the entire tower consists of algebraic extensions. - fn is_algebraic(&self) -> bool; - - /// Checks if the tower is Galois (normal and separable). - fn is_galois(&self) -> bool { - self.is_normal() && self.is_separable() - } - - /// Computes the compositum of this tower with another tower over the same base field. - /// Returns a new tower representing the smallest field containing both towers. - fn compositum(other: &Self) -> Self; - - /// Attempts to find an isomorphic simple extension for this tower. - /// Returns None if no such simple extension exists or cannot be computed. - fn to_simple_extension() -> Option; - - /// Checks if this tower is a refinement of another tower. - /// A refinement means this tower includes all the fields of the other tower, possibly with additional fields in between. - fn is_refinement_of(other: &Self) -> bool; - - /// Returns an iterator over all intermediate fields between the base and top fields. - /// This can be an exponentially large set for some towers. - fn intermediate_fields() -> Box>; - - /// Checks if the tower satisfies the axioms for a valid field extension tower. - fn check_tower_axioms() -> bool { - // Implementation would check: - // 1. Each level is a valid field extension of the previous level - // 2. The tower is properly nested (each field is a subfield of the next) - // 3. Degree multiplicativity holds - // 4. Other consistency checks - unimplemented!("Axiom checking not implemented") - } -} diff --git a/src/field.rs b/src/field.rs deleted file mode 100644 index 9d406a1..0000000 --- a/src/field.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::ClosedDiv; -use crate::{ClosedSub, EuclideanDomain}; - -/// Represents a Field, an algebraic structure that is a Euclidean domain where every non-zero element -/// has a multiplicative inverse. -/// -/// A field (F, +, Β·) consists of: -/// - A set F -/// - Two binary operations + (addition) and Β· (multiplication) on F -/// -/// Formal Definition: -/// Let (F, +, Β·) be a field. Then: -/// 1. (F, +, Β·) is a Euclidean domain -/// 2. Every non-zero element has a multiplicative inverse -/// 3. 0 β‰  1 (the additive identity is not equal to the multiplicative identity) -pub trait Field: EuclideanDomain + ClosedDiv + ClosedSub {} diff --git a/src/field_extension.rs b/src/field_extension.rs deleted file mode 100644 index 69cc4c1..0000000 --- a/src/field_extension.rs +++ /dev/null @@ -1,88 +0,0 @@ -use crate::Field; - -/// Represents a field extension. -/// -/// Let K and L be fields. A field extension L/K is defined as: -/// - K is a subfield of L -/// - The operations of L, when restricted to K, are the same as the operations of K -/// - L is a vector space over K -/// -/// Notation: -/// - K: base field -/// - L: extension field -/// - [L:K]: degree of the extension -pub trait FieldExtension: Field { - /// The base field of the extension. - /// Mathematically, this is K in the extension L/K. - type BaseField: Field; - - /// Returns the degree of the field extension. - /// Mathematically, this is [L:K], the dimension of L as a vector space over K. - /// For infinite extensions, this returns None. - /// - /// [L:K] = dim_K(L) - fn degree() -> Option; - - /// Embeds an element from the base field into the extension field. - /// This represents the natural inclusion map i: K β†’ L. - /// - /// βˆ€ k ∈ K, i(k) ∈ L - fn embed(element: Self::BaseField) -> Self; - - /// Attempts to represent an element of the extension field as an element of the base field. - /// This is the inverse of the embed function, where possible. - /// Returns None if the element is not in the image of K in L. - /// - /// For l ∈ L, if βˆƒ k ∈ K such that i(k) = l, return Some(k), else None - fn project(&self) -> Option; - - /// Returns a basis of the extension field as a vector space over the base field. - /// For a finite extension of degree n, this returns {v₁, ..., vβ‚™} where: - /// βˆ€ l ∈ L, βˆƒ unique k₁, ..., kβ‚™ ∈ K such that l = k₁v₁ + ... + kβ‚™vβ‚™ - /// - /// For infinite extensions, this returns an infinite iterator. - fn basis() -> Box>; - - /// Expresses an element of the extension field as a linear combination of basis elements. - /// For l ∈ L, returns [k₁, ..., kβ‚™] ∈ K^n such that l = k₁v₁ + ... + kβ‚™vβ‚™ - /// where {v₁, ..., vβ‚™} is the basis of L over K. - fn decompose(&self) -> Vec; - - /// Constructs an element of the extension field from its decomposition in terms of the basis. - /// Given [k₁, ..., kβ‚™] ∈ K^n, returns k₁v₁ + ... + kβ‚™vβ‚™ ∈ L - /// where {v₁, ..., vβ‚™} is the basis of L over K. - fn compose(coefficients: &[Self::BaseField]) -> Self; - - /// Returns the minimal polynomial of the extension over the base field. - /// For a simple algebraic extension L = K(Ξ±), this is the monic irreducible polynomial - /// p(X) ∈ K[X] such that p(Ξ±) = 0. - /// - /// The coefficients are given in ascending order of degree: - /// [aβ‚€, a₁, ..., aβ‚™] represents p(X) = aβ‚€ + a₁X + ... + aβ‚™X^n - fn minimal_polynomial() -> Vec; - - /// Checks if this extension is normal. - /// A field extension L/K is normal if L is the splitting field of a polynomial over K. - /// - /// βˆƒ p(X) ∈ K[X] such that L = K(α₁, ..., Ξ±β‚™) where α₁, ..., Ξ±β‚™ are all roots of p(X) - fn is_normal() -> bool; - - /// Checks if this extension is separable. - /// A field extension L/K is separable if the minimal polynomial of every element of L over K - /// is separable (has no repeated roots in its splitting field). - /// - /// βˆ€ Ξ± ∈ L, the minimal polynomial of Ξ± over K has distinct roots in its splitting field - fn is_separable() -> bool; - - /// Checks if this extension is algebraic. - /// A field extension L/K is algebraic if every element of L is algebraic over K. - /// - /// βˆ€ Ξ± ∈ L, βˆƒ non-zero p(X) ∈ K[X] such that p(Ξ±) = 0 - fn is_algebraic() -> bool; - - /// Checks if the field extension axioms hold. - /// This method would implement checks for the field extension properties. - /// The exact checks would depend on whether the extension is finite or infinite, - /// and might be computationally infeasible for some extensions. - fn check_field_extension_axioms() -> bool; -} diff --git a/src/finite_field.rs b/src/finite_field.rs deleted file mode 100644 index 95cf297..0000000 --- a/src/finite_field.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::Field; - -/// Represents a Finite Prime Field, a field with a finite number of elements where the number of elements is prime. -/// -/// A finite prime field β„€/pβ„€ (also denoted as 𝔽_p or GF(p)) consists of: -/// - A set of p elements {0, 1, 2, ..., p-1}, where p is prime -/// - Addition and multiplication operations modulo p -/// -/// Formal Definition: -/// Let p be a prime number. Then: -/// 1. The set is {0, 1, 2, ..., p-1} -/// 2. Addition: a +_p b = (a + b) mod p -/// 3. Multiplication: a Β·_p b = (a Β· b) mod p -/// 4. The additive identity is 0 -/// 5. The multiplicative identity is 1 -/// 6. Every non-zero element has a unique multiplicative inverse -pub trait FiniteField: Field { - /// Returns the characteristic of the field, which is the prime number p. - fn characteristic() -> u64; - - /// Returns the number of elements in the field, which is equal to the characteristic for prime fields. - fn order() -> u64 { - Self::characteristic() - } - - /// Checks if the given integer is a primitive element (generator) of the multiplicative group. - fn is_primitive_element(element: &Self) -> bool; - - /// Computes the multiplicative inverse using Fermat's Little Theorem: a^(p-1) ≑ 1 (mod p) - /// Therefore, a^(p-2) is the multiplicative inverse of a. - fn mul_inverse(&self) -> Option { - if self.is_zero() { - None - } else { - Some(self.pow(Self::characteristic() - 2)) - } - } - - /// Raises the element to a power using exponentiation by squaring. - fn pow(&self, mut exponent: u64) -> Self { - let mut base = self.clone(); - let mut result = Self::one(); - while exponent > 0 { - if exponent % 2 == 1 { - result = result * base.clone(); - } - base = base.clone() * base; - exponent /= 2; - } - result - } -} diff --git a/src/group.rs b/src/group.rs deleted file mode 100644 index ba96018..0000000 --- a/src/group.rs +++ /dev/null @@ -1,116 +0,0 @@ -use crate::monoid::{AdditiveMonoid, MultiplicativeMonoid}; -use crate::{ClosedInv, ClosedNeg}; - -/// Represents an Additive Group, an algebraic structure with a set, an associative closed addition operation, -/// an identity element, and inverses for all elements. -/// -/// An additive group (G, +) consists of: -/// - A set G -/// - A binary operation +: G Γ— G β†’ G that is associative -/// - An identity element 0 ∈ G -/// - For each a ∈ G, an inverse element -a ∈ G such that a + (-a) = (-a) + a = 0 -/// -/// Formal Definition: -/// Let (G, +) be an additive group. Then: -/// 1. βˆ€ a, b, c ∈ G, (a + b) + c = a + (b + c) (associativity) -/// 2. βˆƒ 0 ∈ G, βˆ€ a ∈ G, 0 + a = a + 0 = a (identity) -/// 3. βˆ€ a ∈ G, βˆƒ -a ∈ G, a + (-a) = (-a) + a = 0 (inverse) -pub trait AdditiveGroup: AdditiveMonoid + ClosedNeg {} - -/// Represents a Multiplicative Group, an algebraic structure with a set, an associative closed multiplication operation, -/// an identity element, and inverses for all elements. -/// -/// A multiplicative group (G, βˆ™) consists of: -/// - A set G -/// - A binary operation βˆ™: G Γ— G β†’ G that is associative -/// - An identity element 1 ∈ G -/// - For each a ∈ G, an inverse element a⁻¹ ∈ G such that a βˆ™ a⁻¹ = a⁻¹ βˆ™ a = 1 -/// -/// Formal Definition: -/// Let (G, βˆ™) be a multiplicative group. Then: -/// 1. βˆ€ a, b, c ∈ G, (a βˆ™ b) βˆ™ c = a βˆ™ (b βˆ™ c) (associativity) -/// 2. βˆƒ 1 ∈ G, βˆ€ a ∈ G, 1 βˆ™ a = a βˆ™ 1 = a (identity) -/// 3. βˆ€ a ∈ G, βˆƒ a⁻¹ ∈ G, a βˆ™ a⁻¹ = a⁻¹ βˆ™ a = 1 (inverse) -pub trait MultiplicativeGroup: MultiplicativeMonoid + ClosedInv {} - -impl AdditiveGroup for T where T: AdditiveMonoid + ClosedNeg {} -impl MultiplicativeGroup for T where T: MultiplicativeMonoid + ClosedInv {} - -#[cfg(test)] -mod tests { - use crate::concrete::Z5; - use crate::group::{AdditiveGroup, MultiplicativeGroup}; - use num_traits::{Inv, One, Zero}; - - #[test] - fn test_z5_additive_group() { - // Test associativity - for i in 0..5 { - for j in 0..5 { - for k in 0..5 { - let a = Z5::new(i); - let b = Z5::new(j); - let c = Z5::new(k); - assert_eq!((a + b) + c, a + (b + c)); - } - } - } - - // Test identity - let zero = Z5::zero(); - for i in 0..5 { - let a = Z5::new(i); - assert_eq!(a + zero, a); - assert_eq!(zero + a, a); - } - - // Test inverse - for i in 0..5 { - let a = Z5::new(i); - let neg_a = -a; - assert_eq!(a + neg_a, zero); - assert_eq!(neg_a + a, zero); - } - } - - #[test] - fn test_z5_multiplicative_group() { - // Test associativity - for i in 1..5 { - // Skip 0 as it's not part of the multiplicative group - for j in 1..5 { - for k in 1..5 { - let a = Z5::new(i); - let b = Z5::new(j); - let c = Z5::new(k); - assert_eq!((a * b) * c, a * (b * c)); - } - } - } - - // Test identity - let one = Z5::one(); - for i in 1..5 { - let a = Z5::new(i); - assert_eq!(a * one, a); - assert_eq!(one * a, a); - } - - // Test inverse - for i in 1..5 { - let a = Z5::new(i); - let inv_a = a.inv(); - assert_eq!(a * inv_a, one); - assert_eq!(inv_a * a, one); - } - } - - #[test] - fn test_z5_implements_groups() { - fn assert_additive_group() {} - fn assert_multiplicative_group() {} - - assert_additive_group::(); - assert_multiplicative_group::(); - } -} diff --git a/src/integral_domain.rs b/src/integral_domain.rs deleted file mode 100644 index 163874f..0000000 --- a/src/integral_domain.rs +++ /dev/null @@ -1,54 +0,0 @@ -use crate::ring::Ring; -use crate::ClosedDiv; -use std::ops::Div; - -/// Represents an Integral Domain, a commutative ring with no zero divisors. -/// -/// An integral domain (D, +, Β·) consists of: -/// - A set D -/// - Two binary operations + (addition) and Β· (multiplication) on D -/// - Two distinguished elements 0 (zero) and 1 (unity) of D -/// -/// Formal Definition: -/// Let (D, +, Β·) be an integral domain. Then: -/// 1. (D, +, Β·) is a commutative ring -/// 2. D has no zero divisors: -/// βˆ€ a, b ∈ D, if a Β· b = 0, then a = 0 or b = 0 -/// 3. The zero element is distinct from the unity: -/// 0 β‰  1 -pub trait IntegralDomain: Ring + ClosedDiv {} - -impl IntegralDomain for T where T: Ring + Div {} - -#[cfg(test)] -mod tests { - use super::*; - use crate::concrete::Z5; - use num_traits::{One, Zero}; - use std::panic::{catch_unwind, AssertUnwindSafe}; - - #[test] - fn test_z5_implements_integral_domain() { - fn assert_integral_domain() {} - assert_integral_domain::(); - } - - #[test] - fn test_unity_not_zero() { - let zero = Z5::zero(); - let one = Z5::one(); - assert_ne!(zero, one); - } - - #[test] - fn test_z5_division_by_zero() { - let a = Z5::new(1); - let zero = Z5::zero(); - - let result = catch_unwind(AssertUnwindSafe(|| { - let _ = a / zero; - })); - - assert!(result.is_err(), "Division by zero should panic"); - } -} diff --git a/src/lib.rs b/src/lib.rs index 35a6d54..96cd961 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -91,76 +91,1030 @@ //! β”‚ Tower β”‚ //! β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ //! ``` +//! # Operator Traits for Algebraic Structures +//! +//! This module defines traits for various operators and their properties, +//! providing a foundation for implementing algebraic structures in Rust. +//! +//! An algebraic structure consists of a set with one or more binary operations. +//! Let 𝑆 be a set (Self) and β€’ be a binary operation on 𝑆. +//! Here are the key properties a binary operation may possess, organized from simplest to most complex: +//! +//! - (Closure) βˆ€ a, b ∈ 𝑆, a β€’ b ∈ 𝑆 - Guaranteed by the operators provided +//! - (Totality) βˆ€ a, b ∈ 𝑆, a β€’ b is defined - Guaranteed by Rust +//! - (Commutativity) βˆ€ a, b ∈ 𝑆, a β€’ b = b β€’ a - Marker trait +//! - (Associativity) βˆ€ a, b, c ∈ 𝑆, (a β€’ b) β€’ c = a β€’ (b β€’ c) - Marker trait +//! - (Distributivity) βˆ€ a, b, c ∈ 𝑆, a * (b + c) = (a * b) + (a * c) - Marker trait +//! +//! To be determined: +//! - (Idempotence) βˆ€ a ∈ 𝑆, a β€’ a = a +//! - (Identity) βˆƒ e ∈ 𝑆, βˆ€ a ∈ 𝑆, e β€’ a = a β€’ e = a +//! - (Inverses) βˆ€ a ∈ 𝑆, βˆƒ b ∈ 𝑆, a β€’ b = b β€’ a = e (where e is the identity) +//! - (Cancellation) βˆ€ a, b, c ∈ 𝑆, a β€’ b = a β€’ c β‡’ b = c (a β‰  0 if βˆƒ zero element) +//! - (Divisibility) βˆ€ a, b ∈ 𝑆, βˆƒ x ∈ 𝑆, a β€’ x = b +//! - (Regularity) βˆ€ a ∈ 𝑆, βˆƒ x ∈ 𝑆, a β€’ x β€’ a = a +//! - (Alternativity) βˆ€ a, b ∈ 𝑆, (a β€’ a) β€’ b = a β€’ (a β€’ b) ∧ (b β€’ a) β€’ a = b β€’ (a β€’ a) +//! - (Absorption) βˆ€ a, b ∈ 𝑆, a * (a + b) = a ∧ a + (a * b) = a +//! - (Monotonicity) βˆ€ a, b, c ∈ 𝑆, a ≀ b β‡’ a β€’ c ≀ b β€’ c ∧ c β€’ a ≀ c β€’ b +//! - (Modularity) βˆ€ a, b, c ∈ 𝑆, a ≀ c β‡’ a ∨ (b ∧ c) = (a ∨ b) ∧ c +//! - (Switchability) βˆ€ x, y, z ∈ S, (x + y) * z = x + (y * z) +//! - (Min/Max Ops) βˆ€ a, b ∈ S, a ∨ b = min{a,b}, a ∧ b = max{a,b} +//! - (Defect Op) βˆ€ a, b ∈ S, a *₃ b = a + b - 3 +//! - (Continuity) βˆ€ V βŠ† 𝑆 open, f⁻¹(V) is open (for f: 𝑆 β†’ 𝑆, 𝑆 topological) +//! - (Solvability) βˆƒ series {Gα΅’} | G = Gβ‚€ β–· G₁ β–· ... β–· Gβ‚™ = {e}, [Gα΅’, Gα΅’] ≀ Gα΅’β‚Šβ‚ +//! - (Alg. Closure) βˆ€ p(x) ∈ 𝑆[x] non-constant, βˆƒ a ∈ 𝑆 | p(a) = 0 +//! +//! The traits and blanket implementations provided above serve several important purposes: +//! +//! 1. Closure: All `Closed*` traits ensure that operations on a type always produce a result +//! of the same type. This is crucial for defining algebraic structures. +//! +//! 2. Reference Operations: The `*Ref` variants of traits allow for more efficient operations +//! when the right-hand side can be borrowed, which is common in many algorithms. +//! +//! 3. Marker Traits: Traits like `Commutative`, `Associative`, etc., allow types to declare +//! which algebraic properties they satisfy. This can be used for compile-time checks +//! and to enable more generic implementations of algorithms. There is work to be done +//! to complete the compile time checks. +//! +//! 4. Property Checking: Some marker traits include methods to check if the property holds +//! for specific values. While not providing compile-time guarantees, these can be +//! useful for testing and runtime verification. +//! +//! 5. Automatic Implementation: The blanket implementations ensure that any type satisfying +//! the basic requirements automatically implements the corresponding closed trait. +//! This reduces boilerplate and makes the traits easier to use. +//! +//! 6. Extensibility: New types that implement the standard traits (like `Add`, `Sub`, etc.) +//! will automatically get the closed trait implementations, making the system more +//! extensible and future-proof. +//! +//! 7. Type Safety: These traits help in catching type-related errors at compile-time, +//! ensuring that operations maintain closure within the same type. +//! +//! 8. Generic Programming: These traits enable more expressive generic programming, +//! allowing functions and structs to be generic over types that are closed under +//! certain operations or satisfy certain algebraic properties. +//! +//! Note that while these blanket implementations cover a wide range of cases, there might +//! be situations where more specific implementations are needed. In such cases, you can +//! still manually implement these traits for your types, and the manual implementations +//! will take precedence over these blanket implementations. -// Concrete implemetations for tests -#[cfg(test)] -mod concrete; - -// Implemented traits -mod abelian; -mod commutative_ring; mod concrete_finite; -mod concrete_polynomial; -mod euclidean_domain; -mod extension_tower; -mod field; -mod field_extension; -mod finite_field; -mod group; -mod integral_domain; -mod magma; -mod monoid; -mod operator; -mod pid; -mod real_field; -mod ring; -mod semigroup; -mod semiring; -mod set; -mod ufd; -// Not yet implemented -// mod alg_loop; -// mod quasigroup; -// mod semilattice; -// mod module; -// mod vector_space; -// Library level re-exports +pub use concrete_finite::*; + +use num_traits::{CheckedEuclid, Euclid, Inv, One, Zero}; +use std::ops::{ + Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign, +}; + +// TODO(These marker traits could actually mean something and check things) + +/// Marker trait for commutative addition +pub trait CommutativeAddition {} + +/// Marker trait for commutative multiplication +pub trait CommutativeMultiplication {} + +/// Marker trait for associative addition +pub trait AssociativeAddition {} + +/// Marker trait for associative addition +pub trait AssociativeMultiplication {} + +/// Marker trait for distributive operations +pub trait DistributiveAddition {} + +/// Trait for closed addition operation. +pub trait ClosedAdd: Add {} + +/// Trait for closed addition operation with the right-hand side as a reference. +pub trait ClosedAddRef: for<'a> Add<&'a Rhs, Output = Self> {} + +/// Trait for closed subtraction operation. +pub trait ClosedSub: Sub {} + +/// Trait for closed subtraction operation with the right-hand side as a reference. +pub trait ClosedSubRef: for<'a> Sub<&'a Rhs, Output = Self> {} + +/// Trait for closed multiplication operation. +pub trait ClosedMul: Mul {} + +/// Trait for closed multiplication operation with the right-hand side as a reference. +pub trait ClosedMulRef: for<'a> Mul<&'a Rhs, Output = Self> {} + +/// Trait for closed division operation. +pub trait ClosedDiv: Div {} + +/// Trait for closed division operation with the right-hand side as a reference. +pub trait ClosedDivRef: for<'a> Div<&'a Rhs, Output = Self> {} + +/// Trait for closed remainder operation. +pub trait ClosedRem: Rem {} + +/// Trait for closed remainder operation with the right-hand side as a reference. +pub trait ClosedRemRef: for<'a> Rem<&'a Rhs, Output = Self> {} + +/// Trait for closed negation operation. +pub trait ClosedNeg: Neg {} + +/// Trait for closed negation operation. +pub trait ClosedInv: Inv {} + +/// Trait for closed addition assignment operation. +pub trait ClosedAddAssign: AddAssign {} + +/// Trait for closed addition assignment operation with the right-hand side as a reference. +pub trait ClosedAddAssignRef: for<'a> AddAssign<&'a Rhs> {} + +/// Trait for closed subtraction assignment operation. +pub trait ClosedSubAssign: SubAssign {} + +/// Trait for closed subtraction assignment operation with the right-hand side as a reference. +pub trait ClosedSubAssignRef: for<'a> SubAssign<&'a Rhs> {} + +/// Trait for closed multiplication assignment operation. +pub trait ClosedMulAssign: MulAssign {} + +/// Trait for closed multiplication assignment operation with the right-hand side as a reference. +pub trait ClosedMulAssignRef: for<'a> MulAssign<&'a Rhs> {} + +/// Trait for closed division assignment operation. +pub trait ClosedDivAssign: DivAssign {} + +/// Trait for closed division assignment operation with the right-hand side as a reference. +pub trait ClosedDivAssignRef: for<'a> DivAssign<&'a Rhs> {} + +/// Trait for closed remainder assignment operation. +pub trait ClosedRemAssign: RemAssign {} + +/// Trait for closed remainder assignment operation with the right-hand side as a reference. +pub trait ClosedRemAssignRef: for<'a> RemAssign<&'a Rhs> {} + + +/// Trait for types with a closed zero value. +pub trait ClosedZero: Zero {} + +/// Trait for types with a closed one value. +pub trait ClosedOne: One {} + +/// Trait for closed Euclidean division operation +pub trait ClosedDivEuclid: Euclid { + fn div_euclid(self, rhs: Self) -> Self; +} + +/// Trait for closed Euclidean remainder operation +pub trait ClosedRemEuclid { + fn rem_euclid(self, rhs: Self) -> Self; +} + +// Blanket implementations +impl ClosedDivEuclid for T +where + T: Euclid, +{ + fn div_euclid(self, rhs: Self) -> Self { + Euclid::div_euclid(&self, &rhs) + } +} + +impl ClosedRemEuclid for T +where + T: Euclid, +{ + fn rem_euclid(self, rhs: Self) -> Self { + Euclid::rem_euclid(&self, &rhs) + } +} + +impl ClosedAdd for T where T: Add {} +impl ClosedAddRef for T where T: for<'a> Add<&'a Rhs, Output = T> {} +impl ClosedSub for T where T: Sub {} +impl ClosedSubRef for T where T: for<'a> Sub<&'a Rhs, Output = T> {} +impl ClosedMul for T where T: Mul {} +impl ClosedMulRef for T where T: for<'a> Mul<&'a Rhs, Output = T> {} +impl ClosedDiv for T where T: Div {} +impl ClosedDivRef for T where T: for<'a> Div<&'a Rhs, Output = T> {} +impl ClosedRem for T where T: Rem {} +impl ClosedRemRef for T where T: for<'a> Rem<&'a Rhs, Output = T> {} +impl ClosedNeg for T where T: Neg {} +impl ClosedInv for T where T: Inv {} + +impl ClosedAddAssign for T where T: AddAssign {} +impl ClosedAddAssignRef for T where T: for<'a> AddAssign<&'a Rhs> {} +impl ClosedSubAssign for T where T: SubAssign {} +impl ClosedSubAssignRef for T where T: for<'a> SubAssign<&'a Rhs> {} +impl ClosedMulAssign for T where T: MulAssign {} +impl ClosedMulAssignRef for T where T: for<'a> MulAssign<&'a Rhs> {} +impl ClosedDivAssign for T where T: DivAssign {} +impl ClosedDivAssignRef for T where T: for<'a> DivAssign<&'a Rhs> {} +impl ClosedRemAssign for T where T: RemAssign {} +impl ClosedRemAssignRef for T where T: for<'a> RemAssign<&'a Rhs> {} + +impl ClosedZero for T {} +impl ClosedOne for T {} + +use std::fmt::Debug; + +/// Represents a mathematical set as defined in Zermelo-Fraenkel set theory with Choice (ZFC). +/// +/// # Formal Notation +/// - βˆ…: empty set +/// - ∈: element of +/// - βŠ†: subset of +/// - βˆͺ: union +/// - ∩: intersection +/// - \: set difference +/// - Ξ”: symmetric difference +/// - |A|: cardinality of set A +/// +/// # Axioms of ZFC +/// 1. Extensionality: βˆ€Aβˆ€B(βˆ€x(x ∈ A ↔ x ∈ B) β†’ A = B) +/// 2. Empty Set: βˆƒAβˆ€x(x βˆ‰ A) +/// 3. Pairing: βˆ€aβˆ€bβˆƒAβˆ€x(x ∈ A ↔ x = a ∨ x = b) +/// 4. Union: βˆ€FβˆƒAβˆ€x(x ∈ A ↔ βˆƒB(x ∈ B ∧ B ∈ F)) +/// 5. Power Set: βˆ€AβˆƒPβˆ€x(x ∈ P ↔ x βŠ† A) +/// 6. Infinity: βˆƒA(βˆ… ∈ A ∧ βˆ€x(x ∈ A β†’ x βˆͺ {x} ∈ A)) +/// 7. Separation: βˆ€AβˆƒBβˆ€x(x ∈ B ↔ x ∈ A ∧ Ο†(x)) for any formula Ο† +/// 8. Replacement: βˆ€A(βˆ€xβˆ€yβˆ€z((x ∈ A ∧ Ο†(x,y) ∧ Ο†(x,z)) β†’ y = z) β†’ βˆƒBβˆ€y(y ∈ B ↔ βˆƒx(x ∈ A ∧ Ο†(x,y)))) +/// 9. Foundation: βˆ€A(A β‰  βˆ… β†’ βˆƒx(x ∈ A ∧ x ∩ A = βˆ…)) +/// 10. Choice: βˆ€A(βˆ… βˆ‰ A β†’ βˆƒf:A β†’ βˆͺA βˆ€B∈A(f(B) ∈ B)) +/// +/// TODO(There is significant reasoning to do here about what might be covered by std traits, partial equivalence relations, etc.) +pub trait Set: Sized + Clone + PartialEq + Debug { + type Element; + + /// Returns true if the set is empty (βˆ…). + /// βˆ€x(x βˆ‰ self) + fn is_empty(&self) -> bool; + + /// Checks if the given element is a member of the set. + /// element ∈ self + fn contains(&self, element: &Self::Element) -> bool; + + /// Creates an empty set (βˆ…). + /// βˆƒAβˆ€x(x βˆ‰ A) + fn empty() -> Self; + + /// Creates a singleton set containing the given element. + /// βˆƒAβˆ€x(x ∈ A ↔ x = element) + fn singleton(element: Self::Element) -> Self; + + /// Returns the union of this set with another set. + /// βˆ€x(x ∈ result ↔ x ∈ self ∨ x ∈ other) + fn union(&self, other: &Self) -> Self; + + /// Returns the intersection of this set with another set. + /// βˆ€x(x ∈ result ↔ x ∈ self ∧ x ∈ other) + fn intersection(&self, other: &Self) -> Self; + + /// Returns the difference of this set and another set (self - other). + /// βˆ€x(x ∈ result ↔ x ∈ self ∧ x βˆ‰ other) + fn difference(&self, other: &Self) -> Self; + + /// Returns the symmetric difference of this set and another set. + /// βˆ€x(x ∈ result ↔ (x ∈ self ∧ x βˆ‰ other) ∨ (x βˆ‰ self ∧ x ∈ other)) + fn symmetric_difference(&self, other: &Self) -> Self; + + /// Checks if this set is a subset of another set. + /// self βŠ† other ↔ βˆ€x(x ∈ self β†’ x ∈ other) + fn is_subset(&self, other: &Self) -> bool; + + /// Checks if two sets are equal (by the Axiom of Extensionality). + /// self = other ↔ βˆ€x(x ∈ self ↔ x ∈ other) + fn is_equal(&self, other: &Self) -> bool; + + /// Returns the cardinality of the set. Returns None if the set is infinite. + /// |self| if self is finite, None otherwise + fn cardinality(&self) -> Option; + + /// Returns true if the set is finite, false otherwise. + fn is_finite(&self) -> bool; +} + +/// Represents an Additive Magma, an algebraic structure with a set and a closed addition operation. +/// +/// An additive magma (M, +) consists of: +/// - A set M (represented by the Set trait) +/// - A binary addition operation +: M Γ— M β†’ M +/// +/// Formal Definition: +/// Let (M, +) be an additive magma. Then: +/// βˆ€ a, b ∈ M, a + b ∈ M (closure property) +/// +/// Properties: +/// - Closure: For all a and b in M, the result of a + b is also in M. +/// +/// Note: An additive magma does not necessarily satisfy commutativity, associativity, or have an identity element. +pub trait AdditiveMagma: Set + ClosedAdd + ClosedAddAssign {} + +/// Represents a Multiplicative Magma, an algebraic structure with a set and a closed multiplication operation. +/// +/// A multiplicative magma (M, βˆ™) consists of: +/// - A set M (represented by the Set trait) +/// - A binary multiplication operation βˆ™: M βˆ™ M β†’ M +/// +/// Formal Definition: +/// Let (M, βˆ™) be a multiplicative magma. Then: +/// βˆ€ a, b ∈ M, a βˆ™ b ∈ M (closure property) +/// +/// Properties: +/// - Closure: For all a and b in M, the result of a βˆ™ b is also in M. +/// +/// Note: A multiplicative magma does not necessarily satisfy commutativity, associativity, or have an identity element. +pub trait MultiplicativeMagma: Set + ClosedMul + ClosedMulAssign {} + +impl AdditiveMagma for T where T: Set + ClosedAdd + ClosedAddAssign {} +impl MultiplicativeMagma for T where T: Set + ClosedMul + ClosedMulAssign {} + +/// If this trait is implemented, the object implements Additive Semigroup, an +/// algebraic structure with a set and an associative closed addition operation. +/// +/// An additive semigroup (S, +) consists of: +/// - A set S +/// - A binary operation +: S Γ— S β†’ S that is associative +/// +/// Formal Definition: +/// Let (S, +) be an additive semigroup. Then: +/// βˆ€ a, b, c ∈ S, (a + b) + c = a + (b + c) (associativity) +/// +/// Properties: +/// - Closure: βˆ€ a, b ∈ S, a + b ∈ S +/// - Associativity: βˆ€ a, b, c ∈ S, (a + b) + c = a + (b + c) +pub trait AdditiveSemigroup: AdditiveMagma + AssociativeAddition {} + +/// If this trait is implemented, the object implements a Multiplicative Semigroup, an algebraic +/// structure with a set and an associative closed multiplication operation. +/// +/// A multiplicative semigroup (S, βˆ™) consists of: +/// - A set S +/// - A binary operation βˆ™: S Γ— S β†’ S that is associative +/// +/// Formal Definition: +/// Let (S, βˆ™) be a multiplicative semigroup. Then: +/// βˆ€ a, b, c ∈ S, (a βˆ™ b) βˆ™ c = a βˆ™ (b βˆ™ c) (associativity) +/// +/// Properties: +/// - Closure: βˆ€ a, b ∈ S, a βˆ™ b ∈ S +/// - Associativity: βˆ€ a, b, c ∈ S, (a βˆ™ b) βˆ™ c = a βˆ™ (b βˆ™ c) +pub trait MultiplicativeSemigroup: MultiplicativeMagma + AssociativeMultiplication {} + +// Blanket implementations +impl AdditiveSemigroup for T where T: AdditiveMagma + AssociativeAddition {} +impl MultiplicativeSemigroup for T where T: MultiplicativeMagma + AssociativeMultiplication {} + +/// Represents an Additive Monoid, an algebraic structure with a set, an associative closed addition operation, and an identity element. +/// +/// An additive monoid (M, +, 0) consists of: +/// - A set M (represented by the Set trait) +/// - A binary addition operation +: M Γ— M β†’ M that is associative +/// - An identity element 0 ∈ M +/// +/// Formal Definition: +/// Let (M, +, 0) be an additive monoid. Then: +/// 1. βˆ€ a, b, c ∈ M, (a + b) + c = a + (b + c) (associativity) +/// 2. βˆ€ a ∈ M, a + 0 = 0 + a = a (identity) +/// +/// Properties: +/// - Closure: For all a and b in M, the result of a + b is also in M. +/// - Associativity: For all a, b, and c in M, (a + b) + c = a + (b + c). +/// - Identity: There exists an element 0 in M such that for every element a in M, a + 0 = 0 + a = a. +pub trait AdditiveMonoid: AdditiveSemigroup + ClosedZero {} + +/// Represents a Multiplicative Monoid, an algebraic structure with a set, an associative closed multiplication operation, and an identity element. +/// +/// A multiplicative monoid (M, βˆ™, 1) consists of: +/// - A set M (represented by the Set trait) +/// - A binary multiplication operation βˆ™: M Γ— M β†’ M that is associative +/// - An identity element 1 ∈ M +/// +/// Formal Definition: +/// Let (M, βˆ™, 1) be a multiplicative monoid. Then: +/// 1. βˆ€ a, b, c ∈ M, (a βˆ™ b) βˆ™ c = a βˆ™ (b βˆ™ c) (associativity) +/// 2. βˆ€ a ∈ M, a βˆ™ 1 = 1 βˆ™ a = a (identity) +/// +/// Properties: +/// - Closure: For all a and b in M, the result of a βˆ™ b is also in M. +/// - Associativity: For all a, b, and c in M, (a βˆ™ b) βˆ™ c = a βˆ™ (b βˆ™ c). +/// - Identity: There exists an element 1 in M such that for every element a in M, a βˆ™ 1 = 1 βˆ™ a = a. +pub trait MultiplicativeMonoid: MultiplicativeSemigroup + ClosedOne {} + +impl AdditiveMonoid for T where T: AdditiveSemigroup + ClosedZero {} + +impl MultiplicativeMonoid for T where T: MultiplicativeSemigroup + ClosedOne {} + +/// Represents an Additive Group, an algebraic structure with a set, an associative closed addition operation, +/// an identity element, and inverses for all elements. +/// +/// An additive group (G, +) consists of: +/// - A set G +/// - A binary operation +: G Γ— G β†’ G that is associative +/// - An identity element 0 ∈ G +/// - For each a ∈ G, an inverse element -a ∈ G such that a + (-a) = (-a) + a = 0 +/// +/// Formal Definition: +/// Let (G, +) be an additive group. Then: +/// 1. βˆ€ a, b, c ∈ G, (a + b) + c = a + (b + c) (associativity) +/// 2. βˆƒ 0 ∈ G, βˆ€ a ∈ G, 0 + a = a + 0 = a (identity) +/// 3. βˆ€ a ∈ G, βˆƒ -a ∈ G, a + (-a) = (-a) + a = 0 (inverse) +pub trait AdditiveGroup: AdditiveMonoid + ClosedNeg + Sub + SubAssign {} + +/// Represents a Multiplicative Group, an algebraic structure with a set, an associative closed multiplication operation, +/// an identity element, and inverses for all elements. +/// +/// A multiplicative group (G, βˆ™) consists of: +/// - A set G +/// - A binary operation βˆ™: G Γ— G β†’ G that is associative +/// - An identity element 1 ∈ G +/// - For each a ∈ G, an inverse element a⁻¹ ∈ G such that a βˆ™ a⁻¹ = a⁻¹ βˆ™ a = 1 +/// +/// Formal Definition: +/// Let (G, βˆ™) be a multiplicative group. Then: +/// 1. βˆ€ a, b, c ∈ G, (a βˆ™ b) βˆ™ c = a βˆ™ (b βˆ™ c) (associativity) +/// 2. βˆƒ 1 ∈ G, βˆ€ a ∈ G, 1 βˆ™ a = a βˆ™ 1 = a (identity) +/// 3. βˆ€ a ∈ G, βˆƒ a⁻¹ ∈ G, a βˆ™ a⁻¹ = a⁻¹ βˆ™ a = 1 (inverse) +pub trait MultiplicativeGroup: MultiplicativeMonoid + ClosedInv {} + +impl AdditiveGroup for T where T: AdditiveMonoid + ClosedNeg + Sub + SubAssign {} +impl MultiplicativeGroup for T where T: MultiplicativeMonoid + ClosedInv {} + +/// Represents an Additive Abelian Group, an algebraic structure with a commutative addition operation. +/// +/// An additive abelian group (G, +) is an additive group that also satisfies: +/// - Commutativity: βˆ€ a, b ∈ G, a + b = b + a +/// +/// Formal Definition: +/// Let (G, +) be an additive abelian group. Then: +/// 1. βˆ€ a, b, c ∈ G, (a + b) + c = a + (b + c) (associativity) +/// 2. βˆƒ 0 ∈ G, βˆ€ a ∈ G, 0 + a = a + 0 = a (identity) +/// 3. βˆ€ a ∈ G, βˆƒ -a ∈ G, a + (-a) = (-a) + a = 0 (inverse) +/// 4. βˆ€ a, b ∈ G, a + b = b + a (commutativity) +pub trait AdditiveAbelianGroup: AdditiveGroup + CommutativeAddition {} + +/// Represents a Multiplicative Abelian Group, an algebraic structure with a commutative multiplication operation. +/// +/// A multiplicative abelian group (G, βˆ™) is a multiplicative group that also satisfies: +/// - Commutativity: βˆ€ a, b ∈ G, a βˆ™ b = b βˆ™ a +/// +/// Formal Definition: +/// Let (G, βˆ™) be a multiplicative abelian group. Then: +/// 1. βˆ€ a, b, c ∈ G, (a βˆ™ b) βˆ™ c = a βˆ™ (b βˆ™ c) (associativity) +/// 2. βˆƒ 1 ∈ G, βˆ€ a ∈ G, 1 βˆ™ a = a βˆ™ 1 = a (identity) +/// 3. βˆ€ a ∈ G, βˆƒ a⁻¹ ∈ G, a βˆ™ a⁻¹ = a⁻¹ βˆ™ a = 1 (inverse) +/// 4. βˆ€ a, b ∈ G, a βˆ™ b = b βˆ™ a (commutativity) +pub trait MultiplicativeAbelianGroup: MultiplicativeGroup + CommutativeMultiplication {} + +impl AdditiveAbelianGroup for T where T: AdditiveGroup + CommutativeAddition {} +impl MultiplicativeAbelianGroup for T where T: MultiplicativeGroup + CommutativeMultiplication {} + +/// Represents a Semiring, a set with two associative binary operations (addition and multiplication). +/// +/// # Formal Definition +/// A semiring (R, +, Β·, 0, 1) is a set R equipped with two binary operations + and Β· such that: +/// - (R, +, 0) is a commutative monoid +/// - (R, Β·, 1) is a monoid +/// - Multiplication distributes over addition +/// - Multiplication by 0 annihilates R +/// +/// # Properties +/// - Additive closure: βˆ€a,b ∈ R, a + b ∈ R +/// - Multiplicative closure: βˆ€a,b ∈ R, a Β· b ∈ R +/// - Additive associativity: βˆ€a,b,c ∈ R, (a + b) + c = a + (b + c) +/// - Multiplicative associativity: βˆ€a,b,c ∈ R, (a Β· b) Β· c = a Β· (b Β· c) +/// - Additive commutativity: βˆ€a,b ∈ R, a + b = b + a +/// - Additive identity: βˆƒ0 ∈ R, βˆ€a ∈ R, a + 0 = 0 + a = a +/// - Multiplicative identity: βˆƒ1 ∈ R, βˆ€a ∈ R, 1 Β· a = a Β· 1 = a +/// - Left distributivity: βˆ€a,b,c ∈ R, a Β· (b + c) = (a Β· b) + (a Β· c) +/// - Right distributivity: βˆ€a,b,c ∈ R, (a + b) Β· c = (a Β· c) + (b Β· c) +/// - Multiplication by 0 annihilates R: βˆ€a ∈ R, 0 Β· a = a Β· 0 = 0 +pub trait Semiring: AdditiveMonoid + CommutativeAddition + MultiplicativeMonoid + DistributiveAddition {} + +impl Semiring for T where T: AdditiveMonoid + CommutativeAddition + MultiplicativeMonoid + DistributiveAddition {} + +/// Represents a Ring, an algebraic structure with two binary operations (addition and multiplication) +/// that satisfy certain axioms. +/// +/// A ring (R, +, Β·) consists of: +/// - A set R +/// - Two binary operations + (addition) and Β· (multiplication) on R +/// +/// Formal Definition: +/// Let (R, +, Β·) be a ring. Then: +/// 1. (R, +) is an abelian group: +/// a. βˆ€ a, b, c ∈ R, (a + b) + c = a + (b + c) (associativity) +/// b. βˆ€ a, b ∈ R, a + b = b + a (commutativity) +/// c. βˆƒ 0 ∈ R, βˆ€ a ∈ R, a + 0 = 0 + a = a (identity) +/// d. βˆ€ a ∈ R, βˆƒ -a ∈ R, a + (-a) = (-a) + a = 0 (inverse) +/// 2. (R, Β·) is a monoid: +/// a. βˆ€ a, b, c ∈ R, (a Β· b) Β· c = a Β· (b Β· c) (associativity) +/// b. βˆƒ 1 ∈ R, βˆ€ a ∈ R, 1 Β· a = a Β· 1 = a (identity) +/// 3. Multiplication is distributive over addition: +/// a. βˆ€ a, b, c ∈ R, a Β· (b + c) = (a Β· b) + (a Β· c) (left distributivity) +/// b. βˆ€ a, b, c ∈ R, (a + b) Β· c = (a Β· c) + (b Β· c) (right distributivity) +pub trait Ring: AdditiveAbelianGroup + MultiplicativeMonoid + DistributiveAddition {} + +impl Ring for T where T: AdditiveAbelianGroup + MultiplicativeMonoid + DistributiveAddition {} + +/// Represents a Commutative Ring, an algebraic structure where multiplication is commutative. +/// +/// A commutative ring (R, +, Β·) is a ring that also satisfies: +/// - Commutativity of multiplication: βˆ€ a, b ∈ R, a Β· b = b Β· a +/// +/// Formal Definition: +/// Let (R, +, Β·) be a commutative ring. Then: +/// 1. (R, +, Β·) is a ring +/// 2. βˆ€ a, b ∈ R, a Β· b = b Β· a (commutativity of multiplication) +pub trait CommutativeRing: Ring + CommutativeMultiplication {} + +impl CommutativeRing for T where T: Ring + CommutativeMultiplication {} + +/// Represents an Integral Domain, a commutative ring with no zero divisors. +/// +/// An integral domain (D, +, Β·) consists of: +/// - A set D +/// - Two binary operations + (addition) and Β· (multiplication) on D +/// - Two distinguished elements 0 (zero) and 1 (unity) of D +/// +/// Formal Definition: +/// Let (D, +, Β·) be an integral domain. Then: +/// 1. (D, +, Β·) is a commutative ring +/// 2. D has no zero divisors: +/// βˆ€ a, b ∈ D, if a Β· b = 0, then a = 0 or b = 0 +/// 3. The zero element is distinct from the unity: +/// 0 β‰  1 +pub trait IntegralDomain: Ring { + /// Checks if the element is a zero divisor. + /// + /// # Formal Notation + /// For a ∈ R, returns false if βˆƒb β‰  0 ∈ R such that ab = 0 + fn is_zero_divisor(&self) -> bool { + // In an integral domain, only 0 is a zero divisor + self.is_zero() + } + + /// Checks if the element is a unit (has a multiplicative inverse). + /// + /// # Formal Notation + /// For a ∈ R, returns true if βˆƒb ∈ R such that ab = 1 + fn is_unit(&self) -> bool { + // In an integral domain, all non-zero elements are units + !self.is_zero() + } +} + +impl IntegralDomain for T where T: Ring { +} + +/// Represents a Unique Factorization Domain (UFD), an integral domain where every non-zero +/// non-unit element has a unique factorization into irreducible elements. +/// +/// A UFD (R, +, Β·) is an integral domain that satisfies: +/// 1. Every non-zero non-unit element can be factored into irreducible elements. +/// 2. This factorization is unique up to order and associates. +/// +/// Formal Definition: +/// Let R be an integral domain. R is a UFD if: +/// 1. For every non-zero non-unit a ∈ R, there exist irreducible elements p₁, ..., pβ‚™ such that +/// a = p₁ Β· ... Β· pβ‚™ +/// 2. If a = p₁ Β· ... Β· pβ‚™ = q₁ Β· ... Β· qβ‚˜ are two factorizations of a into irreducible elements, +/// then n = m and there exists a bijection Οƒ: {1, ..., n} β†’ {1, ..., n} such that pα΅’ is +/// associated to qβ‚›α΅’ for all i. +pub trait UniqueFactorizationDomain: IntegralDomain {} + +impl UniqueFactorizationDomain for T where T: IntegralDomain {} + +/// Represents a Principal Ideal Domain (PID), an integral domain where every ideal is principal. +/// +/// A Principal Ideal Domain (R, +, Β·) is an integral domain that satisfies: +/// 1. (R, +, Β·) is an integral domain +/// 2. Every ideal in R is principal (can be generated by a single element) +/// +/// Formal Definition: +/// Let R be an integral domain. R is a PID if for every ideal I βŠ† R, there exists an element a ∈ R +/// such that I = (a) = {ra | r ∈ R}. +pub trait PrincipalIdealDomain: UniqueFactorizationDomain { + /// Computes a generator for the ideal generated by two elements. + /// + /// # Formal Notation + /// For a, b ∈ R, returns g ∈ R such that (a, b) = (g) + fn ideal_generator(&self, other: &Self) -> Self; + + /// Computes the greatest common divisor of two elements. + /// + /// # Formal Notation + /// For a, b ∈ R, returns gcd(a, b) + fn gcd(&self, other: &Self) -> Self; + + /// Computes the least common multiple of two elements. + /// + /// # Formal Notation + /// For a, b ∈ R, returns lcm(a, b) + fn lcm(&self, other: &Self) -> Self; +} + +/// Represents a Euclidean Domain, an integral domain with a Euclidean function. +/// +/// A Euclidean Domain (R, +, Β·, Ο†) is a principal ideal domain equipped with a +/// Euclidean function Ο†: R\{0} β†’ β„•β‚€ that satisfies certain properties. +/// +/// Formal Definition: +/// Let (R, +, Β·) be an integral domain and Ο†: R\{0} β†’ β„•β‚€ a function. R is a Euclidean domain if: +/// 1. βˆ€a, b ∈ R, b β‰  0, βˆƒ!q, r ∈ R : a = bq + r ∧ (r = 0 ∨ Ο†(r) < Ο†(b)) (Division with Remainder) +/// 2. βˆ€a, b ∈ R\{0} : Ο†(a) ≀ Ο†(ab) (Multiplicative Property) +pub trait EuclideanDomain: PrincipalIdealDomain + Euclid { + /// Computes the Euclidean function (degree) of the element. + /// + /// # Formal Notation + /// For a ∈ R\{0}, returns d(a) ∈ Nβ‚€ + fn euclidean_degree(&self) -> usize; + + /// Performs Euclidean division, returning the quotient and remainder. + /// + /// # Formal Notation + /// For a, b ∈ R with b β‰  0, returns (q, r) such that a = bq + r and either r = 0 or d(r) < d(b) + fn div_rem(&self, other: &Self) -> (Self, Self); +} + +/// Represents a Field, an algebraic structure that is a Euclidean domain where every non-zero element +/// has a multiplicative inverse. +/// +/// A field (F, +, Β·) consists of: +/// - A set F +/// - Two binary operations + (addition) and Β· (multiplication) on F +/// +/// Formal Definition: +/// Let (F, +, Β·) be a field. Then: +/// 1. (F, +, Β·) is a Euclidean domain +/// 2. Every non-zero element has a multiplicative inverse +/// 3. 0 β‰  1 (the additive identity is not equal to the multiplicative identity) +pub trait Field: EuclideanDomain + ClosedDiv + ClosedDivAssign { + /// Raises the element to an integer power. + /// + /// # Formal Notation + /// For a ∈ F and n ∈ Z, returns a^n + fn pow(&self, exp: i64) -> Self; +} + +/// Represents a Finite Prime Field, a field with a finite number of elements where the number of elements is prime. +/// +/// A finite prime field β„€/pβ„€ (also denoted as 𝔽_p or GF(p)) consists of: +/// - A set of p elements {0, 1, 2, ..., p-1}, where p is prime +/// - Addition and multiplication operations modulo p +/// +/// Formal Definition: +/// Let p be a prime number. Then: +/// 1. The set is {0, 1, 2, ..., p-1} +/// 2. Addition: a +_p b = (a + b) mod p +/// 3. Multiplication: a Β·_p b = (a Β· b) mod p +/// 4. The additive identity is 0 +/// 5. The multiplicative identity is 1 +/// 6. Every non-zero element has a unique multiplicative inverse +pub trait FiniteField: Field { + // Returns the characteristic of the field. + /// + /// # Formal Notation + /// The smallest positive integer n such that n Β· 1 = 0, where 1 is the multiplicative identity + fn characteristic() -> u64; + + /// Returns the order (number of elements) of the finite field. + /// + /// # Formal Notation + /// |F| = p^n, where p is the characteristic of F and n is its degree over the prime subfield + fn order() -> u64; + + /// Checks if the element is a primitive element (generator) of the multiplicative group. + /// + /// # Formal Notation + /// An element a ∈ F is primitive if it generates F*, i.e., if {a^k : 0 ≀ k < |F*|} = F* + fn is_primitive_element(&self) -> bool; + + /// Applies the Frobenius automorphism to the element. + /// + /// # Formal Notation + /// For a finite field of characteristic p, the Frobenius automorphism Ο† is defined as: + /// Ο†(x) = x^p for all x in the field + fn frobenius(&self) -> Self; + + /// Computes a multiplicative generator of the field. + /// + /// # Formal Notation + /// Returns g ∈ F* such that {g^k : 0 ≀ k < |F*|} = F* + fn multiplicative_generator() -> Self; +} + +/// Represents a Real Field, an ordered field that satisfies the completeness axiom. +/// +/// A real field (F, +, Β·, ≀) consists of: +/// - A set F +/// - Two binary operations + (addition) and Β· (multiplication) +/// - A total order relation ≀ +/// +/// Formal Definition: +/// 1. (F, +, Β·) is a field +/// 2. (F, ≀) is a totally ordered set +/// 3. The order is compatible with field operations +/// 4. F satisfies the completeness axiom +/// 5. Dedekind-complete: Every non-empty subset of ℝ with an upper bound has a least upper bound in ℝ +pub trait RealField: Field + PartialOrd { +} + +/// Represents a Polynomial over a field. +/// +/// # Formal Definition +/// A polynomial over a field F is an expression of the form: +/// a_n * X^n + a_{n-1} * X^{n-1} + ... + a_1 * X + a_0 +/// where a_i ∈ F are called the coefficients, and X is called the indeterminate. +pub trait Polynomial: Clone + PartialEq + ClosedAdd + ClosedMul + Euclid { + /// The type of the coefficients, which must form a field. + type Coefficient: Field; + + /// Returns the degree of the polynomial. + /// + /// # Formal Definition + /// The degree of a non-zero polynomial is the highest power of X with a non-zero coefficient. + /// The degree of the zero polynomial is conventionally defined as -∞ or None. + fn degree(&self) -> Option; + + /// Returns the leading coefficient of the polynomial. + /// + /// # Formal Definition + /// The leading coefficient is the non-zero coefficient of the highest degree term. + /// Returns None for the zero polynomial. + fn leading_coefficient(&self) -> Option; + + /// Evaluates the polynomial at a given point. + /// + /// # Formal Definition + /// For a polynomial f(X) = a_n * X^n + ... + a_1 * X + a_0 and x ∈ F, + /// f(x) = a_n * x^n + ... + a_1 * x + a_0 + fn evaluate(&self, x: &Self::Coefficient) -> Self::Coefficient; + + /// Returns the coefficient of X^k. + /// + /// # Formal Definition + /// For a polynomial f(X) = a_n * X^n + ... + a_1 * X + a_0, + /// coefficient(k) returns a_k if k ≀ n, and zero otherwise. + fn coefficient(&self, k: usize) -> Self::Coefficient; + + /// Computes the derivative of the polynomial. + /// + /// # Formal Definition + /// For f(X) = a_n * X^n + ... + a_1 * X + a_0, + /// f'(X) = n * a_n * X^{n-1} + ... + 2 * a_2 * X + a_1 + fn derivative(&self) -> Self; + + /// Checks if the polynomial is irreducible. + /// + /// # Formal Definition + /// A polynomial is irreducible over a field if it cannot be factored into the product of two non-constant polynomials. + fn is_irreducible(&self) -> bool; +} + +/// Represents a Module over a ring. +/// +/// # Formal Definition +/// A module M over a ring R is an abelian group (M, +) equipped with a scalar multiplication +/// by elements of R, satisfying certain axioms. +/// +/// # Properties +/// - (M, +) is an abelian group +/// - Scalar multiplication: R Γ— M β†’ M satisfying: +/// 1. a(x + y) = ax + ay +/// 2. (a + b)x = ax + bx +/// 3. (ab)x = a(bx) +/// 4. 1x = x +/// where a, b ∈ R and x, y ∈ M +pub trait Module: MultiplicativeAbelianGroup { + type Scalar: Ring; + + /// Performs scalar multiplication. + /// + /// # Formal Notation + /// For a ∈ R and x ∈ M, returns ax + fn scalar_mul(&self, scalar: &Self::Scalar) -> Self; +} + +/// Represents a Vector Space over a field. +/// +/// # Formal Definition +/// A vector space V over a field F is an abelian group (V, +) equipped with scalar multiplication +/// by elements of F, satisfying certain axioms. +/// +/// # Properties +/// - (V, +) is an abelian group +/// - Scalar multiplication: F Γ— V β†’ V satisfying: +/// 1. a(u + v) = au + av +/// 2. (a + b)v = av + bv +/// 3. (ab)v = a(bv) +/// 4. 1v = v +/// where a, b ∈ F and u, v ∈ V +pub trait VectorSpace: AdditiveAbelianGroup { + type Scalar: Field; + + /// Performs scalar multiplication. + /// + /// # Formal Notation + /// For a ∈ F and v ∈ V, returns av + fn scalar_mul(&self, scalar: &Self::Scalar) -> Self; + + /// Returns the dimension of the vector space. + /// + /// # Formal Notation + /// dim(V) = |B| where B is a basis of V + fn dimension() -> Option; + + /// Checks if a set of vectors is linearly independent. + /// + /// # Formal Notation + /// {v₁, ..., vβ‚™} is linearly independent if Ξ£α΅’ aα΅’vα΅’ = 0 implies aα΅’ = 0 for all i + fn is_linearly_independent(vectors: &[Self]) -> bool; + + /// Computes a basis for the vector space. + /// + /// # Formal Notation + /// Returns B βŠ† V such that B is linearly independent and spans V + fn basis() -> Vec; +} + +/// Represents a Field Extension. +/// +/// # Formal Definition +/// A field extension L/K is a field L that contains K as a subfield. +/// +/// # Properties +/// - L is a field +/// - K is a subfield of L +/// - L is a vector space over K +pub trait FieldExtension: Field + VectorSpace { + type BaseField: Field; + + /// Returns the degree of the field extension. + /// + /// # Formal Notation + /// [L:K] = dim_K(L) + fn degree() -> Option; + + /// Embeds an element from the base field into the extension field. + /// + /// # Formal Notation + /// The natural inclusion map i: K β†’ L + fn embed(element: Self::BaseField) -> Self; + + /// Attempts to represent an element of the extension field as an element of the base field. + /// + /// # Formal Notation + /// For l ∈ L, returns Some(k) if l = i(k) for some k ∈ K, None otherwise + fn project(&self) -> Option; + + /// Checks if this extension is normal. + /// + /// # Formal Notation + /// L/K is normal if L is the splitting field of a polynomial over K + fn is_normal() -> bool; + + /// Checks if this extension is separable. + /// + /// # Formal Notation + /// L/K is separable if the minimal polynomial of every element of L over K is separable + fn is_separable() -> bool; + + /// Checks if this extension is algebraic. + /// + /// # Formal Notation + /// L/K is algebraic if every element of L is algebraic over K + fn is_algebraic() -> bool; +} -pub use set::*; +/// Represents a Tower of Field Extensions. +/// +/// # Formal Definition +/// A tower of field extensions is a sequence of fields K = Fβ‚€ βŠ‚ F₁ βŠ‚ ... βŠ‚ Fβ‚™ = L +/// where each Fα΅’β‚Šβ‚/Fα΅’ is a field extension. +/// +/// # Properties +/// - Each level is a field extension of the previous level +/// - The composition of the extensions forms the overall extension L/K +/// - The degree of L/K is the product of the degrees of each extension in the tower +pub trait FieldExtensionTower: FieldExtension { + /// The type representing each level in the tower + type Level: FieldExtension; -pub use operator::*; + /// Returns the number of levels in the tower. + /// + /// # Formal Notation + /// For a tower K = Fβ‚€ βŠ‚ F₁ βŠ‚ ... βŠ‚ Fβ‚™ = L, returns n + 1 + fn height() -> Option; -pub use magma::*; + /// Returns the base field of the tower. + /// + /// # Formal Notation + /// For a tower K = Fβ‚€ βŠ‚ F₁ βŠ‚ ... βŠ‚ Fβ‚™ = L, returns K (= Fβ‚€) + fn base_field() -> Self::BaseField; -pub use semigroup::*; + /// Returns the top field of the tower. + /// + /// # Formal Notation + /// For a tower K = Fβ‚€ βŠ‚ F₁ βŠ‚ ... βŠ‚ Fβ‚™ = L, returns L (= Fβ‚™) + fn top_field() -> Self::Level; -pub use monoid::*; + /// Returns an iterator over all fields in the tower, from bottom to top. + /// + /// # Formal Notation + /// For a tower K = Fβ‚€ βŠ‚ F₁ βŠ‚ ... βŠ‚ Fβ‚™ = L, yields Fβ‚€, F₁, ..., Fβ‚™ in order + fn fields() -> Box>; -pub use group::*; + /// Returns the field at a specific level in the tower. + /// + /// # Formal Notation + /// For a tower K = Fβ‚€ βŠ‚ F₁ βŠ‚ ... βŠ‚ Fβ‚™ = L, returns Fα΅’ for 0 ≀ i ≀ n + fn field_at_level(level: usize) -> Option; -pub use abelian::*; + /// Returns an iterator over the degrees of each extension in the tower. + /// + /// # Formal Notation + /// For a tower K = Fβ‚€ βŠ‚ F₁ βŠ‚ ... βŠ‚ Fβ‚™ = L, yields [F₁:Fβ‚€], [Fβ‚‚:F₁], ..., [Fβ‚™:Fₙ₋₁] + fn extension_degrees() -> Box>>; -pub use semiring::*; + /// Computes the absolute degree of the entire tower extension. + /// + /// # Formal Notation + /// For a tower K = Fβ‚€ βŠ‚ F₁ βŠ‚ ... βŠ‚ Fβ‚™ = L, returns [L:K] = [Fβ‚™:Fₙ₋₁] Β· [Fₙ₋₁:Fβ‚™β‚‹β‚‚] Β· ... Β· [F₁:Fβ‚€] + fn absolute_degree() -> Option; -pub use ring::*; + /// Returns an iterator over the minimal polynomials of each extension in the tower. + /// + /// # Formal Notation + /// For a tower K = Fβ‚€ βŠ‚ F₁ βŠ‚ ... βŠ‚ Fβ‚™ = L, yields the minimal polynomials of F₁/Fβ‚€, Fβ‚‚/F₁, ..., Fβ‚™/Fₙ₋₁ + fn minimal_polynomials() -> Box>>>; -pub use commutative_ring::*; + /// Embeds an element from any field in the tower into the top field. + /// + /// # Formal Notation + /// For an element a ∈ Fα΅’, returns the image of a in L (= Fβ‚™) + fn embed_to_top(element: &Self::Level, from_level: usize) -> Self::Level; -pub use integral_domain::*; + /// Attempts to project an element from the top field to a lower level in the tower. + /// + /// # Formal Notation + /// For an element a ∈ L, attempts to find its preimage in Fα΅’, if it exists + fn project_from_top(element: &Self::Level, to_level: usize) -> Option; -pub use ufd::*; + /// Checks if the entire tower consists of normal extensions. + /// + /// # Formal Notation + /// Returns true if each Fα΅’β‚Šβ‚/Fα΅’ is a normal extension + fn is_normal() -> bool { + Self::fields().all(|field| field.is_normal()) + } -pub use pid::*; + /// Checks if the entire tower consists of separable extensions. + /// + /// # Formal Notation + /// Returns true if each Fα΅’β‚Šβ‚/Fα΅’ is a separable extension + fn is_separable() -> bool { + Self::fields().all(|field| field.is_separable()) + } -pub use euclidean_domain::*; + /// Checks if the entire tower consists of algebraic extensions. + /// + /// # Formal Notation + /// Returns true if each Fα΅’β‚Šβ‚/Fα΅’ is an algebraic extension + fn is_algebraic() -> bool { + Self::fields().all(|field| field.is_algebraic()) + } -pub use field::*; + /// Checks if the tower is Galois (normal and separable). + /// + /// # Formal Notation + /// Returns true if the tower is both normal and separable + fn is_galois() -> bool { + Self::is_normal() && Self::is_separable() + } -pub use real_field::*; + /// Computes the compositum of this tower with another tower over the same base field. + /// + /// # Formal Notation + /// For towers T₁ and Tβ‚‚ over K, returns the smallest tower T containing both T₁ and Tβ‚‚ + fn compositum(other: &Self) -> Self; -pub use field_extension::*; + /// Attempts to find an isomorphic simple extension for this tower. + /// + /// # Formal Notation + /// If it exists, returns a simple extension L/K isomorphic to the entire tower + fn to_simple_extension() -> Option; -pub use finite_field::*; + /// Checks if this tower is a refinement of another tower. + /// + /// # Formal Notation + /// Returns true if this tower includes all the fields of the other tower, + /// possibly with additional intermediate fields + fn is_refinement_of(other: &Self) -> bool; -pub use extension_tower::*; + /// Returns an iterator over all intermediate fields between the base and top fields. + /// + /// # Formal Notation + /// Yields all fields F such that K βŠ† F βŠ† L + fn intermediate_fields() -> Box>; +} \ No newline at end of file diff --git a/src/magma.rs b/src/magma.rs deleted file mode 100644 index 3eca1d8..0000000 --- a/src/magma.rs +++ /dev/null @@ -1,140 +0,0 @@ -use crate::{ClosedAdd, ClosedMul, Set}; - -/// Represents an Additive Magma, an algebraic structure with a set and a closed addition operation. -/// -/// An additive magma (M, +) consists of: -/// - A set M (represented by the Set trait) -/// - A binary addition operation +: M Γ— M β†’ M -/// -/// Formal Definition: -/// Let (M, +) be an additive magma. Then: -/// βˆ€ a, b ∈ M, a + b ∈ M (closure property) -/// -/// Properties: -/// - Closure: For all a and b in M, the result of a + b is also in M. -/// -/// Note: An additive magma does not necessarily satisfy commutativity, associativity, or have an identity element. -pub trait AdditiveMagma: Set + ClosedAdd {} - -/// Represents a Multiplicative Magma, an algebraic structure with a set and a closed multiplication operation. -/// -/// A multiplicative magma (M, βˆ™) consists of: -/// - A set M (represented by the Set trait) -/// - A binary multiplication operation βˆ™: M βˆ™ M β†’ M -/// -/// Formal Definition: -/// Let (M, βˆ™) be a multiplicative magma. Then: -/// βˆ€ a, b ∈ M, a βˆ™ b ∈ M (closure property) -/// -/// Properties: -/// - Closure: For all a and b in M, the result of a βˆ™ b is also in M. -/// -/// Note: A multiplicative magma does not necessarily satisfy commutativity, associativity, or have an identity element. -pub trait MultiplicativeMagma: Set + ClosedMul {} - -impl AdditiveMagma for T where T: Set + ClosedAdd {} -impl MultiplicativeMagma for T where T: Set + ClosedMul {} - -#[cfg(test)] -mod tests { - // Using a string here is an interesting way to test as the elements can form a set. - // However, we can make non-associative addition and multiplication operations. - use super::*; - - #[derive(Clone, PartialEq, Debug)] - struct StringMagma(String); - - impl Set for StringMagma { - type Element = char; - - fn is_empty(&self) -> bool { - self.0.is_empty() - } - - fn contains(&self, element: &Self::Element) -> bool { - self.0.contains(*element) - } - - fn empty() -> Self { - StringMagma(String::new()) - } - - fn singleton(element: Self::Element) -> Self { - StringMagma(element.to_string()) - } - - fn union(&self, other: &Self) -> Self { - StringMagma(self.0.clone() + &other.0) - } - - fn intersection(&self, other: &Self) -> Self { - StringMagma(self.0.chars().filter(|c| other.0.contains(*c)).collect()) - } - - fn difference(&self, other: &Self) -> Self { - StringMagma(self.0.chars().filter(|c| !other.0.contains(*c)).collect()) - } - - fn symmetric_difference(&self, other: &Self) -> Self { - let union = self.union(other); - let intersection = self.intersection(other); - union.difference(&intersection) - } - - fn is_subset(&self, other: &Self) -> bool { - self.0.chars().all(|c| other.0.contains(c)) - } - - fn is_equal(&self, other: &Self) -> bool { - self.0 == other.0 - } - - fn cardinality(&self) -> Option { - Some(self.0.len()) - } - - fn is_finite(&self) -> bool { - true - } - } - - impl std::ops::Add for StringMagma { - type Output = Self; - - fn add(self, other: Self) -> Self::Output { - StringMagma(self.0 + &other.0) - } - } - - impl std::ops::Mul for StringMagma { - type Output = Self; - - fn mul(self, other: Self) -> Self::Output { - StringMagma(self.0.chars().chain(other.0.chars()).collect()) - } - } - - #[test] - fn test_additive_magma() { - let a = StringMagma("Hello".to_string()); - let b = StringMagma(" World".to_string()); - let result = a + b; - assert_eq!(result, StringMagma("Hello World".to_string())); - } - - #[test] - fn test_multiplicative_magma() { - let a = StringMagma("Hello".to_string()); - let b = StringMagma("World".to_string()); - let result = a * b; - assert_eq!(result, StringMagma("HelloWorld".to_string())); - } - - #[test] - fn test_set_operations() { - let set = StringMagma("Hello".to_string()); - assert!(!set.is_empty()); - assert!(set.contains(&'H')); - assert!(!set.contains(&'W')); - } -} diff --git a/src/monoid.rs b/src/monoid.rs deleted file mode 100644 index 7f8b51b..0000000 --- a/src/monoid.rs +++ /dev/null @@ -1,131 +0,0 @@ -use crate::semigroup::{AdditiveSemigroup, MultiplicativeSemigroup}; -use crate::{ClosedOne, ClosedZero}; - -/// Represents an Additive Monoid, an algebraic structure with a set, an associative closed addition operation, and an identity element. -/// -/// An additive monoid (M, +, 0) consists of: -/// - A set M (represented by the Set trait) -/// - A binary addition operation +: M Γ— M β†’ M that is associative -/// - An identity element 0 ∈ M -/// -/// Formal Definition: -/// Let (M, +, 0) be an additive monoid. Then: -/// 1. βˆ€ a, b, c ∈ M, (a + b) + c = a + (b + c) (associativity) -/// 2. βˆ€ a ∈ M, a + 0 = 0 + a = a (identity) -/// -/// Properties: -/// - Closure: For all a and b in M, the result of a + b is also in M. -/// - Associativity: For all a, b, and c in M, (a + b) + c = a + (b + c). -/// - Identity: There exists an element 0 in M such that for every element a in M, a + 0 = 0 + a = a. -pub trait AdditiveMonoid: AdditiveSemigroup + ClosedZero {} - -/// Represents a Multiplicative Monoid, an algebraic structure with a set, an associative closed multiplication operation, and an identity element. -/// -/// A multiplicative monoid (M, βˆ™, 1) consists of: -/// - A set M (represented by the Set trait) -/// - A binary multiplication operation βˆ™: M Γ— M β†’ M that is associative -/// - An identity element 1 ∈ M -/// -/// Formal Definition: -/// Let (M, βˆ™, 1) be a multiplicative monoid. Then: -/// 1. βˆ€ a, b, c ∈ M, (a βˆ™ b) βˆ™ c = a βˆ™ (b βˆ™ c) (associativity) -/// 2. βˆ€ a ∈ M, a βˆ™ 1 = 1 βˆ™ a = a (identity) -/// -/// Properties: -/// - Closure: For all a and b in M, the result of a βˆ™ b is also in M. -/// - Associativity: For all a, b, and c in M, (a βˆ™ b) βˆ™ c = a βˆ™ (b βˆ™ c). -/// - Identity: There exists an element 1 in M such that for every element a in M, a βˆ™ 1 = 1 βˆ™ a = a. -pub trait MultiplicativeMonoid: MultiplicativeSemigroup + ClosedOne {} - -impl AdditiveMonoid for T where T: AdditiveSemigroup + ClosedZero {} - -impl MultiplicativeMonoid for T where T: MultiplicativeSemigroup + ClosedOne {} - -#[cfg(test)] -mod tests { - - use crate::concrete::Z5; - use crate::{AdditiveMonoid, MultiplicativeMonoid}; - use num_traits::{One, Zero}; - - #[test] - fn test_z5_additive_monoid() { - // Test associativity - let a = Z5::new(2); - let b = Z5::new(3); - let c = Z5::new(4); - assert_eq!((a + b) + c, a + (b + c)); - - // Test identity - let zero = Z5::zero(); - assert_eq!(a + zero, a); - assert_eq!(zero + a, a); - - // Test closure - let sum = a + b; - assert!(matches!(sum, Z5(_))); - } - - #[test] - fn test_z5_multiplicative_monoid() { - // Test associativity - let a = Z5::new(2); - let b = Z5::new(3); - let c = Z5::new(4); - assert_eq!((a * b) * c, a * (b * c)); - - // Test identity - let one = Z5::one(); - assert_eq!(a * one, a); - assert_eq!(one * a, a); - - // Test closure - let product = a * b; - assert!(matches!(product, Z5(_))); - } - - #[test] - fn test_z5_additive_monoid_properties() { - for i in 0..5 { - for j in 0..5 { - let a = Z5::new(i); - let b = Z5::new(j); - let zero = Z5::zero(); - - // Closure - assert!(matches!(a + b, Z5(_))); - - // Identity - assert_eq!(a + zero, a); - assert_eq!(zero + a, a); - } - } - } - - #[test] - fn test_z5_multiplicative_monoid_properties() { - for i in 0..5 { - for j in 0..5 { - let a = Z5::new(i); - let b = Z5::new(j); - let one = Z5::one(); - - // Closure - assert!(matches!(a * b, Z5(_))); - - // Identity - assert_eq!(a * one, a); - assert_eq!(one * a, a); - } - } - } - - #[test] - fn test_z5_implements_monoids() { - fn assert_additive_monoid() {} - fn assert_multiplicative_monoid() {} - - assert_additive_monoid::(); - assert_multiplicative_monoid::(); - } -} diff --git a/src/operator.rs b/src/operator.rs deleted file mode 100644 index 081cb64..0000000 --- a/src/operator.rs +++ /dev/null @@ -1,368 +0,0 @@ -//! # Operator Traits for Algebraic Structures -//! -//! This module defines traits for various operators and their properties, -//! providing a foundation for implementing algebraic structures in Rust. -//! -//! An algebraic structure consists of a set with one or more binary operations. -//! Let 𝑆 be a set (Self) and β€’ be a binary operation on 𝑆. -//! Here are the key properties a binary operation may possess, organized from simplest to most complex: -//! -//! - (Closure) βˆ€ a, b ∈ 𝑆, a β€’ b ∈ 𝑆 -//! - (Totality) βˆ€ a, b ∈ 𝑆, a β€’ b is defined -//! - (Commutativity) βˆ€ a, b ∈ 𝑆, a β€’ b = b β€’ a -//! - (Associativity) βˆ€ a, b, c ∈ 𝑆, (a β€’ b) β€’ c = a β€’ (b β€’ c) -//! - (Idempotence) βˆ€ a ∈ 𝑆, a β€’ a = a -//! - (Identity) βˆƒ e ∈ 𝑆, βˆ€ a ∈ 𝑆, e β€’ a = a β€’ e = a -//! - (Inverses) βˆ€ a ∈ 𝑆, βˆƒ b ∈ 𝑆, a β€’ b = b β€’ a = e (where e is the identity) -//! - (Cancellation) βˆ€ a, b, c ∈ 𝑆, a β€’ b = a β€’ c β‡’ b = c (a β‰  0 if βˆƒ zero element) -//! - (Divisibility) βˆ€ a, b ∈ 𝑆, βˆƒ x ∈ 𝑆, a β€’ x = b -//! - (Regularity) βˆ€ a ∈ 𝑆, βˆƒ x ∈ 𝑆, a β€’ x β€’ a = a -//! - (Alternativity) βˆ€ a, b ∈ 𝑆, (a β€’ a) β€’ b = a β€’ (a β€’ b) ∧ (b β€’ a) β€’ a = b β€’ (a β€’ a) -//! - (Distributivity) βˆ€ a, b, c ∈ 𝑆, a * (b + c) = (a * b) + (a * c) -//! - (Absorption) βˆ€ a, b ∈ 𝑆, a * (a + b) = a ∧ a + (a * b) = a -//! - (Monotonicity) βˆ€ a, b, c ∈ 𝑆, a ≀ b β‡’ a β€’ c ≀ b β€’ c ∧ c β€’ a ≀ c β€’ b -//! - (Modularity) βˆ€ a, b, c ∈ 𝑆, a ≀ c β‡’ a ∨ (b ∧ c) = (a ∨ b) ∧ c -//! - (Switchability) βˆ€ x, y, z ∈ S, (x + y) * z = x + (y * z) -//! - (Min/Max Ops) βˆ€ a, b ∈ S, a ∨ b = min{a,b}, a ∧ b = max{a,b} -//! - (Defect Op) βˆ€ a, b ∈ S, a *₃ b = a + b - 3 -//! - (Continuity) βˆ€ V βŠ† 𝑆 open, f⁻¹(V) is open (for f: 𝑆 β†’ 𝑆, 𝑆 topological) -//! -//! To be determined: -//! -//! - (Solvability) βˆƒ series {Gα΅’} | G = Gβ‚€ β–· G₁ β–· ... β–· Gβ‚™ = {e}, [Gα΅’, Gα΅’] ≀ Gα΅’β‚Šβ‚ -//! - (Alg. Closure) βˆ€ p(x) ∈ 𝑆[x] non-constant, βˆƒ a ∈ 𝑆 | p(a) = 0 -//! -//! The traits and blanket implementations provided above serve several important purposes: -//! -//! 1. Closure: All `Closed*` traits ensure that operations on a type always produce a result -//! of the same type. This is crucial for defining algebraic structures. -//! -//! 2. Reference Operations: The `*Ref` variants of traits allow for more efficient operations -//! when the right-hand side can be borrowed, which is common in many algorithms. -//! -//! 3. Marker Traits: Traits like `Commutative`, `Associative`, etc., allow types to declare -//! which algebraic properties they satisfy. This can be used for compile-time checks -//! and to enable more generic implementations of algorithms. -//! -//! 4. Property Checking: Some marker traits include methods to check if the property holds -//! for specific values. While not providing compile-time guarantees, these can be -//! useful for testing and runtime verification. -//! -//! 5. Generic Binary Operations: The `BinaryOp` trait provides a generic way to represent -//! any binary operation, which can be useful for implementing algorithms that work -//! with arbitrary binary operations. -//! -//! 6. Automatic Implementation: The blanket implementations ensure that any type satisfying -//! the basic requirements automatically implements the corresponding closed trait. -//! This reduces boilerplate and makes the traits easier to use. -//! -//! 7. Extensibility: New types that implement the standard traits (like `Add`, `Sub`, etc.) -//! will automatically get the closed trait implementations, making the system more -//! extensible and future-proof. -//! -//! 8. Type Safety: These traits help in catching type-related errors at compile-time, -//! ensuring that operations maintain closure within the same type. -//! -//! 9. Generic Programming: These traits enable more expressive generic programming, -//! allowing functions and structs to be generic over types that are closed under -//! certain operations or satisfy certain algebraic properties. -//! -//! Note that while these blanket implementations cover a wide range of cases, there might -//! be situations where more specific implementations are needed. In such cases, you can -//! still manually implement these traits for your types, and the manual implementations -//! will take precedence over these blanket implementations. - -use num_traits::{Euclid, Inv, One, Zero}; -use std::ops::{ - Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign, -}; -use std::ops::{ - BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Shl, ShlAssign, Shr, - ShrAssign, -}; - -// TODO(These marker traits could actually mean something and check things) - -/// Marker trait for commutative operations -pub trait Commutative {} - -/// Marker trait for associative operations -pub trait Associative {} - -/// Marker trait for idempotent operations -pub trait Idempotent {} - -/// Marker trait for operations with inverses for all elements -pub trait Invertible {} - -/// Marker trait for operations with the cancellation property -pub trait Cancellative {} - -/// Marker trait for regular operations -pub trait Regular {} - -/// Marker trait for alternative operations -pub trait Alternative {} - -/// Marker trait for distributive operations -pub trait Distributive {} - -/// Marker trait for operations with the absorption property -pub trait Absorptive {} - -/// Marker trait for monotonic operations -pub trait Monotonic {} - -/// Marker trait for modular operations -pub trait Modular {} - -/// Marker trait for switchable operations -pub trait Switchable {} - -/// Marker trait for defect operations -pub trait DefectOp {} - -/// Marker trait for continuous operations -pub trait Continuous {} - -/// Marker trait for solvable operations -pub trait Solvability {} - -/// Marker trait for algebraically closed operations -pub trait AlgebraicClosure {} - -/// Trait for closed addition operation. -pub trait ClosedAdd: Add {} - -/// Trait for closed addition operation with the right-hand side as a reference. -pub trait ClosedAddRef: for<'a> Add<&'a Rhs, Output = Self> {} - -/// Trait for closed subtraction operation. -pub trait ClosedSub: Sub {} - -/// Trait for closed subtraction operation with the right-hand side as a reference. -pub trait ClosedSubRef: for<'a> Sub<&'a Rhs, Output = Self> {} - -/// Trait for closed multiplication operation. -pub trait ClosedMul: Mul {} - -/// Trait for closed multiplication operation with the right-hand side as a reference. -pub trait ClosedMulRef: for<'a> Mul<&'a Rhs, Output = Self> {} - -/// Trait for closed division operation. -pub trait ClosedDiv: Div {} - -/// Trait for closed division operation with the right-hand side as a reference. -pub trait ClosedDivRef: for<'a> Div<&'a Rhs, Output = Self> {} - -/// Trait for closed remainder operation. -pub trait ClosedRem: Rem {} - -/// Trait for closed remainder operation with the right-hand side as a reference. -pub trait ClosedRemRef: for<'a> Rem<&'a Rhs, Output = Self> {} - -/// Trait for closed negation operation. -pub trait ClosedNeg: Neg {} - -/// Trait for closed negation operation. -pub trait ClosedInv: Inv {} - -/// Trait for closed addition assignment operation. -pub trait ClosedAddAssign: AddAssign {} - -/// Trait for closed addition assignment operation with the right-hand side as a reference. -pub trait ClosedAddAssignRef: for<'a> AddAssign<&'a Rhs> {} - -/// Trait for closed subtraction assignment operation. -pub trait ClosedSubAssign: SubAssign {} - -/// Trait for closed subtraction assignment operation with the right-hand side as a reference. -pub trait ClosedSubAssignRef: for<'a> SubAssign<&'a Rhs> {} - -/// Trait for closed multiplication assignment operation. -pub trait ClosedMulAssign: MulAssign {} - -/// Trait for closed multiplication assignment operation with the right-hand side as a reference. -pub trait ClosedMulAssignRef: for<'a> MulAssign<&'a Rhs> {} - -/// Trait for closed division assignment operation. -pub trait ClosedDivAssign: DivAssign {} - -/// Trait for closed division assignment operation with the right-hand side as a reference. -pub trait ClosedDivAssignRef: for<'a> DivAssign<&'a Rhs> {} - -/// Trait for closed remainder assignment operation. -pub trait ClosedRemAssign: RemAssign {} - -/// Trait for closed remainder assignment operation with the right-hand side as a reference. -pub trait ClosedRemAssignRef: for<'a> RemAssign<&'a Rhs> {} - -/// Trait for closed bitwise AND operation. -pub trait ClosedBitAnd: BitAnd {} - -/// Trait for closed bitwise AND operation with the right-hand side as a reference. -pub trait ClosedBitAndRef: for<'a> BitAnd<&'a Rhs, Output = Self> {} - -/// Trait for closed bitwise OR operation. -pub trait ClosedBitOr: BitOr {} - -/// Trait for closed bitwise OR operation with the right-hand side as a reference. -pub trait ClosedBitOrRef: for<'a> BitOr<&'a Rhs, Output = Self> {} - -/// Trait for closed bitwise XOR operation. -pub trait ClosedBitXor: BitXor {} - -/// Trait for closed bitwise XOR operation with the right-hand side as a reference. -pub trait ClosedBitXorRef: for<'a> BitXor<&'a Rhs, Output = Self> {} - -/// Trait for closed bitwise NOT operation. -pub trait ClosedNot: Not {} - -/// Trait for closed left shift operation. -pub trait ClosedShl: Shl {} - -/// Trait for closed left shift operation with the right-hand side as a reference. -pub trait ClosedShlRef: for<'a> Shl<&'a Rhs, Output = Self> {} - -/// Trait for closed right shift operation. -pub trait ClosedShr: Shr {} - -/// Trait for closed right shift operation with the right-hand side as a reference. -pub trait ClosedShrRef: for<'a> Shr<&'a Rhs, Output = Self> {} - -/// Trait for closed bitwise AND assignment operation. -pub trait ClosedBitAndAssign: BitAndAssign {} - -/// Trait for closed bitwise AND assignment operation with the right-hand side as a reference. -pub trait ClosedBitAndAssignRef: for<'a> BitAndAssign<&'a Rhs> {} - -/// Trait for closed bitwise OR assignment operation. -pub trait ClosedBitOrAssign: BitOrAssign {} - -/// Trait for closed bitwise OR assignment operation with the right-hand side as a reference. -pub trait ClosedBitOrAssignRef: for<'a> BitOrAssign<&'a Rhs> {} - -/// Trait for closed bitwise XOR assignment operation. -pub trait ClosedBitXorAssign: BitXorAssign {} - -/// Trait for closed bitwise XOR assignment operation with the right-hand side as a reference. -pub trait ClosedBitXorAssignRef: for<'a> BitXorAssign<&'a Rhs> {} - -/// Trait for closed left shift assignment operation. -pub trait ClosedShlAssign: ShlAssign {} - -/// Trait for closed left shift assignment operation with the right-hand side as a reference. -pub trait ClosedShlAssignRef: for<'a> ShlAssign<&'a Rhs> {} - -/// Trait for closed right shift assignment operation. -pub trait ClosedShrAssign: ShrAssign {} - -/// Trait for closed right shift assignment operation with the right-hand side as a reference. -pub trait ClosedShrAssignRef: for<'a> ShrAssign<&'a Rhs> {} - -/// Trait for types with a closed zero value. -pub trait ClosedZero: Zero {} - -/// Trait for types with a closed one value. -pub trait ClosedOne: One {} - -/// Trait for closed Euclidean division operation -pub trait ClosedDivEuclid: Sized { - fn div_euclid(self, rhs: Self) -> Self; -} - -/// Trait for closed Euclidean remainder operation -pub trait ClosedRemEuclid: Sized { - fn rem_euclid(self, rhs: Self) -> Self; -} - -// Blanket implementations -impl ClosedDivEuclid for T -where - T: Euclid, -{ - fn div_euclid(self, rhs: Self) -> Self { - Euclid::div_euclid(&self, &rhs) - } -} - -impl ClosedRemEuclid for T -where - T: Euclid, -{ - fn rem_euclid(self, rhs: Self) -> Self { - Euclid::rem_euclid(&self, &rhs) - } -} - -/// Trait for closed minimum operation -pub trait ClosedMin: Sized { - fn min(self, other: Rhs) -> Self; -} - -/// Trait for closed maximum operation -pub trait ClosedMax: Sized { - fn max(self, other: Rhs) -> Self; -} - -impl ClosedAdd for T where T: Add {} -impl ClosedAddRef for T where T: for<'a> Add<&'a Rhs, Output = T> {} -impl ClosedSub for T where T: Sub {} -impl ClosedSubRef for T where T: for<'a> Sub<&'a Rhs, Output = T> {} -impl ClosedMul for T where T: Mul {} -impl ClosedMulRef for T where T: for<'a> Mul<&'a Rhs, Output = T> {} -impl ClosedDiv for T where T: Div {} -impl ClosedDivRef for T where T: for<'a> Div<&'a Rhs, Output = T> {} -impl ClosedRem for T where T: Rem {} -impl ClosedRemRef for T where T: for<'a> Rem<&'a Rhs, Output = T> {} -impl ClosedNeg for T where T: Neg {} -impl ClosedInv for T where T: Inv {} - -impl ClosedAddAssign for T where T: AddAssign {} -impl ClosedAddAssignRef for T where T: for<'a> AddAssign<&'a Rhs> {} -impl ClosedSubAssign for T where T: SubAssign {} -impl ClosedSubAssignRef for T where T: for<'a> SubAssign<&'a Rhs> {} -impl ClosedMulAssign for T where T: MulAssign {} -impl ClosedMulAssignRef for T where T: for<'a> MulAssign<&'a Rhs> {} -impl ClosedDivAssign for T where T: DivAssign {} -impl ClosedDivAssignRef for T where T: for<'a> DivAssign<&'a Rhs> {} -impl ClosedRemAssign for T where T: RemAssign {} -impl ClosedRemAssignRef for T where T: for<'a> RemAssign<&'a Rhs> {} - -impl ClosedBitAnd for T where T: BitAnd {} -impl ClosedBitAndRef for T where T: for<'a> BitAnd<&'a Rhs, Output = T> {} -impl ClosedBitOr for T where T: BitOr {} -impl ClosedBitOrRef for T where T: for<'a> BitOr<&'a Rhs, Output = T> {} -impl ClosedBitXor for T where T: BitXor {} -impl ClosedBitXorRef for T where T: for<'a> BitXor<&'a Rhs, Output = T> {} -impl ClosedNot for T where T: Not {} -impl ClosedShl for T where T: Shl {} -impl ClosedShlRef for T where T: for<'a> Shl<&'a Rhs, Output = T> {} -impl ClosedShr for T where T: Shr {} -impl ClosedShrRef for T where T: for<'a> Shr<&'a Rhs, Output = T> {} - -impl ClosedBitAndAssign for T where T: BitAndAssign {} -impl ClosedBitAndAssignRef for T where T: for<'a> BitAndAssign<&'a Rhs> {} -impl ClosedBitOrAssign for T where T: BitOrAssign {} -impl ClosedBitOrAssignRef for T where T: for<'a> BitOrAssign<&'a Rhs> {} -impl ClosedBitXorAssign for T where T: BitXorAssign {} -impl ClosedBitXorAssignRef for T where T: for<'a> BitXorAssign<&'a Rhs> {} -impl ClosedShlAssign for T where T: ShlAssign {} -impl ClosedShlAssignRef for T where T: for<'a> ShlAssign<&'a Rhs> {} -impl ClosedShrAssign for T where T: ShrAssign {} -impl ClosedShrAssignRef for T where T: for<'a> ShrAssign<&'a Rhs> {} - -impl ClosedZero for T {} -impl ClosedOne for T {} - -impl ClosedMin for T { - fn min(self, other: Self) -> Self { - std::cmp::min(self, other) - } -} - -impl ClosedMax for T { - fn max(self, other: Self) -> Self { - std::cmp::max(self, other) - } -} diff --git a/src/pid.rs b/src/pid.rs deleted file mode 100644 index 880b998..0000000 --- a/src/pid.rs +++ /dev/null @@ -1,67 +0,0 @@ -use crate::UniqueFactorizationDomain; -use num_traits::Euclid; - -/// Represents a Principal Ideal Domain (PID), an integral domain where every ideal is principal. -/// -/// A Principal Ideal Domain (R, +, Β·) is an integral domain that satisfies: -/// 1. (R, +, Β·) is an integral domain -/// 2. Every ideal in R is principal (can be generated by a single element) -/// -/// Formal Definition: -/// Let R be an integral domain. R is a PID if for every ideal I βŠ† R, there exists an element a ∈ R -/// such that I = (a) = {ra | r ∈ R}. -pub trait PrincipalIdealDomain: UniqueFactorizationDomain + Euclid {} - -impl PrincipalIdealDomain for T where T: UniqueFactorizationDomain + Euclid {} - -#[cfg(test)] -mod tests { - use crate::concrete::Z5; - use crate::PrincipalIdealDomain; - use num_traits::Zero; - - #[test] - fn test_z5_implements_pid() { - fn assert_pid() {} - assert_pid::(); - } - - #[test] - fn test_z5_euclidean_division() { - for i in 0..5 { - for j in 1..5 { - // Avoid division by zero - let a = Z5::new(i); - let b = Z5::new(j); - let (q, r) = a.div_rem_euclid(&b); - assert_eq!(a, q * b + r); - assert!(r.is_zero() || r < b); - } - } - } - - // TODO(Test GCD) - - #[test] - fn test_z5_principal_ideals() { - for i in 0..5 { - let a = Z5::new(i); - let ideal = generate_ideal(a); - assert!(is_principal_ideal(&ideal)); - } - } - - fn generate_ideal(a: Z5) -> Vec { - (0..5).map(|i| a * Z5::new(i)).collect() - } - - fn is_principal_ideal(ideal: &[Z5]) -> bool { - if ideal.is_empty() { - return true; // The zero ideal is principal - } - let binding = Z5::zero(); - let generator = ideal.iter().find(|&&x| !x.is_zero()).unwrap_or(&binding); - let generated_ideal = generate_ideal(*generator); - ideal.iter().all(|elem| generated_ideal.contains(elem)) - } -} diff --git a/src/real_field.rs b/src/real_field.rs deleted file mode 100644 index 471db4c..0000000 --- a/src/real_field.rs +++ /dev/null @@ -1,54 +0,0 @@ -use crate::Field; - -/// Represents a Real Field, an ordered field that satisfies the completeness axiom. -/// -/// A real field (F, +, Β·, ≀) consists of: -/// - A set F -/// - Two binary operations + (addition) and Β· (multiplication) -/// - A total order relation ≀ -/// -/// Formal Definition: -/// 1. (F, +, Β·) is a field -/// 2. (F, ≀) is a totally ordered set -/// 3. The order is compatible with field operations -/// 4. F satisfies the completeness axiom -pub trait RealField: Field + PartialOrd + Ord { - /// Returns the absolute value of the number. - fn abs(&self) -> Self; - - /// Returns the square root of the number, if it exists. - fn sqrt(&self) -> Option; - - /// Computes the natural logarithm of the number. - fn ln(&self) -> Self; - - /// Raises e (Euler's number) to the power of self. - fn exp(&self) -> Self; - - /// Computes the sine of the number (assumed to be in radians). - fn sin(&self) -> Self; - - /// Computes the cosine of the number (assumed to be in radians). - fn cos(&self) -> Self; - - /// Computes the tangent of the number (assumed to be in radians). - fn tan(&self) -> Self; - - /// Returns the smallest integer greater than or equal to the number. - fn ceil(&self) -> Self; - - /// Returns the largest integer less than or equal to the number. - fn floor(&self) -> Self; - - /// Rounds the number to the nearest integer. - fn round(&self) -> Self; - - /// Checks if the number is finite (not infinite and not NaN). - fn is_finite(&self) -> bool; - - /// Checks if the number is infinite. - fn is_infinite(&self) -> bool; - - /// Checks if the number is NaN (Not a Number). - fn is_nan(&self) -> bool; -} diff --git a/src/ring.rs b/src/ring.rs deleted file mode 100644 index 7e01d3f..0000000 --- a/src/ring.rs +++ /dev/null @@ -1,104 +0,0 @@ -use crate::{AdditiveAbelianGroup, Distributive, MultiplicativeMonoid}; - -/// Represents a Ring, an algebraic structure with two binary operations (addition and multiplication) -/// that satisfy certain axioms. -/// -/// A ring (R, +, Β·) consists of: -/// - A set R -/// - Two binary operations + (addition) and Β· (multiplication) on R -/// -/// Formal Definition: -/// Let (R, +, Β·) be a ring. Then: -/// 1. (R, +) is an abelian group: -/// a. βˆ€ a, b, c ∈ R, (a + b) + c = a + (b + c) (associativity) -/// b. βˆ€ a, b ∈ R, a + b = b + a (commutativity) -/// c. βˆƒ 0 ∈ R, βˆ€ a ∈ R, a + 0 = 0 + a = a (identity) -/// d. βˆ€ a ∈ R, βˆƒ -a ∈ R, a + (-a) = (-a) + a = 0 (inverse) -/// 2. (R, Β·) is a monoid: -/// a. βˆ€ a, b, c ∈ R, (a Β· b) Β· c = a Β· (b Β· c) (associativity) -/// b. βˆƒ 1 ∈ R, βˆ€ a ∈ R, 1 Β· a = a Β· 1 = a (identity) -/// 3. Multiplication is distributive over addition: -/// a. βˆ€ a, b, c ∈ R, a Β· (b + c) = (a Β· b) + (a Β· c) (left distributivity) -/// b. βˆ€ a, b, c ∈ R, (a + b) Β· c = (a Β· c) + (b Β· c) (right distributivity) -pub trait Ring: AdditiveAbelianGroup + MultiplicativeMonoid + Distributive {} - -impl Ring for T where T: AdditiveAbelianGroup + MultiplicativeMonoid + Distributive {} - -#[cfg(test)] -mod tests { - use super::*; - use crate::concrete::Z5; - use num_traits::{One, Zero}; - - #[test] - fn test_z5_ring() { - // Test additive abelian group properties - for i in 0..5 { - for j in 0..5 { - let a = Z5::new(i); - let b = Z5::new(j); - - // Commutativity - assert_eq!(a + b, b + a); - - // Associativity - let c = Z5::new((i + j) % 5); - assert_eq!((a + b) + c, a + (b + c)); - } - } - - // Test additive identity and inverse - let zero = Z5::zero(); - for i in 0..5 { - let a = Z5::new(i); - assert_eq!(a + zero, a); - assert_eq!(zero + a, a); - let neg_a = -a; - assert_eq!(a + neg_a, zero); - assert_eq!(neg_a + a, zero); - } - - // Test multiplicative monoid properties - for i in 0..5 { - for j in 0..5 { - let a = Z5::new(i); - let b = Z5::new(j); - - // Associativity - let c = Z5::new((i * j) % 5); - assert_eq!((a * b) * c, a * (b * c)); - } - } - - // Test multiplicative identity - let one = Z5::one(); - for i in 0..5 { - let a = Z5::new(i); - assert_eq!(a * one, a); - assert_eq!(one * a, a); - } - - // Test distributivity - for i in 0..5 { - for j in 0..5 { - for k in 0..5 { - let a = Z5::new(i); - let b = Z5::new(j); - let c = Z5::new(k); - - // Left distributivity - assert_eq!(a * (b + c), (a * b) + (a * c)); - - // Right distributivity - assert_eq!((a + b) * c, (a * c) + (b * c)); - } - } - } - } - - #[test] - fn test_z5_implements_ring() { - fn assert_ring() {} - assert_ring::(); - } -} diff --git a/src/semigroup.rs b/src/semigroup.rs deleted file mode 100644 index ea1c605..0000000 --- a/src/semigroup.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::magma::{AdditiveMagma, MultiplicativeMagma}; -use crate::operator::{ClosedAdd, ClosedMul}; -use crate::Associative; - -/// If this trait is implemented, the object implements Additive Semigroup, an -/// algebraic structure with a set and an associative closed addition operation. -/// -/// An additive semigroup (S, +) consists of: -/// - A set S -/// - A binary operation +: S Γ— S β†’ S that is associative -/// -/// Formal Definition: -/// Let (S, +) be an additive semigroup. Then: -/// βˆ€ a, b, c ∈ S, (a + b) + c = a + (b + c) (associativity) -/// -/// Properties: -/// - Closure: βˆ€ a, b ∈ S, a + b ∈ S -/// - Associativity: βˆ€ a, b, c ∈ S, (a + b) + c = a + (b + c) -pub trait AdditiveSemigroup: AdditiveMagma + ClosedAdd + Associative {} - -/// If this trait is implemented, the object implements a Multiplicative Semigroup, an algebraic -/// structure with a set and an associative closed multiplication operation. -/// -/// A multiplicative semigroup (S, βˆ™) consists of: -/// - A set S -/// - A binary operation βˆ™: S Γ— S β†’ S that is associative -/// -/// Formal Definition: -/// Let (S, βˆ™) be a multiplicative semigroup. Then: -/// βˆ€ a, b, c ∈ S, (a βˆ™ b) βˆ™ c = a βˆ™ (b βˆ™ c) (associativity) -/// -/// Properties: -/// - Closure: βˆ€ a, b ∈ S, a βˆ™ b ∈ S -/// - Associativity: βˆ€ a, b, c ∈ S, (a βˆ™ b) βˆ™ c = a βˆ™ (b βˆ™ c) -pub trait MultiplicativeSemigroup: MultiplicativeMagma + ClosedMul + Associative {} - -// Blanket implementations -impl AdditiveSemigroup for T where T: AdditiveMagma + ClosedAdd + Associative {} -impl MultiplicativeSemigroup for T where T: MultiplicativeMagma + ClosedMul + Associative {} - -#[cfg(test)] -mod tests { - use super::*; - use std::ops::{Add, Mul}; - - // Test structures - #[derive(Clone, PartialEq, Debug)] - struct IntegerAdditiveSemigroup(i32); - - #[derive(Clone, PartialEq, Debug)] - struct StringMultiplicativeSemigroup(String); - - impl Associative for IntegerAdditiveSemigroup {} - - // Implement the necessary traits for IntegerAdditiveSemigroup - impl Add for IntegerAdditiveSemigroup { - type Output = Self; - fn add(self, other: Self) -> Self { - IntegerAdditiveSemigroup(self.0 + other.0) - } - } - - // Implement necessary traits for StringMultiplicativeSemigroup - impl Mul for StringMultiplicativeSemigroup { - type Output = Self; - fn mul(self, other: Self) -> Self { - StringMultiplicativeSemigroup(self.0 + &other.0) - } - } - - #[test] - fn test_additive_semigroup() { - let a = IntegerAdditiveSemigroup(2); - let b = IntegerAdditiveSemigroup(3); - let c = IntegerAdditiveSemigroup(4); - - // Test associativity - assert_eq!((a.clone() + b.clone()) + c.clone(), a + (b + c)); - } - - #[test] - fn test_multiplicative_semigroup() { - let a = StringMultiplicativeSemigroup("a".to_string()); - let b = StringMultiplicativeSemigroup("b".to_string()); - let c = StringMultiplicativeSemigroup("c".to_string()); - - // Test associativity - assert_eq!((a.clone() * b.clone()) * c.clone(), a * (b * c)); - } -} diff --git a/src/semiring.rs b/src/semiring.rs deleted file mode 100644 index 83969d4..0000000 --- a/src/semiring.rs +++ /dev/null @@ -1,111 +0,0 @@ -use crate::monoid::{AdditiveMonoid, MultiplicativeMonoid}; -use crate::Distributive; - -/// Represents a Semiring, an algebraic structure with two binary operations (addition and multiplication) -/// that satisfy certain axioms. -/// -/// A semiring (S, +, Β·, 0, 1) consists of: -/// - A set S -/// - Two binary operations + (addition) and Β· (multiplication) on S -/// - Two distinguished elements 0 (zero) and 1 (one) of S -/// -/// Formal Definition: -/// Let (S, +, Β·, 0, 1) be a semiring. Then: -/// 1. (S, +, 0) is a commutative monoid: -/// a. βˆ€ a, b, c ∈ S, (a + b) + c = a + (b + c) (associativity) -/// b. βˆ€ a, b ∈ S, a + b = b + a (commutativity) -/// c. βˆ€ a ∈ S, a + 0 = a = 0 + a (identity) -/// 2. (S, Β·, 1) is a monoid: -/// a. βˆ€ a, b, c ∈ S, (a Β· b) Β· c = a Β· (b Β· c) (associativity) -/// b. βˆ€ a ∈ S, a Β· 1 = a = 1 Β· a (identity) -/// 3. Multiplication distributes over addition: -/// a. βˆ€ a, b, c ∈ S, a Β· (b + c) = (a Β· b) + (a Β· c) (left distributivity) -/// b. βˆ€ a, b, c ∈ S, (a + b) Β· c = (a Β· c) + (b Β· c) (right distributivity) -/// 4. Multiplication by 0 annihilates S: -/// βˆ€ a ∈ S, 0 Β· a = 0 = a Β· 0 -pub trait Semiring: AdditiveMonoid + MultiplicativeMonoid + Distributive {} - -impl Semiring for T where T: AdditiveMonoid + MultiplicativeMonoid + Distributive {} - -#[cfg(test)] -mod tests { - use super::*; - use crate::concrete::Z5; - use num_traits::{One, Zero}; - - #[test] - fn test_z5_semiring() { - // Test additive abelian group properties - for i in 0..5 { - for j in 0..5 { - let a = Z5::new(i); - let b = Z5::new(j); - - // Commutativity - assert_eq!(a + b, b + a); - - // Associativity - let c = Z5::new((i + j) % 5); - assert_eq!((a + b) + c, a + (b + c)); - } - } - - // Test additive identity - let zero = Z5::zero(); - for i in 0..5 { - let a = Z5::new(i); - assert_eq!(a + zero, a); - assert_eq!(zero + a, a); - } - - // Test multiplicative monoid properties - for i in 0..5 { - for j in 0..5 { - let a = Z5::new(i); - let b = Z5::new(j); - - // Associativity - let c = Z5::new((i * j) % 5); - assert_eq!((a * b) * c, a * (b * c)); - } - } - - // Test multiplicative identity - let one = Z5::one(); - for i in 0..5 { - let a = Z5::new(i); - assert_eq!(a * one, a); - assert_eq!(one * a, a); - } - - // Test distributivity - for i in 0..5 { - for j in 0..5 { - for k in 0..5 { - let a = Z5::new(i); - let b = Z5::new(j); - let c = Z5::new(k); - - // Left distributivity - assert_eq!(a * (b + c), (a * b) + (a * c)); - - // Right distributivity - assert_eq!((a + b) * c, (a * c) + (b * c)); - } - } - } - - // Test multiplication by zero - for i in 0..5 { - let a = Z5::new(i); - assert_eq!(a * zero, zero); - assert_eq!(zero * a, zero); - } - } - - #[test] - fn test_z5_implements_semiring() { - fn assert_semiring() {} - assert_semiring::(); - } -} diff --git a/src/set.rs b/src/set.rs deleted file mode 100644 index 93e4ae3..0000000 --- a/src/set.rs +++ /dev/null @@ -1,154 +0,0 @@ -use std::fmt::Debug; - -/// Represents a mathematical set as defined in Zermelo-Fraenkel set theory with Choice (ZFC). -/// -/// # Formal Notation -/// - βˆ…: empty set -/// - ∈: element of -/// - βŠ†: subset of -/// - βˆͺ: union -/// - ∩: intersection -/// - \: set difference -/// - Ξ”: symmetric difference -/// - |A|: cardinality of set A -/// -/// # Axioms of ZFC -/// 1. Extensionality: βˆ€Aβˆ€B(βˆ€x(x ∈ A ↔ x ∈ B) β†’ A = B) -/// 2. Empty Set: βˆƒAβˆ€x(x βˆ‰ A) -/// 3. Pairing: βˆ€aβˆ€bβˆƒAβˆ€x(x ∈ A ↔ x = a ∨ x = b) -/// 4. Union: βˆ€FβˆƒAβˆ€x(x ∈ A ↔ βˆƒB(x ∈ B ∧ B ∈ F)) -/// 5. Power Set: βˆ€AβˆƒPβˆ€x(x ∈ P ↔ x βŠ† A) -/// 6. Infinity: βˆƒA(βˆ… ∈ A ∧ βˆ€x(x ∈ A β†’ x βˆͺ {x} ∈ A)) -/// 7. Separation: βˆ€AβˆƒBβˆ€x(x ∈ B ↔ x ∈ A ∧ Ο†(x)) for any formula Ο† -/// 8. Replacement: βˆ€A(βˆ€xβˆ€yβˆ€z((x ∈ A ∧ Ο†(x,y) ∧ Ο†(x,z)) β†’ y = z) β†’ βˆƒBβˆ€y(y ∈ B ↔ βˆƒx(x ∈ A ∧ Ο†(x,y)))) -/// 9. Foundation: βˆ€A(A β‰  βˆ… β†’ βˆƒx(x ∈ A ∧ x ∩ A = βˆ…)) -/// 10. Choice: βˆ€A(βˆ… βˆ‰ A β†’ βˆƒf:A β†’ βˆͺA βˆ€B∈A(f(B) ∈ B)) -/// -/// TODO(There is significant reasoning to do here about what might be covered by std traits, partial equivalence relations, etc.) -pub trait Set: Sized + Clone + PartialEq + Debug { - type Element; - - /// Returns true if the set is empty (βˆ…). - /// βˆ€x(x βˆ‰ self) - fn is_empty(&self) -> bool; - - /// Checks if the given element is a member of the set. - /// element ∈ self - fn contains(&self, element: &Self::Element) -> bool; - - /// Creates an empty set (βˆ…). - /// βˆƒAβˆ€x(x βˆ‰ A) - fn empty() -> Self; - - /// Creates a singleton set containing the given element. - /// βˆƒAβˆ€x(x ∈ A ↔ x = element) - fn singleton(element: Self::Element) -> Self; - - /// Returns the union of this set with another set. - /// βˆ€x(x ∈ result ↔ x ∈ self ∨ x ∈ other) - fn union(&self, other: &Self) -> Self; - - /// Returns the intersection of this set with another set. - /// βˆ€x(x ∈ result ↔ x ∈ self ∧ x ∈ other) - fn intersection(&self, other: &Self) -> Self; - - /// Returns the difference of this set and another set (self - other). - /// βˆ€x(x ∈ result ↔ x ∈ self ∧ x βˆ‰ other) - fn difference(&self, other: &Self) -> Self; - - /// Returns the symmetric difference of this set and another set. - /// βˆ€x(x ∈ result ↔ (x ∈ self ∧ x βˆ‰ other) ∨ (x βˆ‰ self ∧ x ∈ other)) - fn symmetric_difference(&self, other: &Self) -> Self; - - /// Checks if this set is a subset of another set. - /// self βŠ† other ↔ βˆ€x(x ∈ self β†’ x ∈ other) - fn is_subset(&self, other: &Self) -> bool; - - /// Checks if two sets are equal (by the Axiom of Extensionality). - /// self = other ↔ βˆ€x(x ∈ self ↔ x ∈ other) - fn is_equal(&self, other: &Self) -> bool; - - /// Returns the cardinality of the set. Returns None if the set is infinite. - /// |self| if self is finite, None otherwise - fn cardinality(&self) -> Option; - - /// Returns true if the set is finite, false otherwise. - fn is_finite(&self) -> bool; -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::concrete::{InfiniteRealSet, Z5}; - - #[test] - fn test_z5_set_operations() { - let a = Z5::new(2); - let b = Z5::new(3); - let c = Z5::new(2); - - assert!(!a.is_empty()); - assert!(a.contains(&Z5::new(2))); - assert!(!a.contains(&Z5::new(3))); - - assert_eq!(Z5::empty(), Z5::new(0)); - assert_eq!(Z5::singleton(Z5::new(2)), a); - - assert_eq!(a.union(&b), Z5::new(2)); - assert_eq!(a.intersection(&b), Z5::new(0)); - assert_eq!(a.intersection(&c), a); - - assert_eq!(a.difference(&b), a); - assert_eq!(a.difference(&c), Z5::new(0)); - - assert_eq!(a.symmetric_difference(&b), Z5::new(3)); - assert_eq!(a.symmetric_difference(&c), Z5::new(0)); - - assert!(a.is_subset(&a)); - assert!(!a.is_subset(&b)); - - assert!(a.is_equal(&c)); - assert!(!a.is_equal(&b)); - - assert_eq!(a.cardinality(), Some(5)); - assert!(a.is_finite()); - } - - #[test] - fn test_infinite_real_set_operations() { - let a = InfiniteRealSet; - let b = InfiniteRealSet; - - assert!(!a.is_empty()); - assert!(a.contains(&3.14)); - assert!(a.contains(&-1000.0)); - - assert_eq!(InfiniteRealSet::empty(), InfiniteRealSet); - assert_eq!(InfiniteRealSet::singleton(3.14), InfiniteRealSet); - - assert_eq!(a.union(&b), InfiniteRealSet); - assert_eq!(a.intersection(&b), InfiniteRealSet); - assert_eq!(a.difference(&b), InfiniteRealSet); - assert_eq!(a.symmetric_difference(&b), InfiniteRealSet); - - assert!(a.is_subset(&b)); - assert!(a.is_equal(&b)); - - assert_eq!(a.cardinality(), None); - assert!(!a.is_finite()); - } - - #[test] - fn test_z5_edge_cases() { - let zero = Z5::new(0); - let five = Z5::new(5); - - assert_eq!(zero, five); - assert_eq!(Z5::new(7), Z5::new(2)); - - assert_eq!(zero.union(&five), zero); - assert_eq!(zero.intersection(&five), zero); - assert_eq!(zero.difference(&five), zero); - assert_eq!(zero.symmetric_difference(&five), zero); - } -} diff --git a/src/ufd.rs b/src/ufd.rs deleted file mode 100644 index fce317f..0000000 --- a/src/ufd.rs +++ /dev/null @@ -1,87 +0,0 @@ -use crate::integral_domain::IntegralDomain; - -/// Represents a Unique Factorization Domain (UFD), an integral domain where every non-zero -/// non-unit element has a unique factorization into irreducible elements. -/// -/// A UFD (R, +, Β·) is an integral domain that satisfies: -/// 1. Every non-zero non-unit element can be factored into irreducible elements. -/// 2. This factorization is unique up to order and associates. -/// -/// Formal Definition: -/// Let R be an integral domain. R is a UFD if: -/// 1. For every non-zero non-unit a ∈ R, there exist irreducible elements p₁, ..., pβ‚™ such that -/// a = p₁ Β· ... Β· pβ‚™ -/// 2. If a = p₁ Β· ... Β· pβ‚™ = q₁ Β· ... Β· qβ‚˜ are two factorizations of a into irreducible elements, -/// then n = m and there exists a bijection Οƒ: {1, ..., n} β†’ {1, ..., n} such that pα΅’ is -/// associated to qβ‚›α΅’ for all i. -pub trait UniqueFactorizationDomain: IntegralDomain {} - -impl UniqueFactorizationDomain for T where T: IntegralDomain {} - -#[cfg(test)] -mod tests { - use super::*; - use crate::concrete::Z5; - use num_traits::{One, Zero}; - - fn is_irreducible(a: &Z5) -> bool { - !a.is_zero() && !a.is_one() - } - - fn factor(a: &Z5) -> Vec { - if a.is_zero() || a.is_one() { - vec![*a] - } else { - vec![*a] // In Z5, all non-zero, non-one elements are irreducible - } - } - - fn are_associates(a: &Z5, b: &Z5) -> bool { - !a.is_zero() && !b.is_zero() - } - - fn check_unique_factorization(a: &Z5) -> bool { - let factorization = factor(a); - - if a.is_zero() || a.is_one() { - factorization.len() == 1 && factorization[0] == *a - } else { - factorization.len() == 1 && is_irreducible(&factorization[0]) - } - } - - #[test] - fn test_z5_ufd() { - // Test irreducibility - assert!(!is_irreducible(&Z5::new(0))); - assert!(!is_irreducible(&Z5::new(1))); - assert!(is_irreducible(&Z5::new(2))); - assert!(is_irreducible(&Z5::new(3))); - assert!(is_irreducible(&Z5::new(4))); - - // Test factorization - assert_eq!(factor(&Z5::new(0)), vec![Z5::new(0)]); - assert_eq!(factor(&Z5::new(1)), vec![Z5::new(1)]); - assert_eq!(factor(&Z5::new(2)), vec![Z5::new(2)]); - assert_eq!(factor(&Z5::new(3)), vec![Z5::new(3)]); - assert_eq!(factor(&Z5::new(4)), vec![Z5::new(4)]); - - // Test associates - for i in 1..5 { - for j in 1..5 { - assert!(are_associates(&Z5::new(i), &Z5::new(j))); - } - } - - // Test unique factorization - for i in 0..5 { - assert!(check_unique_factorization(&Z5::new(i))); - } - } - - #[test] - fn test_z5_implements_ufd() { - fn assert_ufd() {} - assert_ufd::(); - } -} From 5d069b9189abbf7f38d5e05ed581b07c9b5ee03e Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Sat, 13 Jul 2024 06:14:53 -0400 Subject: [PATCH 14/21] fix: cleanup lints --- src/lib.rs | 53 +++++++++++++++-------------------------------------- 1 file changed, 15 insertions(+), 38 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 96cd961..c0a4ac4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -161,11 +161,7 @@ //! still manually implement these traits for your types, and the manual implementations //! will take precedence over these blanket implementations. -mod concrete_finite; - -pub use concrete_finite::*; - -use num_traits::{CheckedEuclid, Euclid, Inv, One, Zero}; +use num_traits::{Euclid, Inv, One, Zero}; use std::ops::{ Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign, }; @@ -253,7 +249,6 @@ pub trait ClosedRemAssign: RemAssign {} /// Trait for closed remainder assignment operation with the right-hand side as a reference. pub trait ClosedRemAssignRef: for<'a> RemAssign<&'a Rhs> {} - /// Trait for types with a closed zero value. pub trait ClosedZero: Zero {} @@ -589,9 +584,15 @@ impl MultiplicativeAbelianGroup for T where T: MultiplicativeGroup + Commutat /// - Left distributivity: βˆ€a,b,c ∈ R, a Β· (b + c) = (a Β· b) + (a Β· c) /// - Right distributivity: βˆ€a,b,c ∈ R, (a + b) Β· c = (a Β· c) + (b Β· c) /// - Multiplication by 0 annihilates R: βˆ€a ∈ R, 0 Β· a = a Β· 0 = 0 -pub trait Semiring: AdditiveMonoid + CommutativeAddition + MultiplicativeMonoid + DistributiveAddition {} +pub trait Semiring: + AdditiveMonoid + CommutativeAddition + MultiplicativeMonoid + DistributiveAddition +{ +} -impl Semiring for T where T: AdditiveMonoid + CommutativeAddition + MultiplicativeMonoid + DistributiveAddition {} +impl Semiring for T where + T: AdditiveMonoid + CommutativeAddition + MultiplicativeMonoid + DistributiveAddition +{ +} /// Represents a Ring, an algebraic structure with two binary operations (addition and multiplication) /// that satisfy certain axioms. @@ -664,8 +665,7 @@ pub trait IntegralDomain: Ring { } } -impl IntegralDomain for T where T: Ring { -} +impl IntegralDomain for T where T: Ring {} /// Represents a Unique Factorization Domain (UFD), an integral domain where every non-zero /// non-unit element has a unique factorization into irreducible elements. @@ -817,8 +817,7 @@ pub trait FiniteField: Field { /// 3. The order is compatible with field operations /// 4. F satisfies the completeness axiom /// 5. Dedekind-complete: Every non-empty subset of ℝ with an upper bound has a least upper bound in ℝ -pub trait RealField: Field + PartialOrd { -} +pub trait RealField: Field + PartialOrd {} /// Represents a Polynomial over a field. /// @@ -1047,7 +1046,9 @@ pub trait FieldExtensionTower: FieldExtension { /// /// # Formal Notation /// For a tower K = Fβ‚€ βŠ‚ F₁ βŠ‚ ... βŠ‚ Fβ‚™ = L, yields the minimal polynomials of F₁/Fβ‚€, Fβ‚‚/F₁, ..., Fβ‚™/Fₙ₋₁ - fn minimal_polynomials() -> Box>>>; + //fn minimal_polynomials( + //) -> Box>>>; + // TODO(Better pattern here) /// Embeds an element from any field in the tower into the top field. /// @@ -1061,30 +1062,6 @@ pub trait FieldExtensionTower: FieldExtension { /// For an element a ∈ L, attempts to find its preimage in Fα΅’, if it exists fn project_from_top(element: &Self::Level, to_level: usize) -> Option; - /// Checks if the entire tower consists of normal extensions. - /// - /// # Formal Notation - /// Returns true if each Fα΅’β‚Šβ‚/Fα΅’ is a normal extension - fn is_normal() -> bool { - Self::fields().all(|field| field.is_normal()) - } - - /// Checks if the entire tower consists of separable extensions. - /// - /// # Formal Notation - /// Returns true if each Fα΅’β‚Šβ‚/Fα΅’ is a separable extension - fn is_separable() -> bool { - Self::fields().all(|field| field.is_separable()) - } - - /// Checks if the entire tower consists of algebraic extensions. - /// - /// # Formal Notation - /// Returns true if each Fα΅’β‚Šβ‚/Fα΅’ is an algebraic extension - fn is_algebraic() -> bool { - Self::fields().all(|field| field.is_algebraic()) - } - /// Checks if the tower is Galois (normal and separable). /// /// # Formal Notation @@ -1117,4 +1094,4 @@ pub trait FieldExtensionTower: FieldExtension { /// # Formal Notation /// Yields all fields F such that K βŠ† F βŠ† L fn intermediate_fields() -> Box>; -} \ No newline at end of file +} From bc0d59c1224192e30da61580d055d6baa3f7f079 Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Sat, 13 Jul 2024 06:20:35 -0400 Subject: [PATCH 15/21] fix: remove benches for now --- Cargo.toml | 9 +-------- benches/benchmarks.rs | 1 - 2 files changed, 1 insertion(+), 9 deletions(-) delete mode 100644 benches/benchmarks.rs diff --git a/Cargo.toml b/Cargo.toml index dc4048e..885d5c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,11 +16,4 @@ edition = "2021" [dependencies] num-traits = "0.2.19" -[lib] - -[dev-dependencies] -criterion = "0.5.1" - -[[bench]] -name = "benchmarks" -harness = false +[lib] \ No newline at end of file diff --git a/benches/benchmarks.rs b/benches/benchmarks.rs deleted file mode 100644 index 8b13789..0000000 --- a/benches/benchmarks.rs +++ /dev/null @@ -1 +0,0 @@ - From e9dddfea71b2c1d39e62a773275a5e1cfdd31dee Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Sat, 13 Jul 2024 06:26:57 -0400 Subject: [PATCH 16/21] fix: escape wacky unicode --- benches/benchmarks.rs | 1 + src/concrete_finite.rs | 454 +++++++++++++++++++++++++++++++++++++ src/concrete_polynomial.rs | 441 +++++++++++++++++++++++++++++++++++ src/lib.rs | 8 + 4 files changed, 904 insertions(+) create mode 100644 benches/benchmarks.rs create mode 100644 src/concrete_finite.rs create mode 100644 src/concrete_polynomial.rs diff --git a/benches/benchmarks.rs b/benches/benchmarks.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/benches/benchmarks.rs @@ -0,0 +1 @@ + diff --git a/src/concrete_finite.rs b/src/concrete_finite.rs new file mode 100644 index 0000000..4d530a8 --- /dev/null +++ b/src/concrete_finite.rs @@ -0,0 +1,454 @@ +use crate::{AdditiveAbelianGroup, AdditiveGroup, AdditiveMagma, AdditiveMonoid, AdditiveSemigroup, AssociativeAddition, AssociativeMultiplication, ClosedAdd, ClosedAddAssign, ClosedDiv, ClosedDivAssign, ClosedMul, ClosedMulAssign, CommutativeAddition, CommutativeMultiplication, DistributiveAddition, EuclideanDomain, Field, FiniteField, IntegralDomain, MultiplicativeMagma, MultiplicativeMonoid, MultiplicativeSemigroup, PrincipalIdealDomain, Ring, Set, UniqueFactorizationDomain}; +use num_traits::{Inv, One, Zero}; +use std::fmt::{self, Debug, Display}; +use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, Sub, SubAssign}; + +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct FinitePrimeField { + value: u64, +} + +impl FinitePrimeField

{ + pub fn new(value: u64) -> Self { + assert!(Self::is_prime(P), "P must be prime"); + Self { value: value % P } + } + + fn is_prime(n: u64) -> bool { + if n <= 1 { + return false; + } + if n == 2 { + return true; + } + if n % 2 == 0 { + return false; + } + let sqrt_n = (n as f64).sqrt() as u64; + for i in (3..=sqrt_n).step_by(2) { + if n % i == 0 { + return false; + } + } + true + } + + pub fn value(&self) -> u64 { + self.value + } +} + +impl Debug for FinitePrimeField

{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}(mod {})", self.value, P) + } +} + +impl Display for FinitePrimeField

{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.value) + } +} + +impl Add for FinitePrimeField

{ + type Output = Self; + fn add(self, rhs: Self) -> Self::Output { + Self::new(self.value + rhs.value) + } +} + +impl Sub for FinitePrimeField

{ + type Output = Self; + fn sub(self, rhs: Self) -> Self::Output { + Self::new(self.value + P - rhs.value) + } +} + +impl Mul for FinitePrimeField

{ + type Output = Self; + fn mul(self, rhs: Self) -> Self::Output { + Self::new(self.value * rhs.value) + } +} + +impl Div for FinitePrimeField

{ + type Output = Self; + fn div(self, rhs: Self) -> Self::Output { + self * rhs.inv() + } +} + +impl Neg for FinitePrimeField

{ + type Output = Self; + fn neg(self) -> Self::Output { + Self::new(P - self.value) + } +} + +impl Rem for FinitePrimeField

{ + type Output = Self; + fn rem(self, rhs: Self) -> Self::Output { + Self::new(self.value % rhs.value) + } +} + +impl Zero for FinitePrimeField

{ + fn zero() -> Self { + Self::new(0) + } + + fn is_zero(&self) -> bool { + self.value == 0 + } +} + +impl One for FinitePrimeField

{ + fn one() -> Self { + Self::new(1) + } +} + +impl Inv for FinitePrimeField

{ + type Output = Self; + + fn inv(self) -> Self::Output { + if self.is_zero() { + panic!("attempt to invert zero"); + } + self.pow(P - 2) + } +} + +impl Set for FinitePrimeField

{ + type Element = Self; + + fn is_empty(&self) -> bool { + false + } + + fn contains(&self, element: &Self::Element) -> bool { + element.value < P + } + + fn empty() -> Self { + Self::zero() + } + + fn singleton(element: Self::Element) -> Self { + element + } + + fn union(&self, _other: &Self) -> Self { + *self + } + + fn intersection(&self, other: &Self) -> Self { + if self == other { + *self + } else { + Self::empty() + } + } + + fn difference(&self, other: &Self) -> Self { + if self == other { + Self::empty() + } else { + *self + } + } + + fn symmetric_difference(&self, other: &Self) -> Self { + if self == other { + Self::empty() + } else { + *self + } + } + + fn is_subset(&self, _other: &Self) -> bool { + true + } + + fn is_equal(&self, other: &Self) -> bool { + self == other + } + + fn cardinality(&self) -> Option { + Some(P as usize) + } + + fn is_finite(&self) -> bool { + true + } +} + +impl CommutativeAddition for FinitePrimeField

{} +impl AssociativeAddition for FinitePrimeField

{} +impl CommutativeMultiplication for FinitePrimeField

{} +impl AssociativeMultiplication for FinitePrimeField

{} +impl DistributiveAddition for FinitePrimeField

{} + +impl num_traits::Euclid for FinitePrimeField

{ + fn div_euclid(&self, v: &Self) -> Self { + *self / *v + } + + fn rem_euclid(&self, v: &Self) -> Self { + *self % *v + } +} + +impl EuclideanDomain for FinitePrimeField

{ + fn gcd(a: Self, b: Self) -> Self { + if b.is_zero() { + a + } else { + Self::gcd(b, a % b) + } + } + + fn euclidean_degree(&self) -> usize { + todo!() + } + + fn div_rem(&self, other: &Self) -> (Self, Self) { + todo!() + } +} + +impl PrincipalIdealDomain for FinitePrimeField

{ + fn ideal_generator(&self, other: &Self) -> Self { + todo!() + } + + fn gcd(&self, other: &Self) -> Self { + todo!() + } + + fn lcm(&self, other: &Self) -> Self { + todo!() + } +} + +impl UniqueFactorizationDomain for FinitePrimeField

{} + +impl IntegralDomain for FinitePrimeField

{} + +impl Ring for FinitePrimeField

{} + +impl AdditiveAbelianGroup for FinitePrimeField

{} + +impl AdditiveGroup for FinitePrimeField

{} + +impl AdditiveMonoid for FinitePrimeField

{} + +impl AdditiveSemigroup for FinitePrimeField

{} + +impl AdditiveMagma for FinitePrimeField

{} + +impl PartialEq for FinitePrimeField

{ + fn eq(&self, other: &Self) -> bool { + todo!() + } +} + +impl ClosedAdd for FinitePrimeField

{} + +impl Add for FinitePrimeField

{ + type Output = (); + + fn add(self, rhs: Self) -> Self::Output { + todo!() + } +} + +impl ClosedAddAssign for FinitePrimeField

{} + +impl AddAssign for FinitePrimeField

{ + fn add_assign(&mut self, rhs: Self) { + todo!() + } +} + +impl Sub for FinitePrimeField

{ + type Output = (); + + fn sub(self, rhs: Self) -> Self::Output { + todo!() + } +} + +impl SubAssign for FinitePrimeField

{ + fn sub_assign(&mut self, rhs: Self) { + todo!() + } +} + +impl MultiplicativeMonoid for FinitePrimeField

{} + +impl MultiplicativeSemigroup for FinitePrimeField

{} + +impl MultiplicativeMagma for FinitePrimeField

{} + +impl ClosedMul for FinitePrimeField

{} + +impl Mul for FinitePrimeField

{ + type Output = (); + + fn mul(self, rhs: Self) -> Self::Output { + todo!() + } +} + +impl ClosedMulAssign for FinitePrimeField

{} + +impl MulAssign for FinitePrimeField

{ + fn mul_assign(&mut self, rhs: Self) { + todo!() + } +} + +impl Div for FinitePrimeField

{ + type Output = (); + + fn div(self, rhs: Self) -> Self::Output { + todo!() + } +} + +impl Rem for FinitePrimeField

{ + type Output = (); + + fn rem(self, rhs: Self) -> Self::Output { + todo!() + } +} + +impl Div for FinitePrimeField

{ + type Output = Self; + + fn div(self, rhs: Self) -> Self::Output { + todo!() + } +} + +impl ClosedDiv for FinitePrimeField

{} + +impl ClosedDivAssign for FinitePrimeField

{} + +impl DivAssign for FinitePrimeField

{ + fn div_assign(&mut self, rhs: Self) { + todo!() + } +} + +impl Field for FinitePrimeField

{ + fn pow(&self, exp: i64) -> Self { + todo!() + } +} + +impl FiniteField for FinitePrimeField

{ + fn characteristic() -> u64 { + P + } + + fn order() -> u64 { + P + } + + fn is_primitive_element(element: &Self) -> bool { + if element.is_zero() { + return false; + } + let mut x = *element; + for _ in 1..P - 1 { + if x.is_one() { + return false; + } + x = x * *element; + } + x.is_one() + } + + fn pow(&self, mut exponent: u64) -> Self { + let mut base = *self; + let mut result = Self::one(); + while exponent > 0 { + if exponent % 2 == 1 { + result = result * base; + } + exponent /= 2; + base = base * base; + } + result + } + + fn mul_inverse(&self) -> Option { + if self.is_zero() { + None + } else { + Some(self.inv()) + } + } + + fn frobenius(&self) -> Self { + todo!() + } + + fn multiplicative_generator() -> Self { + todo!() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + type F5 = FinitePrimeField<5>; + + #[test] + fn test_finite_prime_field_arithmetic() { + let a = F5::new(2); + let b = F5::new(3); + + assert_eq!(a + b, F5::new(0)); + assert_eq!(a - b, F5::new(4)); + assert_eq!(a * b, F5::new(1)); + assert_eq!(a / b, F5::new(4)); + assert_eq!(-a, F5::new(3)); + } + + #[test] + fn test_finite_prime_field_pow() { + type F7 = FinitePrimeField<7>; + + let a = F7::new(3); + assert_eq!(a.pow(0), F7::one()); + assert_eq!(a.pow(1), a); + assert_eq!(a.pow(2), F7::new(2)); + assert_eq!(a.pow(6), F7::one()); + } + + #[test] + fn test_finite_prime_field_inv() { + type F11 = FinitePrimeField<11>; + + let a = F11::new(2); + assert_eq!(a.inv(), F11::new(6)); + assert_eq!(F11::zero().mul_inverse(), None); + } + + #[test] + fn test_finite_prime_field_primitive_element() { + assert!(F5::is_primitive_element(&F5::new(2))); + assert!(!F5::is_primitive_element(&F5::new(1))); + } + + #[test] + #[should_panic(expected = "P must be prime")] + fn test_non_prime_field() { + let _ = FinitePrimeField::<4>::new(1); + } +} diff --git a/src/concrete_polynomial.rs b/src/concrete_polynomial.rs new file mode 100644 index 0000000..5128aa5 --- /dev/null +++ b/src/concrete_polynomial.rs @@ -0,0 +1,441 @@ +use crate::{Associative, Commutative, Distributive, EuclideanDomain, Field, FiniteField, Set}; +use num_traits::{One, Zero}; +use std::fmt; +use std::fmt::{Debug, Display}; +use std::ops::{Add, Div, Mul, Neg, Rem, Sub}; + +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct PolynomialField { + coeffs: [F; N], +} + +impl PolynomialField { + pub fn new(coeffs: [F; N]) -> Self { + Self { coeffs } + } + + pub fn degree(&self) -> usize { + self.coeffs + .iter() + .rev() + .position(|&c| !c.is_zero()) + .map_or(0, |p| N - 1 - p) + } + + pub fn leading_coefficient(&self) -> F { + self.coeffs[self.degree()] + } + + pub fn modulus() -> Self { + let mut coeffs = [F::zero(); N]; + coeffs[0] = F::one(); + coeffs[1] = F::one(); + coeffs[N - 1] = F::one(); + Self::new(coeffs) + } + + fn inv(&self) -> Self { + if self.is_zero() { + panic!("attempt to invert zero"); + } + // Use Fermat's Little Theorem for inversion: a^(p^n - 2) mod p^n + self.pow(Self::order() - 2) + } + + fn pow(&self, mut exponent: u64) -> Self { + let mut base = *self; + let mut result = Self::one(); + while exponent > 0 { + if exponent & 1 == 1 { + result = result * base; + } + base = base * base; + exponent >>= 1; + } + result + } +} + +impl Debug for PolynomialField { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "PolynomialField(")?; + let terms: Vec = self + .coeffs + .iter() + .enumerate() + .rev() + .filter(|(_, &c)| !c.is_zero()) + .map(|(i, c)| match i { + 0 => format!("{:?}", c), + 1 => format!("{:?}x", c), + _ => format!("{:?}x^{}", c, i), + }) + .collect(); + write!(f, "{})", terms.join(" + ")) + } +} + +impl Display for PolynomialField { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +impl Add for PolynomialField { + type Output = Self; + fn add(self, rhs: Self) -> Self::Output { + let mut coeffs = [F::zero(); N]; + for i in 0..N { + coeffs[i] = self.coeffs[i] + rhs.coeffs[i]; + } + Self::new(coeffs) + } +} + +impl Sub for PolynomialField { + type Output = Self; + fn sub(self, rhs: Self) -> Self::Output { + let mut coeffs = [F::zero(); N]; + for i in 0..N { + coeffs[i] = self.coeffs[i] - rhs.coeffs[i]; + } + Self::new(coeffs) + } +} + +impl Mul for PolynomialField { + type Output = Self; + fn mul(self, rhs: Self) -> Self::Output { + let mut result = [F::zero(); N]; + for i in 0..N { + for j in 0..N { + if i + j < N { + result[i + j] = result[i + j] + self.coeffs[i] * rhs.coeffs[j]; + } + } + } + Self::new(result) % Self::modulus() + } +} + +impl Div for PolynomialField { + type Output = Self; + fn div(self, rhs: Self) -> Self::Output { + self * rhs.inv() + } +} + +impl Neg for PolynomialField { + type Output = Self; + fn neg(self) -> Self::Output { + let mut coeffs = [F::zero(); N]; + for i in 0..N { + coeffs[i] = -self.coeffs[i]; + } + Self::new(coeffs) + } +} + +impl Rem for PolynomialField { + type Output = Self; + fn rem(self, rhs: Self) -> Self::Output { + let mut r = self; + while r.degree() >= rhs.degree() { + let lead_r = r.leading_coefficient(); + let lead_rhs = rhs.leading_coefficient(); + let mut t = Self::zero(); + t.coeffs[r.degree() - rhs.degree()] = lead_r / lead_rhs; + r = r - (t * rhs); + } + r + } +} + +impl Zero for PolynomialField { + fn zero() -> Self { + Self::new([F::zero(); N]) + } + + fn is_zero(&self) -> bool { + self.coeffs.iter().all(|&c| c.is_zero()) + } +} + +impl One for PolynomialField { + fn one() -> Self { + let mut coeffs = [F::zero(); N]; + coeffs[0] = F::one(); + Self::new(coeffs) + } +} + +impl Set for PolynomialField { + type Element = Self; + + fn is_empty(&self) -> bool { + false + } + fn contains(&self, _element: &Self::Element) -> bool { + true + } + fn empty() -> Self { + Self::zero() + } + fn singleton(element: Self::Element) -> Self { + element + } + fn union(&self, _other: &Self) -> Self { + *self + } + fn intersection(&self, other: &Self) -> Self { + if self == other { + *self + } else { + Self::empty() + } + } + fn difference(&self, other: &Self) -> Self { + if self == other { + Self::empty() + } else { + *self + } + } + fn symmetric_difference(&self, other: &Self) -> Self { + if self == other { + Self::empty() + } else { + *self + } + } + fn is_subset(&self, _other: &Self) -> bool { + true + } + fn is_equal(&self, other: &Self) -> bool { + self == other + } + fn cardinality(&self) -> Option { + Some(F::order().pow(N as u32) as usize) + } + fn is_finite(&self) -> bool { + true + } +} + +impl Commutative for PolynomialField {} +impl Associative for PolynomialField {} +impl Distributive for PolynomialField {} + +impl num_traits::Euclid for PolynomialField { + fn div_euclid(&self, v: &Self) -> Self { + *self / *v + } + fn rem_euclid(&self, v: &Self) -> Self { + *self % *v + } +} + +impl EuclideanDomain for PolynomialField { + fn gcd(mut a: Self, mut b: Self) -> Self { + while !b.is_zero() { + let r = a % b; + a = b; + b = r; + } + a + } +} + +impl Field for PolynomialField {} + +impl FiniteField for PolynomialField { + fn characteristic() -> u64 { + F::characteristic() + } + + fn order() -> u64 { + F::order().pow(N as u32) + } + + fn is_primitive_element(element: &Self) -> bool { + if element.is_zero() || element.is_one() { + return false; + } + let order = Self::order(); + let mut x = *element; + for i in 1..100 { + // Limit iterations for practicality + if x.is_one() { + return i == order - 1; + } + x = x * *element; + if i % 10 == 0 && x == *element { + return false; + } + } + false // Assume not primitive if not determined after 100 iterations + } + + fn pow(&self, exponent: u64) -> Self { + self.pow(exponent) + } + + fn mul_inverse(&self) -> Option { + if self.is_zero() { + None + } else { + Some(self.inv()) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::concrete_finite::FinitePrimeField; + use std::time::{Duration, Instant}; + + type F5 = FinitePrimeField<5>; + type F5_3 = PolynomialField; + + fn run_with_timeout(f: F, timeout: Duration) -> R + where + F: FnOnce() -> R + Send + 'static, + R: Send + 'static, + { + use std::sync::mpsc::channel; + use std::thread; + + let (tx, rx) = channel(); + let handle = thread::spawn(move || { + let result = f(); + tx.send(result).unwrap(); + }); + + match rx.recv_timeout(timeout) { + Ok(result) => { + handle.join().unwrap(); + result + } + Err(_) => panic!("Test timed out after {:?}", timeout), + } + } + + #[test] + fn test_polynomial_field_arithmetic() { + run_with_timeout( + || { + let a = F5_3::new([F5::new(1), F5::new(2), F5::new(3)]); + let b = F5_3::new([F5::new(4), F5::new(0), F5::new(1)]); + + let sum = a + b; + let diff = a - b; + let prod = a * b; + let quot = a / b; + + assert_eq!(sum, F5_3::new([F5::new(0), F5::new(2), F5::new(4)])); + assert_eq!(diff, F5_3::new([F5::new(2), F5::new(2), F5::new(2)])); + assert_eq!(prod, F5_3::new([F5::new(4), F5::new(3), F5::new(2)])); + assert_eq!(quot * b, a); + }, + Duration::from_secs(1), + ); + } + + #[test] + fn test_polynomial_field_inv() { + run_with_timeout( + || { + let a = F5_3::new([F5::new(1), F5::new(2), F5::new(3)]); + let a_inv = a.inv(); + assert_eq!(a * a_inv, F5_3::one()); + }, + Duration::from_secs(1), + ); + } + + #[test] + fn test_polynomial_field_pow() { + run_with_timeout( + || { + let a = F5_3::new([F5::new(2), F5::new(1), F5::new(0)]); + assert_eq!(a.pow(0), F5_3::one()); + assert_eq!(a.pow(1), a); + assert_eq!(a.pow(5), a * a * a * a * a); + }, + Duration::from_secs(1), + ); + } + + #[test] + fn test_polynomial_field_primitive_element() { + run_with_timeout( + || { + let a = F5_3::new([F5::new(2), F5::new(1), F5::new(0)]); + let is_primitive = F5_3::is_primitive_element(&a); + println!("Is primitive element: {}", is_primitive); + }, + Duration::from_secs(1), + ); + } + + #[test] + fn test_field_properties() { + run_with_timeout( + || { + let a = F5_3::new([F5::new(1), F5::new(2), F5::new(3)]); + let b = F5_3::new([F5::new(4), F5::new(0), F5::new(1)]); + let c = F5_3::new([F5::new(2), F5::new(1), F5::new(0)]); + + assert_eq!((a + b) + c, a + (b + c)); + assert_eq!((a * b) * c, a * (b * c)); + assert_eq!(a + b, b + a); + assert_eq!(a * b, b * a); + assert_eq!(a * (b + c), (a * b) + (a * c)); + assert_eq!(a + F5_3::zero(), a); + assert_eq!(a * F5_3::one(), a); + assert_eq!(a + (-a), F5_3::zero()); + assert_eq!(a * a.inv(), F5_3::one()); + }, + Duration::from_secs(1), + ); + } + + #[test] + fn test_field_order() { + let order = F5_3::order(); + assert_eq!(order, 125); // 5^3 = 125 + } + + #[test] + fn test_polynomial_degree() { + run_with_timeout( + || { + let a = F5_3::new([F5::new(1), F5::new(2), F5::new(3)]); + assert_eq!(a.degree(), 2); + let b = F5_3::new([F5::new(1), F5::new(2), F5::new(0)]); + assert_eq!(b.degree(), 1); + let c = F5_3::new([F5::new(1), F5::new(0), F5::new(0)]); + assert_eq!(c.degree(), 0); + let d = F5_3::zero(); + assert_eq!(d.degree(), 0); + }, + Duration::from_secs(1), + ); + } + + // ... [Include the rest of the tests from the previous response] ... + + #[test] + fn test_polynomial_large_exponent() { + run_with_timeout( + || { + let a = F5_3::new([F5::new(2), F5::new(1), F5::new(0)]); + let large_exp = 1_000_000_007; // A large prime number + let result = a.pow(large_exp); + assert!(!result.is_zero()); + }, + Duration::from_secs(5), + ); // Allow more time for this test + } +} diff --git a/src/lib.rs b/src/lib.rs index c0a4ac4..89964a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -121,8 +121,10 @@ //! - (Min/Max Ops) βˆ€ a, b ∈ S, a ∨ b = min{a,b}, a ∧ b = max{a,b} //! - (Defect Op) βˆ€ a, b ∈ S, a *₃ b = a + b - 3 //! - (Continuity) βˆ€ V βŠ† 𝑆 open, f⁻¹(V) is open (for f: 𝑆 β†’ 𝑆, 𝑆 topological) +//! ```text //! - (Solvability) βˆƒ series {Gα΅’} | G = Gβ‚€ β–· G₁ β–· ... β–· Gβ‚™ = {e}, [Gα΅’, Gα΅’] ≀ Gα΅’β‚Šβ‚ //! - (Alg. Closure) βˆ€ p(x) ∈ 𝑆[x] non-constant, βˆƒ a ∈ 𝑆 | p(a) = 0 +//! ``` //! //! The traits and blanket implementations provided above serve several important purposes: //! @@ -952,7 +954,9 @@ pub trait FieldExtension: Field + VectorSpace { /// Returns the degree of the field extension. /// /// # Formal Notation + /// ```text /// [L:K] = dim_K(L) + /// ``` fn degree() -> Option; /// Embeds an element from the base field into the extension field. @@ -1033,13 +1037,17 @@ pub trait FieldExtensionTower: FieldExtension { /// Returns an iterator over the degrees of each extension in the tower. /// /// # Formal Notation + /// ```text /// For a tower K = Fβ‚€ βŠ‚ F₁ βŠ‚ ... βŠ‚ Fβ‚™ = L, yields [F₁:Fβ‚€], [Fβ‚‚:F₁], ..., [Fβ‚™:Fₙ₋₁] + /// ``` fn extension_degrees() -> Box>>; /// Computes the absolute degree of the entire tower extension. /// /// # Formal Notation + /// ```text /// For a tower K = Fβ‚€ βŠ‚ F₁ βŠ‚ ... βŠ‚ Fβ‚™ = L, returns [L:K] = [Fβ‚™:Fₙ₋₁] Β· [Fₙ₋₁:Fβ‚™β‚‹β‚‚] Β· ... Β· [F₁:Fβ‚€] + /// ``` fn absolute_degree() -> Option; /// Returns an iterator over the minimal polynomials of each extension in the tower. From 4ef662b42fe47cbc41051f4075c152caa11e29fe Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Sat, 13 Jul 2024 06:27:36 -0400 Subject: [PATCH 17/21] fix: remove concrete impls for now --- src/concrete_finite.rs | 454 ------------------------------------- src/concrete_polynomial.rs | 441 ----------------------------------- 2 files changed, 895 deletions(-) delete mode 100644 src/concrete_finite.rs delete mode 100644 src/concrete_polynomial.rs diff --git a/src/concrete_finite.rs b/src/concrete_finite.rs deleted file mode 100644 index 4d530a8..0000000 --- a/src/concrete_finite.rs +++ /dev/null @@ -1,454 +0,0 @@ -use crate::{AdditiveAbelianGroup, AdditiveGroup, AdditiveMagma, AdditiveMonoid, AdditiveSemigroup, AssociativeAddition, AssociativeMultiplication, ClosedAdd, ClosedAddAssign, ClosedDiv, ClosedDivAssign, ClosedMul, ClosedMulAssign, CommutativeAddition, CommutativeMultiplication, DistributiveAddition, EuclideanDomain, Field, FiniteField, IntegralDomain, MultiplicativeMagma, MultiplicativeMonoid, MultiplicativeSemigroup, PrincipalIdealDomain, Ring, Set, UniqueFactorizationDomain}; -use num_traits::{Inv, One, Zero}; -use std::fmt::{self, Debug, Display}; -use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, Sub, SubAssign}; - -#[derive(Clone, Copy, PartialEq, Eq)] -pub struct FinitePrimeField { - value: u64, -} - -impl FinitePrimeField

{ - pub fn new(value: u64) -> Self { - assert!(Self::is_prime(P), "P must be prime"); - Self { value: value % P } - } - - fn is_prime(n: u64) -> bool { - if n <= 1 { - return false; - } - if n == 2 { - return true; - } - if n % 2 == 0 { - return false; - } - let sqrt_n = (n as f64).sqrt() as u64; - for i in (3..=sqrt_n).step_by(2) { - if n % i == 0 { - return false; - } - } - true - } - - pub fn value(&self) -> u64 { - self.value - } -} - -impl Debug for FinitePrimeField

{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}(mod {})", self.value, P) - } -} - -impl Display for FinitePrimeField

{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.value) - } -} - -impl Add for FinitePrimeField

{ - type Output = Self; - fn add(self, rhs: Self) -> Self::Output { - Self::new(self.value + rhs.value) - } -} - -impl Sub for FinitePrimeField

{ - type Output = Self; - fn sub(self, rhs: Self) -> Self::Output { - Self::new(self.value + P - rhs.value) - } -} - -impl Mul for FinitePrimeField

{ - type Output = Self; - fn mul(self, rhs: Self) -> Self::Output { - Self::new(self.value * rhs.value) - } -} - -impl Div for FinitePrimeField

{ - type Output = Self; - fn div(self, rhs: Self) -> Self::Output { - self * rhs.inv() - } -} - -impl Neg for FinitePrimeField

{ - type Output = Self; - fn neg(self) -> Self::Output { - Self::new(P - self.value) - } -} - -impl Rem for FinitePrimeField

{ - type Output = Self; - fn rem(self, rhs: Self) -> Self::Output { - Self::new(self.value % rhs.value) - } -} - -impl Zero for FinitePrimeField

{ - fn zero() -> Self { - Self::new(0) - } - - fn is_zero(&self) -> bool { - self.value == 0 - } -} - -impl One for FinitePrimeField

{ - fn one() -> Self { - Self::new(1) - } -} - -impl Inv for FinitePrimeField

{ - type Output = Self; - - fn inv(self) -> Self::Output { - if self.is_zero() { - panic!("attempt to invert zero"); - } - self.pow(P - 2) - } -} - -impl Set for FinitePrimeField

{ - type Element = Self; - - fn is_empty(&self) -> bool { - false - } - - fn contains(&self, element: &Self::Element) -> bool { - element.value < P - } - - fn empty() -> Self { - Self::zero() - } - - fn singleton(element: Self::Element) -> Self { - element - } - - fn union(&self, _other: &Self) -> Self { - *self - } - - fn intersection(&self, other: &Self) -> Self { - if self == other { - *self - } else { - Self::empty() - } - } - - fn difference(&self, other: &Self) -> Self { - if self == other { - Self::empty() - } else { - *self - } - } - - fn symmetric_difference(&self, other: &Self) -> Self { - if self == other { - Self::empty() - } else { - *self - } - } - - fn is_subset(&self, _other: &Self) -> bool { - true - } - - fn is_equal(&self, other: &Self) -> bool { - self == other - } - - fn cardinality(&self) -> Option { - Some(P as usize) - } - - fn is_finite(&self) -> bool { - true - } -} - -impl CommutativeAddition for FinitePrimeField

{} -impl AssociativeAddition for FinitePrimeField

{} -impl CommutativeMultiplication for FinitePrimeField

{} -impl AssociativeMultiplication for FinitePrimeField

{} -impl DistributiveAddition for FinitePrimeField

{} - -impl num_traits::Euclid for FinitePrimeField

{ - fn div_euclid(&self, v: &Self) -> Self { - *self / *v - } - - fn rem_euclid(&self, v: &Self) -> Self { - *self % *v - } -} - -impl EuclideanDomain for FinitePrimeField

{ - fn gcd(a: Self, b: Self) -> Self { - if b.is_zero() { - a - } else { - Self::gcd(b, a % b) - } - } - - fn euclidean_degree(&self) -> usize { - todo!() - } - - fn div_rem(&self, other: &Self) -> (Self, Self) { - todo!() - } -} - -impl PrincipalIdealDomain for FinitePrimeField

{ - fn ideal_generator(&self, other: &Self) -> Self { - todo!() - } - - fn gcd(&self, other: &Self) -> Self { - todo!() - } - - fn lcm(&self, other: &Self) -> Self { - todo!() - } -} - -impl UniqueFactorizationDomain for FinitePrimeField

{} - -impl IntegralDomain for FinitePrimeField

{} - -impl Ring for FinitePrimeField

{} - -impl AdditiveAbelianGroup for FinitePrimeField

{} - -impl AdditiveGroup for FinitePrimeField

{} - -impl AdditiveMonoid for FinitePrimeField

{} - -impl AdditiveSemigroup for FinitePrimeField

{} - -impl AdditiveMagma for FinitePrimeField

{} - -impl PartialEq for FinitePrimeField

{ - fn eq(&self, other: &Self) -> bool { - todo!() - } -} - -impl ClosedAdd for FinitePrimeField

{} - -impl Add for FinitePrimeField

{ - type Output = (); - - fn add(self, rhs: Self) -> Self::Output { - todo!() - } -} - -impl ClosedAddAssign for FinitePrimeField

{} - -impl AddAssign for FinitePrimeField

{ - fn add_assign(&mut self, rhs: Self) { - todo!() - } -} - -impl Sub for FinitePrimeField

{ - type Output = (); - - fn sub(self, rhs: Self) -> Self::Output { - todo!() - } -} - -impl SubAssign for FinitePrimeField

{ - fn sub_assign(&mut self, rhs: Self) { - todo!() - } -} - -impl MultiplicativeMonoid for FinitePrimeField

{} - -impl MultiplicativeSemigroup for FinitePrimeField

{} - -impl MultiplicativeMagma for FinitePrimeField

{} - -impl ClosedMul for FinitePrimeField

{} - -impl Mul for FinitePrimeField

{ - type Output = (); - - fn mul(self, rhs: Self) -> Self::Output { - todo!() - } -} - -impl ClosedMulAssign for FinitePrimeField

{} - -impl MulAssign for FinitePrimeField

{ - fn mul_assign(&mut self, rhs: Self) { - todo!() - } -} - -impl Div for FinitePrimeField

{ - type Output = (); - - fn div(self, rhs: Self) -> Self::Output { - todo!() - } -} - -impl Rem for FinitePrimeField

{ - type Output = (); - - fn rem(self, rhs: Self) -> Self::Output { - todo!() - } -} - -impl Div for FinitePrimeField

{ - type Output = Self; - - fn div(self, rhs: Self) -> Self::Output { - todo!() - } -} - -impl ClosedDiv for FinitePrimeField

{} - -impl ClosedDivAssign for FinitePrimeField

{} - -impl DivAssign for FinitePrimeField

{ - fn div_assign(&mut self, rhs: Self) { - todo!() - } -} - -impl Field for FinitePrimeField

{ - fn pow(&self, exp: i64) -> Self { - todo!() - } -} - -impl FiniteField for FinitePrimeField

{ - fn characteristic() -> u64 { - P - } - - fn order() -> u64 { - P - } - - fn is_primitive_element(element: &Self) -> bool { - if element.is_zero() { - return false; - } - let mut x = *element; - for _ in 1..P - 1 { - if x.is_one() { - return false; - } - x = x * *element; - } - x.is_one() - } - - fn pow(&self, mut exponent: u64) -> Self { - let mut base = *self; - let mut result = Self::one(); - while exponent > 0 { - if exponent % 2 == 1 { - result = result * base; - } - exponent /= 2; - base = base * base; - } - result - } - - fn mul_inverse(&self) -> Option { - if self.is_zero() { - None - } else { - Some(self.inv()) - } - } - - fn frobenius(&self) -> Self { - todo!() - } - - fn multiplicative_generator() -> Self { - todo!() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - type F5 = FinitePrimeField<5>; - - #[test] - fn test_finite_prime_field_arithmetic() { - let a = F5::new(2); - let b = F5::new(3); - - assert_eq!(a + b, F5::new(0)); - assert_eq!(a - b, F5::new(4)); - assert_eq!(a * b, F5::new(1)); - assert_eq!(a / b, F5::new(4)); - assert_eq!(-a, F5::new(3)); - } - - #[test] - fn test_finite_prime_field_pow() { - type F7 = FinitePrimeField<7>; - - let a = F7::new(3); - assert_eq!(a.pow(0), F7::one()); - assert_eq!(a.pow(1), a); - assert_eq!(a.pow(2), F7::new(2)); - assert_eq!(a.pow(6), F7::one()); - } - - #[test] - fn test_finite_prime_field_inv() { - type F11 = FinitePrimeField<11>; - - let a = F11::new(2); - assert_eq!(a.inv(), F11::new(6)); - assert_eq!(F11::zero().mul_inverse(), None); - } - - #[test] - fn test_finite_prime_field_primitive_element() { - assert!(F5::is_primitive_element(&F5::new(2))); - assert!(!F5::is_primitive_element(&F5::new(1))); - } - - #[test] - #[should_panic(expected = "P must be prime")] - fn test_non_prime_field() { - let _ = FinitePrimeField::<4>::new(1); - } -} diff --git a/src/concrete_polynomial.rs b/src/concrete_polynomial.rs deleted file mode 100644 index 5128aa5..0000000 --- a/src/concrete_polynomial.rs +++ /dev/null @@ -1,441 +0,0 @@ -use crate::{Associative, Commutative, Distributive, EuclideanDomain, Field, FiniteField, Set}; -use num_traits::{One, Zero}; -use std::fmt; -use std::fmt::{Debug, Display}; -use std::ops::{Add, Div, Mul, Neg, Rem, Sub}; - -#[derive(Clone, Copy, PartialEq, Eq)] -pub struct PolynomialField { - coeffs: [F; N], -} - -impl PolynomialField { - pub fn new(coeffs: [F; N]) -> Self { - Self { coeffs } - } - - pub fn degree(&self) -> usize { - self.coeffs - .iter() - .rev() - .position(|&c| !c.is_zero()) - .map_or(0, |p| N - 1 - p) - } - - pub fn leading_coefficient(&self) -> F { - self.coeffs[self.degree()] - } - - pub fn modulus() -> Self { - let mut coeffs = [F::zero(); N]; - coeffs[0] = F::one(); - coeffs[1] = F::one(); - coeffs[N - 1] = F::one(); - Self::new(coeffs) - } - - fn inv(&self) -> Self { - if self.is_zero() { - panic!("attempt to invert zero"); - } - // Use Fermat's Little Theorem for inversion: a^(p^n - 2) mod p^n - self.pow(Self::order() - 2) - } - - fn pow(&self, mut exponent: u64) -> Self { - let mut base = *self; - let mut result = Self::one(); - while exponent > 0 { - if exponent & 1 == 1 { - result = result * base; - } - base = base * base; - exponent >>= 1; - } - result - } -} - -impl Debug for PolynomialField { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "PolynomialField(")?; - let terms: Vec = self - .coeffs - .iter() - .enumerate() - .rev() - .filter(|(_, &c)| !c.is_zero()) - .map(|(i, c)| match i { - 0 => format!("{:?}", c), - 1 => format!("{:?}x", c), - _ => format!("{:?}x^{}", c, i), - }) - .collect(); - write!(f, "{})", terms.join(" + ")) - } -} - -impl Display for PolynomialField { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - -impl Add for PolynomialField { - type Output = Self; - fn add(self, rhs: Self) -> Self::Output { - let mut coeffs = [F::zero(); N]; - for i in 0..N { - coeffs[i] = self.coeffs[i] + rhs.coeffs[i]; - } - Self::new(coeffs) - } -} - -impl Sub for PolynomialField { - type Output = Self; - fn sub(self, rhs: Self) -> Self::Output { - let mut coeffs = [F::zero(); N]; - for i in 0..N { - coeffs[i] = self.coeffs[i] - rhs.coeffs[i]; - } - Self::new(coeffs) - } -} - -impl Mul for PolynomialField { - type Output = Self; - fn mul(self, rhs: Self) -> Self::Output { - let mut result = [F::zero(); N]; - for i in 0..N { - for j in 0..N { - if i + j < N { - result[i + j] = result[i + j] + self.coeffs[i] * rhs.coeffs[j]; - } - } - } - Self::new(result) % Self::modulus() - } -} - -impl Div for PolynomialField { - type Output = Self; - fn div(self, rhs: Self) -> Self::Output { - self * rhs.inv() - } -} - -impl Neg for PolynomialField { - type Output = Self; - fn neg(self) -> Self::Output { - let mut coeffs = [F::zero(); N]; - for i in 0..N { - coeffs[i] = -self.coeffs[i]; - } - Self::new(coeffs) - } -} - -impl Rem for PolynomialField { - type Output = Self; - fn rem(self, rhs: Self) -> Self::Output { - let mut r = self; - while r.degree() >= rhs.degree() { - let lead_r = r.leading_coefficient(); - let lead_rhs = rhs.leading_coefficient(); - let mut t = Self::zero(); - t.coeffs[r.degree() - rhs.degree()] = lead_r / lead_rhs; - r = r - (t * rhs); - } - r - } -} - -impl Zero for PolynomialField { - fn zero() -> Self { - Self::new([F::zero(); N]) - } - - fn is_zero(&self) -> bool { - self.coeffs.iter().all(|&c| c.is_zero()) - } -} - -impl One for PolynomialField { - fn one() -> Self { - let mut coeffs = [F::zero(); N]; - coeffs[0] = F::one(); - Self::new(coeffs) - } -} - -impl Set for PolynomialField { - type Element = Self; - - fn is_empty(&self) -> bool { - false - } - fn contains(&self, _element: &Self::Element) -> bool { - true - } - fn empty() -> Self { - Self::zero() - } - fn singleton(element: Self::Element) -> Self { - element - } - fn union(&self, _other: &Self) -> Self { - *self - } - fn intersection(&self, other: &Self) -> Self { - if self == other { - *self - } else { - Self::empty() - } - } - fn difference(&self, other: &Self) -> Self { - if self == other { - Self::empty() - } else { - *self - } - } - fn symmetric_difference(&self, other: &Self) -> Self { - if self == other { - Self::empty() - } else { - *self - } - } - fn is_subset(&self, _other: &Self) -> bool { - true - } - fn is_equal(&self, other: &Self) -> bool { - self == other - } - fn cardinality(&self) -> Option { - Some(F::order().pow(N as u32) as usize) - } - fn is_finite(&self) -> bool { - true - } -} - -impl Commutative for PolynomialField {} -impl Associative for PolynomialField {} -impl Distributive for PolynomialField {} - -impl num_traits::Euclid for PolynomialField { - fn div_euclid(&self, v: &Self) -> Self { - *self / *v - } - fn rem_euclid(&self, v: &Self) -> Self { - *self % *v - } -} - -impl EuclideanDomain for PolynomialField { - fn gcd(mut a: Self, mut b: Self) -> Self { - while !b.is_zero() { - let r = a % b; - a = b; - b = r; - } - a - } -} - -impl Field for PolynomialField {} - -impl FiniteField for PolynomialField { - fn characteristic() -> u64 { - F::characteristic() - } - - fn order() -> u64 { - F::order().pow(N as u32) - } - - fn is_primitive_element(element: &Self) -> bool { - if element.is_zero() || element.is_one() { - return false; - } - let order = Self::order(); - let mut x = *element; - for i in 1..100 { - // Limit iterations for practicality - if x.is_one() { - return i == order - 1; - } - x = x * *element; - if i % 10 == 0 && x == *element { - return false; - } - } - false // Assume not primitive if not determined after 100 iterations - } - - fn pow(&self, exponent: u64) -> Self { - self.pow(exponent) - } - - fn mul_inverse(&self) -> Option { - if self.is_zero() { - None - } else { - Some(self.inv()) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::concrete_finite::FinitePrimeField; - use std::time::{Duration, Instant}; - - type F5 = FinitePrimeField<5>; - type F5_3 = PolynomialField; - - fn run_with_timeout(f: F, timeout: Duration) -> R - where - F: FnOnce() -> R + Send + 'static, - R: Send + 'static, - { - use std::sync::mpsc::channel; - use std::thread; - - let (tx, rx) = channel(); - let handle = thread::spawn(move || { - let result = f(); - tx.send(result).unwrap(); - }); - - match rx.recv_timeout(timeout) { - Ok(result) => { - handle.join().unwrap(); - result - } - Err(_) => panic!("Test timed out after {:?}", timeout), - } - } - - #[test] - fn test_polynomial_field_arithmetic() { - run_with_timeout( - || { - let a = F5_3::new([F5::new(1), F5::new(2), F5::new(3)]); - let b = F5_3::new([F5::new(4), F5::new(0), F5::new(1)]); - - let sum = a + b; - let diff = a - b; - let prod = a * b; - let quot = a / b; - - assert_eq!(sum, F5_3::new([F5::new(0), F5::new(2), F5::new(4)])); - assert_eq!(diff, F5_3::new([F5::new(2), F5::new(2), F5::new(2)])); - assert_eq!(prod, F5_3::new([F5::new(4), F5::new(3), F5::new(2)])); - assert_eq!(quot * b, a); - }, - Duration::from_secs(1), - ); - } - - #[test] - fn test_polynomial_field_inv() { - run_with_timeout( - || { - let a = F5_3::new([F5::new(1), F5::new(2), F5::new(3)]); - let a_inv = a.inv(); - assert_eq!(a * a_inv, F5_3::one()); - }, - Duration::from_secs(1), - ); - } - - #[test] - fn test_polynomial_field_pow() { - run_with_timeout( - || { - let a = F5_3::new([F5::new(2), F5::new(1), F5::new(0)]); - assert_eq!(a.pow(0), F5_3::one()); - assert_eq!(a.pow(1), a); - assert_eq!(a.pow(5), a * a * a * a * a); - }, - Duration::from_secs(1), - ); - } - - #[test] - fn test_polynomial_field_primitive_element() { - run_with_timeout( - || { - let a = F5_3::new([F5::new(2), F5::new(1), F5::new(0)]); - let is_primitive = F5_3::is_primitive_element(&a); - println!("Is primitive element: {}", is_primitive); - }, - Duration::from_secs(1), - ); - } - - #[test] - fn test_field_properties() { - run_with_timeout( - || { - let a = F5_3::new([F5::new(1), F5::new(2), F5::new(3)]); - let b = F5_3::new([F5::new(4), F5::new(0), F5::new(1)]); - let c = F5_3::new([F5::new(2), F5::new(1), F5::new(0)]); - - assert_eq!((a + b) + c, a + (b + c)); - assert_eq!((a * b) * c, a * (b * c)); - assert_eq!(a + b, b + a); - assert_eq!(a * b, b * a); - assert_eq!(a * (b + c), (a * b) + (a * c)); - assert_eq!(a + F5_3::zero(), a); - assert_eq!(a * F5_3::one(), a); - assert_eq!(a + (-a), F5_3::zero()); - assert_eq!(a * a.inv(), F5_3::one()); - }, - Duration::from_secs(1), - ); - } - - #[test] - fn test_field_order() { - let order = F5_3::order(); - assert_eq!(order, 125); // 5^3 = 125 - } - - #[test] - fn test_polynomial_degree() { - run_with_timeout( - || { - let a = F5_3::new([F5::new(1), F5::new(2), F5::new(3)]); - assert_eq!(a.degree(), 2); - let b = F5_3::new([F5::new(1), F5::new(2), F5::new(0)]); - assert_eq!(b.degree(), 1); - let c = F5_3::new([F5::new(1), F5::new(0), F5::new(0)]); - assert_eq!(c.degree(), 0); - let d = F5_3::zero(); - assert_eq!(d.degree(), 0); - }, - Duration::from_secs(1), - ); - } - - // ... [Include the rest of the tests from the previous response] ... - - #[test] - fn test_polynomial_large_exponent() { - run_with_timeout( - || { - let a = F5_3::new([F5::new(2), F5::new(1), F5::new(0)]); - let large_exp = 1_000_000_007; // A large prime number - let result = a.pow(large_exp); - assert!(!result.is_zero()); - }, - Duration::from_secs(5), - ); // Allow more time for this test - } -} From 1badb1dd41a6ee31108ad4d3bb79d9e286a074b0 Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Sat, 13 Jul 2024 06:29:25 -0400 Subject: [PATCH 18/21] fix: satisfy clippy --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 89964a5..7ce6e9e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -886,7 +886,7 @@ pub trait Polynomial: Clone + PartialEq + ClosedAdd + ClosedMul + Euclid { /// 2. (a + b)x = ax + bx /// 3. (ab)x = a(bx) /// 4. 1x = x -/// where a, b ∈ R and x, y ∈ M +/// where a, b ∈ R and x, y ∈ M pub trait Module: MultiplicativeAbelianGroup { type Scalar: Ring; @@ -910,7 +910,7 @@ pub trait Module: MultiplicativeAbelianGroup { /// 2. (a + b)v = av + bv /// 3. (ab)v = a(bv) /// 4. 1v = v -/// where a, b ∈ F and u, v ∈ V +/// where a, b ∈ F and u, v ∈ V pub trait VectorSpace: AdditiveAbelianGroup { type Scalar: Field; From 0050054b60ba125024d7997e329a704312fdb481 Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Sat, 13 Jul 2024 06:33:43 -0400 Subject: [PATCH 19/21] fix: really really satisfy clippy --- src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7ce6e9e..7989908 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -881,12 +881,11 @@ pub trait Polynomial: Clone + PartialEq + ClosedAdd + ClosedMul + Euclid { /// /// # Properties /// - (M, +) is an abelian group -/// - Scalar multiplication: R Γ— M β†’ M satisfying: +/// - Scalar multiplication: R Γ— M β†’ M where a, b ∈ R and x, y ∈ M satisfying: /// 1. a(x + y) = ax + ay /// 2. (a + b)x = ax + bx /// 3. (ab)x = a(bx) /// 4. 1x = x -/// where a, b ∈ R and x, y ∈ M pub trait Module: MultiplicativeAbelianGroup { type Scalar: Ring; @@ -905,12 +904,11 @@ pub trait Module: MultiplicativeAbelianGroup { /// /// # Properties /// - (V, +) is an abelian group -/// - Scalar multiplication: F Γ— V β†’ V satisfying: +/// - Scalar multiplication: F Γ— V β†’ V where a, b ∈ F and u, v ∈ V satisfying: /// 1. a(u + v) = au + av /// 2. (a + b)v = av + bv /// 3. (ab)v = a(bv) /// 4. 1v = v -/// where a, b ∈ F and u, v ∈ V pub trait VectorSpace: AdditiveAbelianGroup { type Scalar: Field; From 790eb6dd092f593b802817b12a6c7f17ec300721 Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Sat, 13 Jul 2024 06:53:27 -0400 Subject: [PATCH 20/21] docs: update notes --- src/lib.rs | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7989908..59274ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -139,29 +139,18 @@ //! and to enable more generic implementations of algorithms. There is work to be done //! to complete the compile time checks. //! -//! 4. Property Checking: Some marker traits include methods to check if the property holds -//! for specific values. While not providing compile-time guarantees, these can be -//! useful for testing and runtime verification. -//! -//! 5. Automatic Implementation: The blanket implementations ensure that any type satisfying -//! the basic requirements automatically implements the corresponding closed trait. -//! This reduces boilerplate and makes the traits easier to use. -//! -//! 6. Extensibility: New types that implement the standard traits (like `Add`, `Sub`, etc.) +//! 4. Extensibility: New types that implement the standard traits (like `Add`, `Sub`, etc.) //! will automatically get the closed trait implementations, making the system more //! extensible and future-proof. //! -//! 7. Type Safety: These traits help in catching type-related errors at compile-time, +//! 5. Type Safety: These traits help in catching type-related errors at compile-time, //! ensuring that operations maintain closure within the same type. //! -//! 8. Generic Programming: These traits enable more expressive generic programming, +//! 6. Generic Programming: These traits enable more expressive generic programming, //! allowing functions and structs to be generic over types that are closed under //! certain operations or satisfy certain algebraic properties. //! -//! Note that while these blanket implementations cover a wide range of cases, there might -//! be situations where more specific implementations are needed. In such cases, you can -//! still manually implement these traits for your types, and the manual implementations -//! will take precedence over these blanket implementations. +//! TODO(Replace blanket implementations with derive) use num_traits::{Euclid, Inv, One, Zero}; use std::ops::{ From f27ee21ef4d53a4439a0888090577901a14957db Mon Sep 17 00:00:00 2001 From: Alcibiades Athens Date: Sat, 13 Jul 2024 14:50:09 -0400 Subject: [PATCH 21/21] docs: readme --- README.md | 382 ++++++++++++++++++++++++++++++++++++++++++++++++++++- src/lib.rs | 154 --------------------- 2 files changed, 375 insertions(+), 161 deletions(-) diff --git a/README.md b/README.md index 3e455fb..74aee60 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,383 @@ # Noether -[![License](https://img.shields.io/crates/l/noether)](https://choosealicense.com/licenses/mit/) +[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![Crates.io](https://img.shields.io/crates/v/noether)](https://crates.io/crates/noether) -[![Docs](https://img.shields.io/crates/v/noether?color=blue&label=docs)](https://docs.rs/noether/) +[![Docs](https://img.shields.io/docsrs/noether)](https://docs.rs/noether) ![CI](https://github.com/warlock-labs/noether/actions/workflows/CI.yml/badge.svg) -Noether provides traits scalar abstract algebra. +Noether provides traits and blanket implementations for algebraic structures, from basic ones like magmas to more +complex ones like fields. It leans heavily on the basic traits available in std::ops and num_traits. +## Table of Contents -Inspirations: +- [Background](#background) + - [Inspirations](#inspirations) +- [Features](#features) +- [Installation](#installation) +- [Usage](#usage) +- [Core Concepts](#core-concepts) +- [Hierarchy of Algebraic Structures](#hierarchy-of-algebraic-structures) +- [Operator Traits for Algebraic Structures](#operator-traits-for-algebraic-structures) +- [API Overview](#api-overview) +- [Advanced Usage](#advanced-usage) +- [Performance](#performance) +- [Roadmap](#roadmap) +- [Contributing](#contributing) +- [License](#license) -https://github.com/dimforge/alga/tree/dev/alga -https://crates.io/crates/simba -https://crates.io/crates/algebra +## Background + +Named after Emmy Noether, a pioneering mathematician in abstract algebra, this library aims to bridge the gap between +abstract mathematics and practical programming in Rust. It enables developers to work with mathematical concepts in a +type-safe, efficient, and expressive manner. + +The goal is to provide a common interface for working with algebraic structures in Rust. Interestingly, these traits can +be used to categorize implementations of various structs based on the properties they satisfy, and be applied in most +cases for anything from scalar values to n-dimensional arrays. + +### Inspirations + +Noether draws inspiration from several existing libraries and projects in the field of computational algebra: + +1. [simba](https://crates.io/crates/simba): A Rust crate for SIMD-accelerated algebra. + +2. [alga](https://github.com/dimforge/alga): A Rust library for abstract algebra, providing solid mathematical + abstractions for algebra-focused applications. alga defines and organizes basic building blocks of general algebraic + structures through trait inheritance. + +3. [algebra](https://github.com/brendanzab/algebra): A Rust library for abstract algebra that organizes a wide range of + structures into a logically consistent framework. It aims to create composable libraries and APIs based on algebraic + classifications. + +These libraries demonstrate the power and utility of representing algebraic structures in programming languages. Noether +builds upon their ideas, aiming to provide a comprehensive and ergonomic framework for working with algebraic structures +in Rust. + +Other notable inspirations from different programming languages include: + +- Haskell's [Numeric Prelude](http://www.haskell.org/haskellwiki/Numeric_Prelude) and Edward A. + Kmett's [algebra package](http://hackage.haskell.org/package/algebra-3.1) +- Agda's [algebra module](http://www.cse.chalmers.se/~nad/listings/lib-0.7/Algebra.html) +- Idris' [algebra module](https://github.com/idris-lang/Idris-dev/blob/master/libs/prelude/Prelude/Algebra.idr) +- Scala's [spire](https://github.com/non/spire) + +Noether also draws insights from academic papers in the field: + +- [The Scratchpad II Type System: Domains and Subdomains](http://www.csd.uwo.ca/~watt/pub/reprints/1990-miola-spadtypes.pdf) +- [Fundamental Algebraic Concepts in Concept-Enabled C++](ftp://cgi.cs.indiana.edu/pub/techreports/TR638.pdf) + +Noether aims to bring the best ideas from these libraries and research to the Rust ecosystem, while taking advantage of +Rust's unique features like zero-cost abstractions and powerful type system. + +## Features + +- Traits for a wide range of algebraic structures (e.g., Magma, Semigroup, Monoid, Group, Ring, Field) +- Marker traits for important algebraic properties (e.g., Associativity, Commutativity) +- Blanket implementations to reduce boilerplate code +- Support for both built-in and custom types +- Zero-cost abstractions leveraging Rust's type system + +## Installation + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +noether = "0.1.0" +``` + +## Usage + +Here is a rough example of Zβ‚… (integers modulo 5) using Noether: + +```rust +use noether::{Field}; +use std::ops::{Add, Sub, Mul, Div, Neg}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +struct Z5(u8); + +impl Z5 { + fn new(n: u8) -> Self { + Z5(n % 5) + } +} + +impl Add for Z5 { + type Output = Self; + fn add(self, rhs: Self) -> Self { + Z5((self.0 + rhs.0) % 5) + } +} + +impl Sub for Z5 { + type Output = Self; + fn sub(self, rhs: Self) -> Self { + self + (-rhs) + } +} + +impl Mul for Z5 { + type Output = Self; + fn mul(self, rhs: Self) -> Self { + Z5((self.0 * rhs.0) % 5) + } +} + +impl Div for Z5 { + type Output = Self; + fn div(self, rhs: Self) -> Self { + if rhs.0 == 0 { + panic!("Division by zero in Z5"); + } + self * rhs.multiplicative_inverse().unwrap() + } +} + +impl Neg for Z5 { + type Output = Self; + fn neg(self) -> Self { + Z5((5 - self.0) % 5) + } +} + +impl Field for Z5 { + fn multiplicative_inverse(&self) -> Option { + match self.0 { + 0 => None, + 1 | 4 => Some(*self), + 2 => Some(Z5(3)), + 3 => Some(Z5(2)), + _ => unreachable!(), + } + } +} +``` + +This example shows how to construct a well factored finite field using Noether, +leveraging Rust's native operators and traits. + +## Core Concepts + +1. **Algebraic Structures**: Traits representing mathematical structures with specific properties and operations. +2. **Marker Traits**: Traits like `Associative` and `Commutative` for compile-time property checks. +3. **Blanket Implementations**: Automatic implementations of higher-level traits based on more fundamental ones. +4. **Zero-Cost Abstractions**: Leveraging Rust's type system for efficiency without runtime overhead. +5. **Extensibility**: The library is designed to be easily extended with new types and structures. +6. **Type Safety**: Ensuring operations maintain closure within the same type and catching errors at compile-time. + +## Hierarchy of Algebraic Structures + +```text + β”Œβ”€β”€β”€β”€β”€β” + β”‚ Set β”‚ + β””β”€β”€β”¬β”€β”€β”˜ + β”‚ + β”Œβ”€β”€β–Όβ”€β”€β” + β”‚Magmaβ”‚ + β””β”€β”€β”¬β”€β”€β”˜ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ β”‚ β”‚ + β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” + β”‚Quasigroup β”‚ β”‚ Semigroup β”‚ β”‚Semilatticeβ”‚ + β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ β”‚ + β”Œβ”€β”€β”€β–Όβ”€β”€β”€β” β”Œβ”€β”€β”€β–Όβ”€β”€β”€β” + β”‚ Loop β”‚ β”‚Monoid β”‚ + β””β”€β”€β”€β”¬β”€β”€β”€β”˜ β””β”€β”€β”€β”¬β”€β”€β”€β”˜ + β”‚ β”‚ + └────────┐ β”Œβ”€β”€β”€β”€β”€β”˜ + β”‚ β”‚ + β”Œβ”€β”€β–Όβ”€β–Όβ”€β”€β” + β”‚ Group β”‚ + β””β”€β”€β”€β”¬β”€β”€β”€β”˜ + β”‚ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ Abelian Group β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β” + β”‚Semiring β”‚ + β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ + β”‚ + β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β” + β”‚ Ring β”‚ + β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ β”‚ + β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” + β”‚ Module β”‚ β”‚Commutativeβ”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ Ring β”‚ + β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ + β”‚ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ Integral Domain β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚Unique Factorization Domainβ”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚Principal Ideal Domain β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚Euclidean Domain β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”Œβ”€β”€β”€β–Όβ”€β”€β”€β” + β”‚ Field │────────────────────────┐ + β””β”€β”€β”€β”¬β”€β”€β”€β”˜ β”‚ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ + β”‚ β”‚ β”‚ + β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” + β”‚ Finite β”‚ β”‚ Infinite β”‚ β”‚ Vector β”‚ + β”‚ Field β”‚ β”‚ Field β”‚ β”‚ Space β”‚ + β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” + β”‚ Field β”‚ + β”‚ Extension β”‚ + β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ + β”‚ + β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” + β”‚ Extension β”‚ + β”‚ Tower β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +## Operator Traits for Algebraic Structures + +This module defines traits for various operators and their properties, providing a foundation for implementing algebraic +structures in Rust. + +An algebraic structure consists of a set with one or more binary operations. Let $S$ be a set (Self) and $\bullet$ be a +binary operation on $S$. Here are the key properties a binary operation may possess, organized from simplest to most +complex: + +- (Closure) $\forall a, b \in S, a \bullet b \in S$ - Guaranteed by the operators provided +- (Totality) $\forall a, b \in S, a \bullet b$ is defined - Guaranteed by Rust +- (Commutativity) $\forall a, b \in S, a \bullet b = b \bullet a$ - Marker trait +- (Associativity) $\forall a, b, c \in S, (a \bullet b) \bullet c = a \bullet (b \bullet c)$ - Marker trait +- (Distributivity) $\forall a, b, c \in S, a * (b + c) = (a * b) + (a * c)$ - Marker trait + +Additional properties to be implemented: + +- (Idempotence) $\forall a \in S, a \bullet a = a$ +- (Identity) $\exists e \in S, \forall a \in S, e \bullet a = a \bullet e = a$ +- (Inverses) $\forall a \in S, \exists b \in S, a \bullet b = b \bullet a = e$ (where $e$ is the identity) +- (Cancellation) $\forall a, b, c \in S, a \bullet b = a \bullet c \Rightarrow b = c$ ($a \neq 0$ if $\exists$ zero + element) +- (Divisibility) $\forall a, b \in S, \exists x \in S, a \bullet x = b$ +- (Regularity) $\forall a \in S, \exists x \in S, a \bullet x \bullet a = a$ +- (Alternativity) $\forall a, b \in S, (a \bullet a) \bullet b = a \bullet (a \bullet b) \wedge (b \bullet a) \bullet + a = b \bullet (a \bullet a)$ +- (Absorption) $\forall a, b \in S, a * (a + b) = a \wedge a + (a * b) = a$ +- (Monotonicity) $\forall a, b, c \in S, a \leq b \Rightarrow a \bullet c \leq b \bullet c \wedge c \bullet a \leq c + \bullet b$ +- (Modularity) $\forall a, b, c \in S, a \leq c \Rightarrow a \vee (b \wedge c) = (a \vee b) \wedge c$ +- (Switchability) $\forall x, y, z \in S, (x + y) * z = x + (y * z)$ +- (Min/Max Ops) $\forall a, b \in S, a \vee b = \min\{a,b\}, a \wedge b = \max\{a,b\}$ +- (Defect Op) $\forall a, b \in S, a *_3 b = a + b - 3$ +- (Continuity) $\forall V \subseteq S$ open, $f^{-1}(V)$ is open (for $f: S \rightarrow S, S$ topological) +- (Solvability) $\exists$ series $\{G_i\} | G = G_0 \triangleright G_1 \triangleright \ldots \triangleright G_n = + \{e\}, [G_i, G_i] \leq G_{i+1}$ +- (Alg. Closure) $\forall p(x) \in S[x]$ non-constant, $\exists a \in S | p(a) = 0$ + +The traits and blanket implementations provided serve several important purposes: + +1. Closure: All `Closed*` traits ensure that operations on a type always produce a result of the same type. This is + crucial for defining algebraic structures. + +2. Reference Operations: The `*Ref` variants of traits allow for more efficient operations when the right-hand side can + be borrowed, which is common in many algorithms. + +3. Marker Traits: Traits like `Commutative`, `Associative`, etc., allow types to declare which algebraic properties they + satisfy. This can be used for compile-time checks and to enable more generic implementations of algorithms. + +4. Extensibility: New types that implement the standard traits (like `Add`, `Sub`, etc.) will automatically get the + closed trait implementations, making the system more extensible and future-proof. + +5. Type Safety: These traits help in catching type-related errors at compile-time, ensuring that operations maintain + closure within the same type. + +6. Generic Programming: These traits enable more expressive generic programming, allowing functions and structs to be + generic over types that are closed under certain operations or satisfy certain algebraic properties. + +## API Overview + +Noether provides traits for various algebraic structures, including: + +- `Magma`: Set with a binary operation +- `Semigroup`: Associative magma +- `Monoid`: Semigroup with identity element +- `Group`: Monoid where every element has an inverse +- `Ring`: Set with two operations (addition and multiplication) satisfying certain axioms +- `Field`: Commutative ring where every non-zero element has a multiplicative inverse +- `VectorSpace`: An abelian group with scalar multiplication over a field +- `Module`: Similar to a vector space, but over a ring instead of a field +- `Polynomial`: Represents polynomials over a field +- `FieldExtension`: Represents field extensions + +Each trait comes with methods defining the operations and properties of the respective algebraic structure. For a +complete list of traits and their methods, please refer to the [API documentation](https://docs.rs/noether). + +## Advanced Usage + +Noether's power lies in its ability to express complex mathematical concepts and algorithms generically. Here's an +example of a function that works with any type implementing the `Field` trait: + +```rust +use noether::Field; + +fn polynomial_evaluation(coefficients: &[F], x: F) -> F { + coefficients.iter().rev().fold(F::zero(), |acc, &c| acc * x + c) +} + +// This function works for any type implementing the Field trait +``` + +You can use this function with any type that implements the `Field` trait, whether it's a built-in numeric type or a +custom type like our `Z5` from the earlier example. + +## Performance + +Noether is designed with performance in mind, leveraging Rust's zero-cost abstractions. The use of trait-based +polymorphism allows for efficient, monomorphized code when used with concrete types. + +However, as with any abstract library, be aware that extensive use of dynamic dispatch (e.g., through trait objects) may +incur some runtime cost. In most cases, the compiler can optimize away the abstractions, resulting in performance +equivalent to hand-written implementations. + +## Roadmap + +Future plans for Noether include: + +- Implementing more advanced algebraic structures (e.g., Lattices, Boolean Algebras) +- Adding support for infinite fields and their operations +- Implementing algorithms for polynomial operations over fields +- Adding support for symbolic computation +- Implementing numerical methods for root finding and equation solving +- Enhancing documentation with more examples and tutorials +- Optimizing performance for common operations +- Adding a comprehensive test suite, including property-based tests +- Exploring integration with other mathematical libraries in the Rust ecosystem + +## Contributing + +Contributions are welcome! Please feel free to submit issues, feature requests, or pull requests on +the [GitHub repository](https://github.com/warlock-labs/noether). + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +--- + +We hope that Noether will be a valuable tool for cryptographers, mathematicians, scientists, and +developers working with algebraic structures in Rust. If you have any questions, suggestions, or +feedback, please don't hesitate to open an issue on our GitHub repository or contact the +maintainers. + +Happy coding with Noether! \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 59274ff..e453e0c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,157 +1,3 @@ -//! # Noether -//! -//! Noether provides traits and blanket implementations for algebraic structures, -//! from basic ones like magmas to more complex ones like fields. It leans heavily on -//! the basic traits available in std::ops and num_traits. -//! -//! The goal is to provide a common interface for working with algebraic structures -//! in Rust. -//! -//! Interestingly, these traits can be used to categorize implementations of various -//! structs based on the properties they satisfy, and be applied in most cases for -//! anything from scalar values to n-dimensional arrays. -//! -//! ## Hierarchy of Algebraic Structures -//! -//! ```text -//! β”Œβ”€β”€β”€β”€β”€β” -//! β”‚ Set β”‚ -//! β””β”€β”€β”¬β”€β”€β”˜ -//! β”‚ -//! β”Œβ”€β”€β–Όβ”€β”€β” -//! β”‚Magmaβ”‚ -//! β””β”€β”€β”¬β”€β”€β”˜ -//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -//! β”‚ β”‚ β”‚ -//! β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” -//! β”‚Quasigroup β”‚ β”‚ Semigroup β”‚ β”‚Semilatticeβ”‚ -//! β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -//! β”‚ β”‚ -//! β”Œβ”€β”€β”€β–Όβ”€β”€β”€β” β”Œβ”€β”€β”€β–Όβ”€β”€β”€β” -//! β”‚ Loop β”‚ β”‚Monoid β”‚ -//! β””β”€β”€β”€β”¬β”€β”€β”€β”˜ β””β”€β”€β”€β”¬β”€β”€β”€β”˜ -//! β”‚ β”‚ -//! └────────┐ β”Œβ”€β”€β”€β”€β”€β”˜ -//! β”‚ β”‚ -//! β”Œβ”€β”€β–Όβ”€β–Όβ”€β”€β” -//! β”‚ Group β”‚ -//! β””β”€β”€β”€β”¬β”€β”€β”€β”˜ -//! β”‚ -//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β” -//! β”‚ Abelian Group β”‚ -//! β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -//! β”‚ -//! β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β” -//! β”‚Semiring β”‚ -//! β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ -//! β”‚ -//! β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β” -//! β”‚ Ring β”‚ -//! β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ -//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -//! β”‚ β”‚ -//! β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” -//! β”‚ Module β”‚ β”‚Commutativeβ”‚ -//! β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ Ring β”‚ -//! β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ -//! β”‚ -//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β” -//! β”‚ Integral Domain β”‚ -//! β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -//! β”‚ -//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -//! β”‚Unique Factorization Domainβ”‚ -//! β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -//! β”‚ -//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” -//! β”‚Principal Ideal Domain β”‚ -//! β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -//! β”‚ -//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β” -//! β”‚Euclidean Domain β”‚ -//! β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -//! β”‚ -//! β”Œβ”€β”€β”€β–Όβ”€β”€β”€β” -//! β”‚ Field │────────────────────────┐ -//! β””β”€β”€β”€β”¬β”€β”€β”€β”˜ β”‚ -//! β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ -//! β”‚ β”‚ β”‚ -//! β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” -//! β”‚ Finite β”‚ β”‚ Infinite β”‚ β”‚ Vector β”‚ -//! β”‚ Field β”‚ β”‚ Field β”‚ β”‚ Space β”‚ -//! β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -//! β”‚ -//! β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” -//! β”‚ Field β”‚ -//! β”‚ Extension β”‚ -//! β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ -//! β”‚ -//! β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β” -//! β”‚ Extension β”‚ -//! β”‚ Tower β”‚ -//! β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ -//! ``` -//! # Operator Traits for Algebraic Structures -//! -//! This module defines traits for various operators and their properties, -//! providing a foundation for implementing algebraic structures in Rust. -//! -//! An algebraic structure consists of a set with one or more binary operations. -//! Let 𝑆 be a set (Self) and β€’ be a binary operation on 𝑆. -//! Here are the key properties a binary operation may possess, organized from simplest to most complex: -//! -//! - (Closure) βˆ€ a, b ∈ 𝑆, a β€’ b ∈ 𝑆 - Guaranteed by the operators provided -//! - (Totality) βˆ€ a, b ∈ 𝑆, a β€’ b is defined - Guaranteed by Rust -//! - (Commutativity) βˆ€ a, b ∈ 𝑆, a β€’ b = b β€’ a - Marker trait -//! - (Associativity) βˆ€ a, b, c ∈ 𝑆, (a β€’ b) β€’ c = a β€’ (b β€’ c) - Marker trait -//! - (Distributivity) βˆ€ a, b, c ∈ 𝑆, a * (b + c) = (a * b) + (a * c) - Marker trait -//! -//! To be determined: -//! - (Idempotence) βˆ€ a ∈ 𝑆, a β€’ a = a -//! - (Identity) βˆƒ e ∈ 𝑆, βˆ€ a ∈ 𝑆, e β€’ a = a β€’ e = a -//! - (Inverses) βˆ€ a ∈ 𝑆, βˆƒ b ∈ 𝑆, a β€’ b = b β€’ a = e (where e is the identity) -//! - (Cancellation) βˆ€ a, b, c ∈ 𝑆, a β€’ b = a β€’ c β‡’ b = c (a β‰  0 if βˆƒ zero element) -//! - (Divisibility) βˆ€ a, b ∈ 𝑆, βˆƒ x ∈ 𝑆, a β€’ x = b -//! - (Regularity) βˆ€ a ∈ 𝑆, βˆƒ x ∈ 𝑆, a β€’ x β€’ a = a -//! - (Alternativity) βˆ€ a, b ∈ 𝑆, (a β€’ a) β€’ b = a β€’ (a β€’ b) ∧ (b β€’ a) β€’ a = b β€’ (a β€’ a) -//! - (Absorption) βˆ€ a, b ∈ 𝑆, a * (a + b) = a ∧ a + (a * b) = a -//! - (Monotonicity) βˆ€ a, b, c ∈ 𝑆, a ≀ b β‡’ a β€’ c ≀ b β€’ c ∧ c β€’ a ≀ c β€’ b -//! - (Modularity) βˆ€ a, b, c ∈ 𝑆, a ≀ c β‡’ a ∨ (b ∧ c) = (a ∨ b) ∧ c -//! - (Switchability) βˆ€ x, y, z ∈ S, (x + y) * z = x + (y * z) -//! - (Min/Max Ops) βˆ€ a, b ∈ S, a ∨ b = min{a,b}, a ∧ b = max{a,b} -//! - (Defect Op) βˆ€ a, b ∈ S, a *₃ b = a + b - 3 -//! - (Continuity) βˆ€ V βŠ† 𝑆 open, f⁻¹(V) is open (for f: 𝑆 β†’ 𝑆, 𝑆 topological) -//! ```text -//! - (Solvability) βˆƒ series {Gα΅’} | G = Gβ‚€ β–· G₁ β–· ... β–· Gβ‚™ = {e}, [Gα΅’, Gα΅’] ≀ Gα΅’β‚Šβ‚ -//! - (Alg. Closure) βˆ€ p(x) ∈ 𝑆[x] non-constant, βˆƒ a ∈ 𝑆 | p(a) = 0 -//! ``` -//! -//! The traits and blanket implementations provided above serve several important purposes: -//! -//! 1. Closure: All `Closed*` traits ensure that operations on a type always produce a result -//! of the same type. This is crucial for defining algebraic structures. -//! -//! 2. Reference Operations: The `*Ref` variants of traits allow for more efficient operations -//! when the right-hand side can be borrowed, which is common in many algorithms. -//! -//! 3. Marker Traits: Traits like `Commutative`, `Associative`, etc., allow types to declare -//! which algebraic properties they satisfy. This can be used for compile-time checks -//! and to enable more generic implementations of algorithms. There is work to be done -//! to complete the compile time checks. -//! -//! 4. Extensibility: New types that implement the standard traits (like `Add`, `Sub`, etc.) -//! will automatically get the closed trait implementations, making the system more -//! extensible and future-proof. -//! -//! 5. Type Safety: These traits help in catching type-related errors at compile-time, -//! ensuring that operations maintain closure within the same type. -//! -//! 6. Generic Programming: These traits enable more expressive generic programming, -//! allowing functions and structs to be generic over types that are closed under -//! certain operations or satisfy certain algebraic properties. -//! -//! TODO(Replace blanket implementations with derive) - use num_traits::{Euclid, Inv, One, Zero}; use std::ops::{ Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign,