noether/
rings.rs

1//! Ring theory structures.
2//!
3//! This module defines traits for algebraic structures from rings to integral domains.
4
5use crate::groups::{AdditiveAbelianGroup, MultiplicativeMonoid};
6use crate::operations::{ClosedAdd, ClosedMul, Distributive};
7use crate::CommutativeMultiplication;
8use num_traits::Euclid;
9
10/// Represents a Ring, an algebraic structure with two binary operations (addition and multiplication) that satisfy certain axioms.
11///
12/// # Mathematical Definition
13/// A ring (R, +, ·) consists of:
14/// - A set R
15/// - Two binary operations + (addition) and · (multiplication) on R
16///
17/// # Formal Definition
18/// Let (R, +, ·) be a ring. Then:
19/// 1. (R, +) is an abelian group:
20///    a. ∀ a, b, c ∈ R, (a + b) + c = a + (b + c) (associativity)
21///    b. ∀ a, b ∈ R, a + b = b + a (commutativity)
22///    c. ∃ 0 ∈ R, ∀ a ∈ R, a + 0 = 0 + a = a (identity)
23///    d. ∀ a ∈ R, ∃ -a ∈ R, a + (-a) = (-a) + a = 0 (inverse)
24/// 2. (R, ·) is a monoid:
25///    a. ∀ a, b, c ∈ R, (a · b) · c = a · (b · c) (associativity)
26///    b. ∃ 1 ∈ R, ∀ a ∈ R, 1 · a = a · 1 = a (identity)
27/// 3. Multiplication is distributive over addition:
28///    a. ∀ a, b, c ∈ R, a · (b + c) = (a · b) + (a · c) (left distributivity)
29///    b. ∀ a, b, c ∈ R, (a + b) · c = (a · c) + (b · c) (right distributivity)
30pub trait Ring: AdditiveAbelianGroup + MultiplicativeMonoid + Distributive {}
31
32/// Represents a Commutative Ring, an algebraic structure where multiplication is commutative.
33///
34/// # Mathematical Definition
35/// A commutative ring (R, +, ·) is a ring where:
36/// - The multiplication operation is commutative
37///
38/// # Formal Definition
39/// Let (R, +, ·) be a commutative ring. Then:
40/// 1. (R, +, ·) is a ring
41/// 2. ∀ a, b ∈ R, a · b = b · a (commutativity of multiplication)
42pub trait CommutativeRing: Ring + CommutativeMultiplication {}
43
44/// Represents an Integral Domain, a commutative ring with no zero divisors.
45///
46/// # Mathematical Definition
47/// An integral domain (D, +, ·) is a commutative ring where:
48/// - The ring has no zero divisors
49///
50/// # Formal Definition
51/// Let (D, +, ·) be an integral domain. Then:
52/// 1. (D, +, ·) is a commutative ring
53/// 2. D has no zero divisors:
54///    ∀ a, b ∈ D, if a · b = 0, then a = 0 or b = 0
55/// 3. The zero element is distinct from the unity:
56///    0 ≠ 1
57pub trait IntegralDomain: CommutativeRing {}
58
59/// Represents a Unique Factorization Domain (UFD), an integral domain where every non-zero
60/// non-unit element has a unique factorization into irreducible elements.
61///
62/// # Mathematical Definition
63/// A UFD (R, +, ·) is an integral domain that satisfies:
64/// 1. Every non-zero non-unit element can be factored into irreducible elements.
65/// 2. This factorization is unique up to order and associates.
66///
67/// # Formal Definition
68/// Let R be an integral domain. R is a UFD if:
69/// 1. For every non-zero non-unit a ∈ R, there exist irreducible elements p₁, ..., pₙ such that
70///    a = p₁ · ... · pₙ
71/// 2. If a = p₁ · ... · pₙ = q₁ · ... · qₘ are two factorizations of a into irreducible elements,
72///    then n = m and there exists a bijection σ: {1, ..., n} → {1, ..., n} such that pᵢ is
73///    associated to qₛᵢ for all i.
74pub trait UniqueFactorizationDomain: IntegralDomain {}
75
76/// Represents a Principal Ideal Domain (PID), an integral domain where every ideal is principal.
77///
78/// # Mathematical Definition
79/// A Principal Ideal Domain (R, +, ·) is an integral domain where:
80/// - Every ideal in R is principal (can be generated by a single element)
81///
82/// # Formal Definition
83/// Let R be an integral domain. R is a PID if for every ideal I ⊆ R, there exists an element a ∈ R
84/// such that I = (a) = {ra | r ∈ R}.
85pub trait PrincipalIdealDomain: UniqueFactorizationDomain {}
86
87/// Represents a Polynomial over a ring.
88///
89/// # Mathematical Definition
90/// A polynomial over a field F is an expression of the form:
91/// a_n * X^n + a_{n-1} * X^{n-1} + ... + a_1 * X + a_0
92/// where a_i ∈ F are called the coefficients, and X is the indeterminate.
93pub trait Polynomial: Clone + PartialEq + ClosedAdd + ClosedMul + Euclid {
94    /// The type of the coefficients of the polynomial.
95    type Coefficient: Ring;
96
97    /// Returns the degree of the polynomial.
98    fn degree(&self) -> usize;
99
100    /// Gets the coefficient of the term with the given degree.
101    fn coefficient(&self, degree: usize) -> Self::Coefficient;
102}
103
104// Blanket implementations
105impl<T: AdditiveAbelianGroup + MultiplicativeMonoid + Distributive> Ring for T {}
106impl<T: Ring + CommutativeMultiplication> CommutativeRing for T {}
107impl<T: CommutativeRing> IntegralDomain for T {}
108impl<T: IntegralDomain> UniqueFactorizationDomain for T {}
109impl<T: UniqueFactorizationDomain> PrincipalIdealDomain for T {}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114    use crate::operations::{
115        AssociativeAddition, AssociativeMultiplication, CommutativeAddition,
116        CommutativeMultiplication, Distributive,
117    };
118    use num_traits::{One, Zero};
119    use std::ops::{Add, Mul};
120
121    // A simple integer-based structure for testing ring traits
122    #[derive(Debug, Clone, Copy, PartialEq)]
123    struct TestRing(i32);
124
125    impl Add for TestRing {
126        type Output = Self;
127
128        fn add(self, rhs: Self) -> Self::Output {
129            TestRing(self.0 + rhs.0)
130        }
131    }
132
133    impl std::ops::AddAssign for TestRing {
134        fn add_assign(&mut self, rhs: Self) {
135            self.0 += rhs.0;
136        }
137    }
138
139    impl std::ops::Sub for TestRing {
140        type Output = Self;
141
142        fn sub(self, rhs: Self) -> Self::Output {
143            TestRing(self.0 - rhs.0)
144        }
145    }
146
147    impl std::ops::SubAssign for TestRing {
148        fn sub_assign(&mut self, rhs: Self) {
149            self.0 -= rhs.0;
150        }
151    }
152
153    impl Mul for TestRing {
154        type Output = Self;
155
156        fn mul(self, rhs: Self) -> Self::Output {
157            TestRing(self.0 * rhs.0)
158        }
159    }
160
161    impl std::ops::MulAssign for TestRing {
162        fn mul_assign(&mut self, rhs: Self) {
163            self.0 *= rhs.0;
164        }
165    }
166
167    impl std::ops::Div for TestRing {
168        type Output = Self;
169
170        fn div(self, rhs: Self) -> Self::Output {
171            TestRing(self.0 / rhs.0)
172        }
173    }
174
175    impl std::ops::DivAssign for TestRing {
176        fn div_assign(&mut self, rhs: Self) {
177            self.0 /= rhs.0;
178        }
179    }
180
181    impl std::ops::Rem for TestRing {
182        type Output = Self;
183
184        fn rem(self, rhs: Self) -> Self::Output {
185            TestRing(self.0 % rhs.0)
186        }
187    }
188
189    impl std::ops::RemAssign for TestRing {
190        fn rem_assign(&mut self, rhs: Self) {
191            self.0 %= rhs.0;
192        }
193    }
194
195    impl Zero for TestRing {
196        fn zero() -> Self {
197            TestRing(0)
198        }
199
200        fn is_zero(&self) -> bool {
201            self.0 == 0
202        }
203    }
204
205    impl One for TestRing {
206        fn one() -> Self {
207            TestRing(1)
208        }
209    }
210
211    impl std::ops::Neg for TestRing {
212        type Output = Self;
213
214        fn neg(self) -> Self::Output {
215            TestRing(-self.0)
216        }
217    }
218
219    impl num_traits::Inv for TestRing {
220        type Output = Self;
221
222        fn inv(self) -> Self::Output {
223            if self.0 == 0 {
224                panic!("Cannot invert zero");
225            }
226            if self.0 == 1 || self.0 == -1 {
227                self
228            } else {
229                panic!("Only 1 and -1 have multiplicative inverses in integer ring");
230            }
231        }
232    }
233
234    impl num_traits::Euclid for TestRing {
235        fn div_euclid(&self, v: &Self) -> Self {
236            TestRing(self.0.div_euclid(v.0))
237        }
238
239        fn rem_euclid(&self, v: &Self) -> Self {
240            TestRing(self.0.rem_euclid(v.0))
241        }
242    }
243
244    // Marker traits for algebraic properties
245    impl CommutativeAddition for TestRing {}
246    impl AssociativeAddition for TestRing {}
247    impl CommutativeMultiplication for TestRing {}
248    impl AssociativeMultiplication for TestRing {}
249    impl Distributive for TestRing {}
250
251    // Simple Polynomial for testing, we'll skip the Polynomial trait since it has Euclid requirement
252    #[derive(Debug, Clone, PartialEq)]
253    struct SimplePolynomial {
254        coefficients: Vec<i32>, // Coefficients in ascending order of degree
255    }
256
257    impl SimplePolynomial {
258        fn new(coefficients: Vec<i32>) -> Self {
259            // Remove trailing zeros
260            let mut coeffs = coefficients;
261            while coeffs.len() > 1 && *coeffs.last().unwrap() == 0 {
262                coeffs.pop();
263            }
264            Self {
265                coefficients: coeffs,
266            }
267        }
268
269        fn degree(&self) -> usize {
270            if self.coefficients.is_empty()
271                || (self.coefficients.len() == 1 && self.coefficients[0] == 0)
272            {
273                0
274            } else {
275                self.coefficients.len() - 1
276            }
277        }
278
279        fn coefficient(&self, degree: usize) -> i32 {
280            if degree < self.coefficients.len() {
281                self.coefficients[degree]
282            } else {
283                0
284            }
285        }
286    }
287
288    impl Add for SimplePolynomial {
289        type Output = Self;
290
291        fn add(self, rhs: Self) -> Self::Output {
292            let max_len = self.coefficients.len().max(rhs.coefficients.len());
293            let mut result = vec![0; max_len];
294
295            for (i, &coeff) in self.coefficients.iter().enumerate() {
296                result[i] += coeff;
297            }
298
299            for (i, &coeff) in rhs.coefficients.iter().enumerate() {
300                result[i] += coeff;
301            }
302
303            Self::new(result)
304        }
305    }
306
307    impl Mul for SimplePolynomial {
308        type Output = Self;
309
310        fn mul(self, rhs: Self) -> Self::Output {
311            if self.coefficients.is_empty() || rhs.coefficients.is_empty() {
312                return Self::new(vec![0]);
313            }
314
315            let result_degree = self.degree() + rhs.degree();
316            let mut result = vec![0; result_degree + 1];
317
318            for (i, &a) in self.coefficients.iter().enumerate() {
319                for (j, &b) in rhs.coefficients.iter().enumerate() {
320                    result[i + j] += a * b;
321                }
322            }
323
324            Self::new(result)
325        }
326    }
327
328    impl Zero for SimplePolynomial {
329        fn zero() -> Self {
330            Self::new(vec![0])
331        }
332
333        fn is_zero(&self) -> bool {
334            self.coefficients.len() == 1 && self.coefficients[0] == 0
335        }
336    }
337
338    impl One for SimplePolynomial {
339        fn one() -> Self {
340            Self::new(vec![1])
341        }
342    }
343
344    // Marker traits
345    impl CommutativeAddition for SimplePolynomial {}
346    impl AssociativeAddition for SimplePolynomial {}
347    impl CommutativeMultiplication for SimplePolynomial {}
348    impl AssociativeMultiplication for SimplePolynomial {}
349    impl Distributive for SimplePolynomial {}
350
351    #[test]
352    fn test_ring_trait() {
353        // Test that our integer types implement Ring
354        fn assert_is_ring<T: Ring>(_: &T) {}
355
356        assert_is_ring(&5i32);
357        assert_is_ring(&10i64);
358        assert_is_ring(&TestRing(42));
359    }
360
361    #[test]
362    fn test_commutative_ring_trait() {
363        // Test that our integer types implement CommutativeRing
364        fn assert_is_commutative_ring<T: CommutativeRing>(_: &T) {}
365
366        assert_is_commutative_ring(&5i32);
367        assert_is_commutative_ring(&10i64);
368        assert_is_commutative_ring(&TestRing(42));
369    }
370
371    #[test]
372    fn test_integral_domain_trait() {
373        // Test that our integer types implement IntegralDomain
374        fn assert_is_integral_domain<T: IntegralDomain>(_: &T) {}
375
376        assert_is_integral_domain(&5i32);
377        assert_is_integral_domain(&10i64);
378        assert_is_integral_domain(&TestRing(42));
379    }
380
381    #[test]
382    fn test_ufd_trait() {
383        // Test that our integer types implement UniqueFactorizationDomain
384        fn assert_is_ufd<T: UniqueFactorizationDomain>(_: &T) {}
385
386        assert_is_ufd(&5i32);
387        assert_is_ufd(&10i64);
388        assert_is_ufd(&TestRing(42));
389    }
390
391    #[test]
392    fn test_pid_trait() {
393        // Test that our integer types implement PrincipalIdealDomain
394        fn assert_is_pid<T: PrincipalIdealDomain>(_: &T) {}
395
396        assert_is_pid(&5i32);
397        assert_is_pid(&10i64);
398        assert_is_pid(&TestRing(42));
399    }
400
401    #[test]
402    fn test_simple_polynomial() {
403        // Create and test polynomials
404        // p(x) = 1 + 2x + 3x^2
405        let p1 = SimplePolynomial::new(vec![1, 2, 3]);
406        // q(x) = 4 + 5x
407        let p2 = SimplePolynomial::new(vec![4, 5]);
408
409        // Test polynomial addition
410        // (1 + 2x + 3x^2) + (4 + 5x) = 5 + 7x + 3x^2
411        let sum = p1.clone() + p2.clone();
412        assert_eq!(sum, SimplePolynomial::new(vec![5, 7, 3]));
413
414        // Test polynomial multiplication
415        // (1 + 2x + 3x^2) * (4 + 5x) = 4 + 13x + 22x^2 + 15x^3
416        let product = p1.clone() * p2.clone();
417        assert_eq!(product, SimplePolynomial::new(vec![4, 13, 22, 15]));
418
419        // Test degree
420        assert_eq!(p1.degree(), 2);
421        assert_eq!(p2.degree(), 1);
422        assert_eq!(product.degree(), 3);
423
424        // Test coefficient
425        assert_eq!(p1.coefficient(0), 1);
426        assert_eq!(p1.coefficient(1), 2);
427        assert_eq!(p1.coefficient(2), 3);
428        assert_eq!(p1.coefficient(3), 0); // Beyond the degree
429
430        // Test zero polynomial
431        let zero = SimplePolynomial::zero();
432        assert_eq!(zero, SimplePolynomial::new(vec![0]));
433        assert!(zero.is_zero());
434        assert_eq!(zero.degree(), 0);
435
436        // Test one polynomial
437        let one = SimplePolynomial::one();
438        assert_eq!(one, SimplePolynomial::new(vec![1]));
439        assert_eq!(one.degree(), 0);
440    }
441
442    #[test]
443    fn test_ring_axioms() {
444        // Test ring axioms for integers
445
446        // 1. (R, +) is an abelian group
447        // a. Associativity: (a + b) + c = a + (b + c)
448        let a = TestRing(5);
449        let b = TestRing(7);
450        let c = TestRing(10);
451        assert_eq!((a + b) + c, a + (b + c));
452
453        // b. Commutativity: a + b = b + a
454        assert_eq!(a + b, b + a);
455
456        // c. Identity: a + 0 = a
457        assert_eq!(a + TestRing::zero(), a);
458
459        // d. Inverse: a + (-a) = 0
460        assert_eq!(a + (-a), TestRing::zero());
461
462        // 2. (R, ·) is a monoid
463        // a. Associativity: (a · b) · c = a · (b · c)
464        assert_eq!((a * b) * c, a * (b * c));
465
466        // b. Identity: a · 1 = a
467        assert_eq!(a * TestRing::one(), a);
468
469        // 3. Distributivity:
470        // Left: a · (b + c) = (a · b) + (a · c)
471        assert_eq!(a * (b + c), (a * b) + (a * c));
472
473        // Right: (a + b) · c = (a · c) + (b · c)
474        assert_eq!((a + b) * c, (a * c) + (b * c));
475    }
476
477    #[test]
478    fn test_polynomial_ring_structure() {
479        // Test that our polynomial implementation satisfies ring axioms
480
481        // Define some polynomials
482        let p = SimplePolynomial::new(vec![1, 2, 3]); // 1 + 2x + 3x²
483        let q = SimplePolynomial::new(vec![4, 5]); // 4 + 5x
484        let r = SimplePolynomial::new(vec![6, 7, 8]); // 6 + 7x + 8x²
485
486        // Test associativity of addition
487        assert_eq!(
488            (p.clone() + q.clone()) + r.clone(),
489            p.clone() + (q.clone() + r.clone())
490        );
491
492        // Test commutativity of addition
493        assert_eq!(p.clone() + q.clone(), q.clone() + p.clone());
494
495        // Test additive identity
496        let zero = SimplePolynomial::zero();
497        assert_eq!(p.clone() + zero.clone(), p.clone());
498
499        // Test associativity of multiplication
500        assert_eq!(
501            (p.clone() * q.clone()) * r.clone(),
502            p.clone() * (q.clone() * r.clone())
503        );
504
505        // Test multiplicative identity
506        let one = SimplePolynomial::one();
507        assert_eq!(p.clone() * one.clone(), p.clone());
508
509        // Test distributivity
510        assert_eq!(
511            p.clone() * (q.clone() + r.clone()),
512            (p.clone() * q.clone()) + (p.clone() * r.clone())
513        );
514    }
515}