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}