algebraeon_rings/
rational.rs

1use crate::algebraic_number_field::{AlgebraicIntegerRingSignature, AlgebraicNumberFieldSignature};
2use crate::polynomial::{PolynomialStructure, factorize_by_factorize_primitive_part};
3use crate::structure::*;
4use algebraeon_nzq::traits::*;
5use algebraeon_nzq::*;
6use algebraeon_sets::structure::*;
7use static_assertions::const_assert;
8use std::borrow::Cow;
9
10impl RinglikeSpecializationSignature for RationalCanonicalStructure {
11    fn try_ring_restructure(&self) -> Option<impl EqSignature<Set = Self::Set> + RingSignature> {
12        Some(self.clone())
13    }
14
15    fn try_char_zero_ring_restructure(
16        &self,
17    ) -> Option<impl EqSignature<Set = Self::Set> + CharZeroRingSignature> {
18        Some(self.clone())
19    }
20}
21
22impl ZeroSignature for RationalCanonicalStructure {
23    fn zero(&self) -> Self::Set {
24        Rational::ZERO
25    }
26}
27
28impl AdditionSignature for RationalCanonicalStructure {
29    fn add(&self, a: &Self::Set, b: &Self::Set) -> Self::Set {
30        a + b
31    }
32}
33
34impl CancellativeAdditionSignature for RationalCanonicalStructure {
35    fn try_sub(&self, a: &Self::Set, b: &Self::Set) -> Option<Self::Set> {
36        Some(self.sub(a, b))
37    }
38}
39
40impl TryNegateSignature for RationalCanonicalStructure {
41    fn try_neg(&self, a: &Self::Set) -> Option<Self::Set> {
42        Some(self.neg(a))
43    }
44}
45
46impl AdditiveMonoidSignature for RationalCanonicalStructure {}
47
48impl AdditiveGroupSignature for RationalCanonicalStructure {
49    fn neg(&self, a: &Self::Set) -> Self::Set {
50        -a
51    }
52
53    fn sub(&self, a: &Self::Set, b: &Self::Set) -> Self::Set {
54        a - b
55    }
56}
57
58impl OneSignature for RationalCanonicalStructure {
59    fn one(&self) -> Self::Set {
60        Rational::ONE
61    }
62}
63
64impl MultiplicationSignature for RationalCanonicalStructure {
65    fn mul(&self, a: &Self::Set, b: &Self::Set) -> Self::Set {
66        a * b
67    }
68}
69
70impl CommutativeMultiplicationSignature for RationalCanonicalStructure {}
71
72impl MultiplicativeMonoidSignature for RationalCanonicalStructure {}
73
74impl MultiplicativeAbsorptionMonoidSignature for RationalCanonicalStructure {}
75
76impl LeftDistributiveMultiplicationOverAddition for RationalCanonicalStructure {}
77
78impl RightDistributiveMultiplicationOverAddition for RationalCanonicalStructure {}
79
80impl SemiRingSignature for RationalCanonicalStructure {}
81
82impl RingSignature for RationalCanonicalStructure {
83    fn is_reduced(&self) -> Result<bool, String> {
84        Ok(true)
85    }
86}
87
88impl CharacteristicSignature for RationalCanonicalStructure {
89    fn characteristic(&self) -> Natural {
90        Natural::ZERO
91    }
92}
93
94impl TryReciprocalSignature for RationalCanonicalStructure {
95    fn try_reciprocal(&self, a: &Self::Set) -> Option<Self::Set> {
96        self.try_divide(&self.one(), a)
97    }
98}
99
100impl CancellativeMultiplicationSignature for RationalCanonicalStructure {
101    fn try_divide(&self, a: &Self::Set, b: &Self::Set) -> Option<Self::Set> {
102        if b == &Rational::ZERO {
103            None
104        } else {
105            Some(a / b)
106        }
107    }
108}
109
110impl MultiplicativeIntegralMonoidSignature for RationalCanonicalStructure {}
111
112impl IntegralDomainSignature for RationalCanonicalStructure {}
113
114impl OrderedRingSignature for RationalCanonicalStructure {
115    fn ring_cmp(&self, a: &Self::Set, b: &Self::Set) -> std::cmp::Ordering {
116        Self::Set::cmp(a, b)
117    }
118}
119
120impl FieldSignature for RationalCanonicalStructure {}
121
122impl CharZeroRingSignature for RationalCanonicalStructure {
123    fn try_to_int(&self, x: &Rational) -> Option<Integer> {
124        let (n, d) = x.numerator_and_denominator();
125        debug_assert_ne!(&d, &Natural::ZERO);
126        if d == Natural::ONE { Some(n) } else { None }
127    }
128}
129
130impl CharZeroFieldSignature for RationalCanonicalStructure {
131    fn try_to_rat(&self, x: &Rational) -> Option<Rational> {
132        Some(x.clone())
133    }
134}
135
136impl<'h, B: BorrowedStructure<RationalCanonicalStructure>>
137    FreeModuleSignature<RationalCanonicalStructure>
138    for RingHomomorphismRangeModuleStructure<
139        'h,
140        RationalCanonicalStructure,
141        RationalCanonicalStructure,
142        PrincipalRationalMap<RationalCanonicalStructure, B>,
143    >
144{
145    type Basis = SingletonSetStructure;
146
147    fn basis_set(&self) -> impl std::borrow::Borrow<Self::Basis> {
148        Self::Basis::default()
149    }
150
151    fn to_component<'a>(&self, _: &(), v: &'a Rational) -> Cow<'a, Rational> {
152        Cow::Borrowed(v)
153    }
154
155    fn from_component(&self, _: &(), r: &Rational) -> Rational {
156        r.clone()
157    }
158}
159
160impl ComplexSubsetSignature for RationalCanonicalStructure {
161    fn as_f32_real_and_imaginary_parts(&self, z: &Self::Set) -> (f32, f32) {
162        (self.as_f32(z), 0.0)
163    }
164
165    fn as_f64_real_and_imaginary_parts(&self, z: &Self::Set) -> (f64, f64) {
166        (self.as_f64(z), 0.0)
167    }
168}
169
170impl RealSubsetSignature for RationalCanonicalStructure {
171    fn as_f64(&self, x: &Rational) -> f64 {
172        x.into()
173    }
174
175    fn as_f32(&self, x: &Self::Set) -> f32 {
176        x.into()
177    }
178}
179
180impl<B: BorrowedStructure<RationalCanonicalStructure>>
181    FieldOfFractionsInclusion<IntegerCanonicalStructure, RationalCanonicalStructure>
182    for PrincipalIntegerMap<RationalCanonicalStructure, B>
183{
184    fn numerator_and_denominator(&self, a: &Rational) -> (Integer, Integer) {
185        (a.numerator(), a.denominator().into())
186    }
187}
188
189impl RealRoundingSignature for RationalCanonicalStructure {
190    fn floor(&self, x: &Self::Set) -> Integer {
191        Floor::floor(x)
192    }
193    fn ceil(&self, x: &Self::Set) -> Integer {
194        Ceil::ceil(x)
195    }
196    fn round(&self, x: &Self::Set) -> Integer {
197        self.floor(&(x + Rational::ONE_HALF))
198    }
199}
200
201impl RealFromFloatSignature for RationalCanonicalStructure {
202    fn from_f64_approx(&self, x: f64) -> Self::Set {
203        Rational::try_from_float_simplest(x).unwrap()
204    }
205}
206
207impl AlgebraicNumberFieldSignature for RationalCanonicalStructure {
208    type Basis = SingletonSetStructure;
209    type RationalInclusion<B: BorrowedStructure<Self>> = PrincipalRationalMap<Self, B>;
210
211    fn inbound_finite_dimensional_rational_extension(&self) -> Self::RationalInclusion<&Self> {
212        self.inbound_principal_rational_map()
213    }
214    fn into_inbound_finite_dimensional_rational_extension(self) -> Self::RationalInclusion<Self> {
215        self.into_inbound_principal_rational_map()
216    }
217
218    fn generator(&self) -> Rational {
219        Rational::ONE
220    }
221
222    fn discriminant(&self) -> Integer {
223        Integer::ONE
224    }
225
226    fn integral_basis(&self) -> Vec<Self::Set> {
227        vec![Rational::ONE]
228    }
229
230    fn is_algebraic_integer(&self, a: &Self::Set) -> bool {
231        self.try_to_int(a).is_some()
232    }
233}
234
235const_assert!(
236    impls::impls!(IntegerCanonicalStructure : AlgebraicIntegerRingSignature<RationalCanonicalStructure>)
237);
238
239impl<B: BorrowedStructure<RationalCanonicalStructure>> FactoringMonoidSignature
240    for PolynomialStructure<RationalCanonicalStructure, B>
241{
242    fn factor_unchecked(
243        &self,
244        p: &Self::Set,
245    ) -> Factored<Self::Set, <Self::FactoredExponent as SetSignature>::Set> {
246        factorize_by_factorize_primitive_part(
247            &PrincipalIntegerMap::new(self.coeff_ring().clone()),
248            self,
249            p,
250        )
251    }
252}
253
254#[cfg(test)]
255mod tests {
256    use std::str::FromStr;
257
258    use super::*;
259
260    #[test]
261    fn test_rational_floor_ceil_round() {
262        let rat = |s: &'static str| Rational::from_str(s).unwrap();
263
264        assert_eq!(rat("-2").floor(), Integer::from(-2));
265        assert_eq!(rat("-7/4").floor(), Integer::from(-2));
266        assert_eq!(rat("-3/2").floor(), Integer::from(-2));
267        assert_eq!(rat("-5/4").floor(), Integer::from(-2));
268        assert_eq!(rat("-1").floor(), Integer::from(-1));
269        assert_eq!(rat("-3/4").floor(), Integer::from(-1));
270        assert_eq!(rat("-1/2").floor(), Integer::from(-1));
271        assert_eq!(rat("-1/4").floor(), Integer::from(-1));
272        assert_eq!(rat("0").floor(), Integer::from(0));
273        assert_eq!(rat("1/4").floor(), Integer::from(0));
274        assert_eq!(rat("1/2").floor(), Integer::from(0));
275        assert_eq!(rat("3/4").floor(), Integer::from(0));
276        assert_eq!(rat("1").floor(), Integer::from(1));
277        assert_eq!(rat("5/4").floor(), Integer::from(1));
278        assert_eq!(rat("3/2").floor(), Integer::from(1));
279        assert_eq!(rat("7/4").floor(), Integer::from(1));
280        assert_eq!(rat("2").floor(), Integer::from(2));
281
282        assert_eq!(rat("-2").ceil(), Integer::from(-2));
283        assert_eq!(rat("-7/4").ceil(), Integer::from(-1));
284        assert_eq!(rat("-3/2").ceil(), Integer::from(-1));
285        assert_eq!(rat("-5/4").ceil(), Integer::from(-1));
286        assert_eq!(rat("-1").ceil(), Integer::from(-1));
287        assert_eq!(rat("-3/4").ceil(), Integer::from(0));
288        assert_eq!(rat("-1/2").ceil(), Integer::from(0));
289        assert_eq!(rat("-1/4").ceil(), Integer::from(0));
290        assert_eq!(rat("0").ceil(), Integer::from(0));
291        assert_eq!(rat("1/4").ceil(), Integer::from(1));
292        assert_eq!(rat("1/2").ceil(), Integer::from(1));
293        assert_eq!(rat("3/4").ceil(), Integer::from(1));
294        assert_eq!(rat("1").ceil(), Integer::from(1));
295        assert_eq!(rat("5/4").ceil(), Integer::from(2));
296        assert_eq!(rat("3/2").ceil(), Integer::from(2));
297        assert_eq!(rat("7/4").ceil(), Integer::from(2));
298        assert_eq!(rat("2").ceil(), Integer::from(2));
299
300        assert_eq!(rat("-2").round(), Integer::from(-2));
301        assert_eq!(rat("-7/4").round(), Integer::from(-2));
302        assert!([Integer::from(-2), Integer::from(-1)].contains(&rat("-3/2").round()));
303        assert_eq!(rat("-5/4").round(), Integer::from(-1));
304        assert_eq!(rat("-1").round(), Integer::from(-1));
305        assert_eq!(rat("-3/4").round(), Integer::from(-1));
306        assert!([Integer::from(-1), Integer::from(0)].contains(&rat("-1/2").round()));
307        assert_eq!(rat("-1/4").round(), Integer::from(0));
308        assert_eq!(rat("0").round(), Integer::from(0));
309        assert_eq!(rat("1/4").round(), Integer::from(0));
310        assert!([Integer::from(0), Integer::from(1)].contains(&rat("1/2").round()));
311        assert_eq!(rat("3/4").round(), Integer::from(1));
312        assert_eq!(rat("1").round(), Integer::from(1));
313        assert_eq!(rat("5/4").round(), Integer::from(1));
314        assert!([Integer::from(1), Integer::from(2)].contains(&rat("3/2").round()));
315        assert_eq!(rat("7/4").round(), Integer::from(2));
316        assert_eq!(rat("2").round(), Integer::from(2));
317    }
318}