feanor_math/rings/extension/
number_field.rs

1
2use std::alloc::Global;
3
4use extension_impl::FreeAlgebraImplBase;
5use gcd::poly_gcd_local;
6use local::*;
7use hensel::hensel_lift_factorization;
8use sparse::SparseMapVector;
9use squarefree_part::poly_power_decomposition_local;
10
11use crate::algorithms::interpolate::product_except_one;
12use crate::algorithms::poly_factor::finite::poly_factor_finite_field;
13use crate::algorithms::rational_reconstruction::balanced_rational_reconstruction;
14use crate::computation::*;
15use crate::delegate::DelegateRingImplEuclideanRing;
16use crate::specialization::*;
17use crate::algorithms::convolution::*;
18use crate::algorithms::eea::signed_lcm;
19use crate::algorithms::poly_factor::extension::poly_factor_extension;
20use crate::algorithms::poly_gcd::*;
21use crate::MAX_PROBABILISTIC_REPETITIONS;
22use crate::delegate::DelegateRing;
23use crate::integer::*;
24use crate::pid::*;
25use crate::ring::*;
26use crate::rings::field::AsField;
27use crate::rings::poly::*;
28use crate::rings::zn::ZnRingStore;
29use crate::rings::rational::*;
30use crate::divisibility::*;
31use crate::rings::extension::*;
32
33use super::extension_impl::FreeAlgebraImpl;
34use super::Field;
35use super::FreeAlgebra;
36
37///
38/// An algebraic number field, i.e. a finite rank field extension of the rationals.
39/// 
40/// This type only wraps an underlying implementation of the ring arithmetic, and adds
41/// some number-field specific functionality. However, the implementation type defaults to
42/// [`DefaultNumberFieldImpl`], which should be sufficient for almost all purposes.
43/// Note that the only way to create a number field that does not use the default
44/// implementation is via [`NumberFieldBase::create()`].
45/// 
46/// # Example
47/// 
48/// ```
49/// # use feanor_math::assert_el_eq;
50/// # use feanor_math::ring::*;
51/// # use feanor_math::rings::extension::*;
52/// # use feanor_math::rings::extension::number_field::*;
53/// # use feanor_math::rings::poly::*;
54/// # use feanor_math::rings::poly::dense_poly::*;
55/// # use feanor_math::rings::rational::*;
56/// # use feanor_math::integer::*;
57/// let ZZ = BigIntRing::RING;
58/// let ZZX = DensePolyRing::new(ZZ, "X");
59/// let [gen_poly] = ZZX.with_wrapped_indeterminate(|X| [X.pow_ref(2) + 1]);
60/// // the Gaussian numbers `QQ[i]`
61/// let QQi = NumberField::new(&ZZX, &gen_poly);
62/// let i = QQi.canonical_gen();
63/// assert_el_eq!(&QQi, QQi.neg_one(), QQi.pow(i, 2));
64/// ```
65/// So far, we could have done the same with just [`FreeAlgebraImpl`], which indeed
66/// is used as the default implementation of the arithmetic. However, [`NumberField`]
67/// provides additional functionality, that is not available for general extensions.
68/// ```
69/// # use feanor_math::assert_el_eq;
70/// # use feanor_math::ring::*;
71/// # use feanor_math::rings::extension::*;
72/// # use feanor_math::rings::extension::number_field::*;
73/// # use feanor_math::rings::poly::*;
74/// # use feanor_math::rings::poly::dense_poly::*;
75/// # use feanor_math::rings::rational::*;
76/// # use feanor_math::algorithms::poly_factor::*;
77/// # use feanor_math::integer::*;
78/// # let ZZ = BigIntRing::RING;
79/// # let ZZX = DensePolyRing::new(ZZ, "X");
80/// # let [gen_poly] = ZZX.with_wrapped_indeterminate(|X| [X.pow_ref(2) + 1]);
81/// # let QQi = NumberField::new(&ZZX, &gen_poly);
82/// # let i = QQi.canonical_gen();
83/// let QQiX = DensePolyRing::new(&QQi, "X");
84/// let [f] = QQiX.with_wrapped_indeterminate(|X| [X.pow_ref(2) + 4]);
85/// let (factorization, _) = <_ as FactorPolyField>::factor_poly(&QQiX, &f);
86/// assert_eq!(2, factorization.len());
87/// ```
88/// The internal generating polynomial of a number field is currently always
89/// integral, but you can create a number field also from a rational polynomial
90/// using [`NumberField::adjoin_root()`].
91/// ```
92/// # use feanor_math::assert_el_eq;
93/// # use feanor_math::ring::*;
94/// # use feanor_math::homomorphism::*;
95/// # use feanor_math::divisibility::*;
96/// # use feanor_math::rings::extension::*;
97/// # use feanor_math::rings::extension::number_field::*;
98/// # use feanor_math::rings::poly::*;
99/// # use feanor_math::rings::poly::dense_poly::*;
100/// # use feanor_math::rings::rational::*;
101/// # use feanor_math::integer::*;
102/// let ZZ = BigIntRing::RING;
103/// let QQ = RationalField::new(ZZ);
104/// let QQX = DensePolyRing::new(&QQ, "X");
105/// // take `gen_poly = X^2 + 1/4`
106/// let gen_poly = QQX.add(QQX.pow(QQX.indeterminate(), 2), QQX.inclusion().map(QQ.invert(&QQ.int_hom().map(4)).unwrap()));
107/// // this still gives the Gaussian numbers `QQ[i]`
108/// let (QQi, i_half) = NumberField::adjoin_root(&QQX, &gen_poly);
109/// assert_el_eq!(&QQi, QQi.neg_one(), QQi.pow(QQi.int_hom().mul_ref_map(&i_half, &2), 2));
110/// // however the canonical generator might not be `i/2`
111/// assert!(!QQi.eq_el(&QQi.canonical_gen(), &i_half));
112/// ```
113/// 
114/// # Why not relative number fields?
115/// 
116/// Same as [`crate::rings::extension::galois_field::GaloisFieldBase`], this type represents
117/// number fields globally, i.e. always in the form `Q[X]/(f(X))`. By the primitive element
118/// theorem, each number field can be written in this form. However, it might be more natural
119/// in some applications to write it as an extension of a smaller number field, say `L = K[X]/(f(X))`.
120/// 
121/// I tried this before, and it turned out to be a constant fight with the type system.
122/// The final code worked more or less (see git commit b1ef445cf14733f63d035b39314c2dd66fd7fcb5),
123/// but it looks terrible, since we need quite a few "helper" traits to be able to provide all the
124/// expected functionality. Basically, every functionality must now be represented by one (or many)
125/// traits that are implemented by `QQ` and by any extension `K[X]/(f(X))` for which `K` implements 
126/// it. In some cases (like polynomial factorization), we want to have "functorial" functions that
127/// map a number field to something else (e.g. one of its orders), and each of those now requires
128/// a complete parallel hierarchy of traits. If you are not yet frightened, checkout the above
129/// commit and see if you can make sense of the corresponding code.
130/// 
131/// To summarize, all number fields are represented absolutely, i.e. as extensions of `QQ`.
132/// 
133/// # Choice of blanket implementations of [`CanHomFrom`]
134/// 
135/// This is done analogously to [`crate::rings::extension::galois_field::GaloisFieldBase`], see
136/// the description there.
137/// 
138#[stability::unstable(feature = "enable")]
139pub struct NumberFieldBase<Impl, I>
140    where Impl: RingStore,
141        Impl::Type: Field + FreeAlgebra,
142        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
143        I: RingStore,
144        I::Type: IntegerRing
145{
146    base: Impl
147}
148
149#[stability::unstable(feature = "enable")]
150pub type DefaultNumberFieldImpl = AsField<FreeAlgebraImpl<RationalField<BigIntRing>, Vec<El<RationalField<BigIntRing>>>, Global, KaratsubaAlgorithm>>;
151#[stability::unstable(feature = "enable")]
152pub type NumberField<Impl = DefaultNumberFieldImpl, I = BigIntRing> = RingValue<NumberFieldBase<Impl, I>>;
153
154impl NumberField {
155
156    ///
157    /// If the given polynomial is irreducible, returns the number field generated
158    /// by it (with a root of the polynomial as canonical generator). Otherwise,
159    /// `None` is returned.
160    /// 
161    /// If the given polynomial is not integral or not monic, consider using
162    /// [`NumberField::try_adjoin_root()`] instead.
163    /// 
164    #[stability::unstable(feature = "enable")]
165    pub fn try_new<P>(poly_ring: P, generating_poly: &El<P>) -> Option<Self>
166        where P: RingStore,
167            P::Type: PolyRing,
168            <P::Type as RingExtension>::BaseRing: RingStore<Type = BigIntRingBase>
169    {
170        assert!(poly_ring.base_ring().is_one(poly_ring.lc(generating_poly).unwrap()));
171        let QQ = RationalField::new(BigIntRing::RING);
172        let rank = poly_ring.degree(generating_poly).unwrap();
173        let modulus = (0..rank).map(|i| QQ.negate(QQ.inclusion().map_ref(poly_ring.coefficient_at(generating_poly, i)))).collect::<Vec<_>>();
174        return FreeAlgebraImpl::new_with(QQ, rank, modulus, "θ", Global, STANDARD_CONVOLUTION).as_field().ok().map(Self::create);
175    }
176    
177    ///
178    /// Given a monic, integral and irreducible polynomial, returns the number field 
179    /// generated by it (with a root of the polynomial as canonical generator).
180    /// 
181    /// Panics if the polynomial is not irreducible.
182    /// 
183    /// If the given polynomial is not integral or not monic, consider using
184    /// [`NumberField::adjoin_root()`] instead.
185    /// 
186    #[stability::unstable(feature = "enable")]
187    pub fn new<P>(poly_ring: P, generating_poly: &El<P>) -> Self
188        where P: RingStore,
189            P::Type: PolyRing,
190            <P::Type as RingExtension>::BaseRing: RingStore<Type = BigIntRingBase>
191    {
192        Self::try_new(poly_ring, generating_poly).unwrap()
193    }
194
195    ///
196    /// If the given polynopmial is irreducible, computes the number field generated
197    /// by one of its roots, and returns it together with the root (which is not necessarily
198    /// the canonical generator of the number field). Otherwise, `None` is returned.
199    /// 
200    #[stability::unstable(feature = "enable")]
201    pub fn try_adjoin_root<P>(poly_ring: P, generating_poly: &El<P>) -> Option<(Self, El<Self>)>
202        where P: RingStore,
203            P::Type: PolyRing,
204            <P::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<BigIntRing>>
205    {
206        let QQ = poly_ring.base_ring();
207        let ZZ = QQ.base_ring();
208        let denominator = poly_ring.terms(generating_poly).map(|(c, _)| QQ.get_ring().den(c)).fold(
209            ZZ.one(), 
210            |a, b| signed_lcm(a, ZZ.clone_el(b), ZZ)
211        );
212        let rank = poly_ring.degree(generating_poly).unwrap();
213        let scaled_lc = ZZ.checked_div(&ZZ.mul_ref(&denominator, QQ.get_ring().num(poly_ring.lc(generating_poly).unwrap())), QQ.get_ring().den(poly_ring.lc(generating_poly).unwrap())).unwrap();
214        let ZZX = DensePolyRing::new(ZZ, "X");
215        let new_generating_poly = ZZX.from_terms(poly_ring.terms(generating_poly).map(|(c, i)| if i == rank {
216            (ZZ.one(), rank)
217        } else {
218            (ZZ.checked_div(&ZZ.mul_ref_fst(&denominator, ZZ.mul_ref_fst(QQ.get_ring().num(c), ZZ.pow(ZZ.clone_el(&scaled_lc), rank - i - 1))), QQ.get_ring().den(c)).unwrap(), i)
219        }));
220        return Self::try_new(ZZX, &new_generating_poly).map(|res| {
221            let root = res.inclusion().mul_map(res.canonical_gen(), QQ.invert(&QQ.inclusion().map(scaled_lc)).unwrap());
222            return (res, root);
223        });
224    }
225    
226    #[stability::unstable(feature = "enable")]
227    pub fn adjoin_root<P>(poly_ring: P, generating_poly: &El<P>) -> (Self, El<Self>)
228        where P: RingStore,
229            P::Type: PolyRing,
230            <P::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<BigIntRing>>
231    {
232        Self::try_adjoin_root(poly_ring, generating_poly).unwrap()
233    }
234}
235
236impl<Impl, I> NumberField<Impl, I>
237    where Impl: RingStore,
238        Impl::Type: Field + FreeAlgebra,
239        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
240        I: RingStore,
241        I::Type: IntegerRing
242{
243    ///
244    /// Creates a new number field with the given underlying implementation.
245    /// 
246    /// Requires that all coefficients of the generating polynomial are integral.
247    /// 
248    #[stability::unstable(feature = "enable")]
249    pub fn create(implementation: Impl) -> Self {
250        let poly_ring = DensePolyRing::new(implementation.base_ring(), "X");
251        let gen_poly = implementation.generating_poly(&poly_ring, poly_ring.base_ring().identity());
252        assert!(poly_ring.terms(&gen_poly).all(|(c, _)| poly_ring.base_ring().base_ring().is_one(poly_ring.base_ring().get_ring().den(c))));
253        RingValue::from(NumberFieldBase {
254            base: implementation,
255        })
256    }
257}
258
259impl<Impl, I> Clone for NumberFieldBase<Impl, I>
260    where Impl: RingStore + Clone,
261        Impl::Type: Field + FreeAlgebra,
262        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
263        I: RingStore,
264        I::Type: IntegerRing
265{
266    fn clone(&self) -> Self {
267        Self {
268            base: self.base.clone(),
269        }
270    }
271}
272
273impl<Impl, I> Copy for NumberFieldBase<Impl, I>
274    where Impl: RingStore + Copy,
275        Impl::Type: Field + FreeAlgebra,
276        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
277        I: RingStore,
278        I::Type: IntegerRing,
279        El<Impl>: Copy,
280        El<I>: Copy
281{}
282
283impl<Impl, I> PartialEq for NumberFieldBase<Impl, I>
284    where Impl: RingStore,
285        Impl::Type: Field + FreeAlgebra,
286        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
287        I: RingStore,
288        I::Type: IntegerRing
289{
290    fn eq(&self, other: &Self) -> bool {
291        self.base.get_ring() == other.base.get_ring()
292    }
293}
294
295impl<Impl, I> DelegateRing for NumberFieldBase<Impl, I>
296    where Impl: RingStore,
297        Impl::Type: Field + FreeAlgebra,
298        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
299        I: RingStore,
300        I::Type: IntegerRing
301{
302    type Base = Impl::Type;
303    type Element = El<Impl>;
304
305    fn get_delegate(&self) -> &Self::Base {
306        self.base.get_ring()
307    }
308
309    fn delegate(&self, el: Self::Element) -> <Self::Base as RingBase>::Element { el }
310    fn delegate_mut<'a>(&self, el: &'a mut Self::Element) -> &'a mut <Self::Base as RingBase>::Element { el }
311    fn delegate_ref<'a>(&self, el: &'a Self::Element) -> &'a <Self::Base as RingBase>::Element { el }
312    fn rev_delegate(&self, el: <Self::Base as RingBase>::Element) -> Self::Element { el }
313}
314
315impl<Impl, I> DelegateRingImplEuclideanRing for NumberFieldBase<Impl, I>
316    where Impl: RingStore,
317        Impl::Type: Field + FreeAlgebra,
318        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
319        I: RingStore,
320        I::Type: IntegerRing
321{}
322
323impl<Impl, I> FiniteRingSpecializable for NumberFieldBase<Impl, I>
324    where Impl: RingStore,
325        Impl::Type: Field + FreeAlgebra,
326        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
327        I: RingStore,
328        I::Type: IntegerRing
329{
330    fn specialize<O: FiniteRingOperation<Self>>(_op: O) -> Result<O::Output, ()> {
331        Err(())
332    }
333}
334
335impl<Impl, I> Field for NumberFieldBase<Impl, I>
336    where Impl: RingStore,
337        Impl::Type: Field + FreeAlgebra,
338        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
339        I: RingStore,
340        I::Type: IntegerRing
341{}
342
343impl<Impl, I> PerfectField for NumberFieldBase<Impl, I>
344    where Impl: RingStore,
345        Impl::Type: Field + FreeAlgebra,
346        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
347        I: RingStore,
348        I::Type: IntegerRing
349{}
350
351impl<Impl, I> Domain for NumberFieldBase<Impl, I>
352    where Impl: RingStore,
353        Impl::Type: Field + FreeAlgebra,
354        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
355        I: RingStore,
356        I::Type: IntegerRing
357{}
358
359impl<Impl, I> PolyTFracGCDRing for NumberFieldBase<Impl, I>
360    where Impl: RingStore,
361        Impl::Type: Field + FreeAlgebra,
362        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
363        I: RingStore,
364        I::Type: IntegerRing
365{
366    fn gcd<P>(poly_ring: P, lhs: &El<P>, rhs: &El<P>) -> El<P>
367        where P: RingStore + Copy,
368            P::Type: PolyRing + DivisibilityRing,
369            <P::Type as RingExtension>::BaseRing: RingStore<Type = Self>
370    {
371        let self_ = NumberFieldByOrder { base: RingRef::new(poly_ring.base_ring().get_ring()) };
372
373        let order_poly_ring = DensePolyRing::new(RingRef::new(&self_), "X");
374        let lhs_order = self_.scale_poly_to_order(poly_ring, &order_poly_ring, lhs);
375        let rhs_order = self_.scale_poly_to_order(poly_ring, &order_poly_ring, rhs);
376
377        let result = poly_gcd_local(&order_poly_ring, order_poly_ring.clone_el(&lhs_order), order_poly_ring.clone_el(&rhs_order), LogProgress);
378
379        return self_.normalize_map_back_from_order(&order_poly_ring, poly_ring, &result);
380    }
381
382    fn power_decomposition<P>(poly_ring: P, poly: &El<P>) -> Vec<(El<P>, usize)>
383        where P: RingStore + Copy,
384            P::Type: PolyRing + DivisibilityRing,
385            <P::Type as RingExtension>::BaseRing: RingStore<Type = Self> 
386    {
387        let self_ = NumberFieldByOrder { base: RingRef::new(poly_ring.base_ring().get_ring()) };
388        let order_poly_ring = DensePolyRing::new(RingRef::new(&self_), "X");
389        let poly_order = self_.scale_poly_to_order(poly_ring, &order_poly_ring, poly);
390
391        let result = poly_power_decomposition_local(&order_poly_ring, poly_order, LogProgress);
392
393        return result.into_iter().map(|(f, k)| (self_.normalize_map_back_from_order(&order_poly_ring, poly_ring, &f), k)).collect();
394    }
395}
396
397impl<Impl, I> FactorPolyField for NumberFieldBase<Impl, I>
398    where Impl: RingStore,
399        Impl::Type: Field + FreeAlgebra,
400        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
401        I: RingStore,
402        I::Type: IntegerRing
403{
404    fn factor_poly<P>(poly_ring: P, poly: &El<P>) -> (Vec<(El<P>, usize)>, Self::Element)
405        where P: RingStore + Copy,
406            P::Type: PolyRing + EuclideanRing,
407            <P::Type as RingExtension>::BaseRing: RingStore<Type = Self>
408    {
409        let self_ = NumberFieldByOrder { base: RingRef::new(poly_ring.base_ring().get_ring()) };
410        let order_poly_ring = DensePolyRing::new(RingRef::new(&self_), "X");
411        let poly_order = self_.scale_poly_to_order(poly_ring, &order_poly_ring, poly);
412
413        let mut result = Vec::new();
414        for (irred_factor, e) in poly_factor_extension(&poly_ring, &self_.normalize_map_back_from_order(&order_poly_ring, poly_ring, &poly_order)).0 {
415            result.push((irred_factor, e));
416        }
417        return (result, self_.clone_el(poly_ring.lc(poly).unwrap()));
418    }
419}
420
421///
422/// Implements [`PolyGCDLocallyDomain`] for [`NumberField`].
423/// 
424/// We don't want to expose the interface of [`PolyGCDLocallyDomain`] for number
425/// fields generally, thus use a private newtype.
426/// 
427struct NumberFieldByOrder<'a, Impl, I>
428    where Impl: RingStore,
429        Impl::Type: Field + FreeAlgebra,
430        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
431        I: RingStore,
432        I::Type: IntegerRing
433{
434    base: RingRef<'a, NumberFieldBase<Impl, I>>
435}
436
437impl<'a, Impl, I> NumberFieldByOrder<'a, Impl, I>
438    where Impl: RingStore,
439        Impl::Type: Field + FreeAlgebra,
440        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
441        I: RingStore,
442        I::Type: IntegerRing
443{
444    fn scale_poly_to_order<'ring, P1, P2>(&self, from: P1, to: P2, poly: &El<P1>) -> El<P2>
445        where P1: RingStore,
446            P1::Type: PolyRing,
447            <P1::Type as RingExtension>::BaseRing: RingStore<Type = NumberFieldBase<Impl, I>>,
448            P2: RingStore,
449            P2::Type: PolyRing,
450            <P2::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
451            Self: 'ring
452    {
453        debug_assert!(self.base.get_ring() == from.base_ring().get_ring());
454        debug_assert!(self.base.get_ring() == to.base_ring().get_ring().base.get_ring());
455        let QQ = self.base.base_ring();
456        let ZZ = QQ.base_ring();
457        let denominator = QQ.inclusion().map(from.terms(poly).map(|(c, _)| 
458            self.base.wrt_canonical_basis(c).iter().map(|c| ZZ.clone_el(QQ.get_ring().den(&c))).fold(ZZ.one(), |a, b| signed_lcm(a, b, ZZ))
459        ).fold(ZZ.one(), |a, b| signed_lcm(a, b, ZZ)));
460        debug_assert!(!QQ.is_zero(&denominator));
461        return to.from_terms(from.terms(poly).map(|(c, i)| (self.base.inclusion().mul_ref_map(c, &denominator), i)));
462    }
463
464    fn normalize_map_back_from_order<'ring, P1, P2>(&self, from: P1, to: P2, poly: &El<P1>) -> El<P2>
465        where P1: RingStore,
466            P1::Type: PolyRing,
467            <P1::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
468            P2: RingStore,
469            P2::Type: PolyRing,
470            <P2::Type as RingExtension>::BaseRing: RingStore<Type = NumberFieldBase<Impl, I>>,
471            Self: 'ring
472    {
473        debug_assert!(self.base.get_ring() == to.base_ring().get_ring());
474        debug_assert!(self.base.get_ring() == from.base_ring().get_ring().base.get_ring());
475        let result = to.from_terms(from.terms(poly).map(|(c, i)| (self.clone_el(c), i)));
476        return to.normalize(result);
477    }
478}
479
480impl<'a, Impl, I> PartialEq for NumberFieldByOrder<'a, Impl, I>
481    where Impl: RingStore,
482        Impl::Type: Field + FreeAlgebra,
483        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
484        I: RingStore,
485        I::Type: IntegerRing
486{
487    fn eq(&self, other: &Self) -> bool {
488        self.base.get_ring() == other.base.get_ring()
489    }
490}
491
492impl<'a, Impl, I> FiniteRingSpecializable for NumberFieldByOrder<'a, Impl, I>
493    where Impl: RingStore,
494        Impl::Type: Field + FreeAlgebra,
495        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
496        I: RingStore,
497        I::Type: IntegerRing
498{
499    fn specialize<O: FiniteRingOperation<Self>>(_op: O) -> Result<O::Output, ()> {
500        Err(())
501    }
502}
503
504impl<'a, Impl, I> DelegateRing for NumberFieldByOrder<'a, Impl, I>
505    where Impl: RingStore,
506        Impl::Type: Field + FreeAlgebra,
507        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
508        I: RingStore,
509        I::Type: IntegerRing
510{
511    type Base = Impl::Type;
512    type Element = El<Impl>;
513
514    fn get_delegate(&self) -> &Self::Base {
515        self.base.get_ring().base.get_ring()
516    }
517
518    fn delegate(&self, el: Self::Element) -> <Self::Base as RingBase>::Element { el }
519    fn delegate_mut<'b>(&self, el: &'b mut Self::Element) -> &'b mut <Self::Base as RingBase>::Element { el }
520    fn delegate_ref<'b>(&self, el: &'b Self::Element) -> &'b <Self::Base as RingBase>::Element { el }
521    fn rev_delegate(&self, el: <Self::Base as RingBase>::Element) -> Self::Element { el }
522}
523
524impl<'a, Impl, I> Domain for NumberFieldByOrder<'a, Impl, I>
525    where Impl: RingStore,
526        Impl::Type: Field + FreeAlgebra,
527        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
528        I: RingStore,
529        I::Type: IntegerRing
530{}
531
532type LocalRing<'ring, I> = <<I as RingStore>::Type as PolyGCDLocallyDomain>::LocalRing<'ring>;
533type LocalField<'ring, I> = <<I as RingStore>::Type as PolyGCDLocallyDomain>::LocalField<'ring>;
534
535pub struct NumberRingIdeal<'ring, I>
536    where I: RingStore,
537        I::Type: IntegerRing,
538        I: 'ring
539{
540    prime: <I::Type as PolyGCDLocallyDomain>::SuitableIdeal<'ring>,
541    ZZX: DensePolyRing<&'ring I>,
542    number_field_poly: El<DensePolyRing<&'ring I>>,
543    FpX: DensePolyRing<<I::Type as PolyGCDLocallyDomain>::LocalField<'ring>>,
544    Fp_as_ring: <I::Type as PolyGCDLocallyDomain>::LocalRing<'ring>,
545    minpoly_factors_mod_p: Vec<El<DensePolyRing<<I::Type as PolyGCDLocallyDomain>::LocalField<'ring>>>>
546}
547
548impl<'ring, I> NumberRingIdeal<'ring, I>
549    where I: RingStore,
550        I::Type: IntegerRing,
551        I: 'ring
552{
553    fn lifted_factorization<'a>(&'a self, e: usize) -> (DensePolyRing<<I::Type as PolyGCDLocallyDomain>::LocalRing<'ring>>, Vec<El<DensePolyRing<<I::Type as PolyGCDLocallyDomain>::LocalRing<'ring>>>>) {
554        let ZZX = &self.ZZX;
555        let ZZ = ZZX.base_ring();
556        let ZpeX = DensePolyRing::new(ZZ.get_ring().local_ring_at(&self.prime, e, 0), "X");
557        let Zpe = ZpeX.base_ring();
558        let FpX = &self.FpX;
559        let Zpe_to_Fp = PolyGCDLocallyIntermediateReductionMap::new(ZZ.get_ring(), &self.prime, Zpe, e, &self.Fp_as_ring, 1, 0);
560        let ZZ_to_Zpe = PolyGCDLocallyReductionMap::new(ZZ.get_ring(), &self.prime, &Zpe, e, 0);
561
562        let factors = hensel_lift_factorization(
563            &Zpe_to_Fp,
564            &ZpeX,
565            FpX,
566            &ZpeX.lifted_hom(ZZX, ZZ_to_Zpe).map_ref(&self.number_field_poly),
567            &self.minpoly_factors_mod_p[..],
568            DontObserve
569        );
570        
571        return (ZpeX, factors);
572    }
573}
574
575impl<'a, Impl, I> PolyGCDLocallyDomain for NumberFieldByOrder<'a, Impl, I>
576    where Impl: RingStore,
577        Impl::Type: Field + FreeAlgebra,
578        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
579        I: RingStore,
580        I::Type: IntegerRing
581{
582    type LocalRingBase<'ring> = FreeAlgebraImplBase<
583        LocalRing<'ring, I>, 
584        SparseMapVector<LocalRing<'ring, I>>
585    >
586        where Self: 'ring;
587
588    type LocalRing<'ring> = RingValue<Self::LocalRingBase<'ring>>
589        where Self: 'ring;
590
591    type LocalFieldBase<'ring> = AsFieldBase<FreeAlgebraImpl<
592        LocalField<'ring, I>, 
593        SparseMapVector<LocalField<'ring, I>>
594    >>
595        where Self: 'ring;
596
597    type LocalField<'ring> = RingValue<Self::LocalFieldBase<'ring>>
598        where Self: 'ring;
599
600    type SuitableIdeal<'ring> = NumberRingIdeal<'ring, I>
601        where Self: 'ring;
602
603    fn maximal_ideal_factor_count<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>) -> usize
604        where Self: 'ring
605    {
606        ideal.minpoly_factors_mod_p.len()
607    }
608
609    fn heuristic_exponent<'ring, 'b, J>(&self, ideal: &Self::SuitableIdeal<'ring>, poly_deg: usize, coefficients: J) -> usize
610        where J: Iterator<Item = &'b Self::Element>,
611            Self: 'b,
612            Self: 'ring
613    {
614        const HEURISTIC_FACTOR_SIZE_OVER_POLY_SIZE_FACTOR: f64 = 0.25;
615
616        let QQ = self.base.base_ring();
617        let ZZ = QQ.base_ring();
618        // to give any mathematically justifiable value, we would probably have to consider the canonical norm;
619        // I don't want to deal with this here, so let's just use the coefficient norm instead...
620        let log2_max_coeff = coefficients.map(|c| self.base.wrt_canonical_basis(c).iter().map(|c| ZZ.abs_log2_ceil(QQ.get_ring().num(&c)).unwrap_or(0)).max().unwrap()).max().unwrap_or(0);
621        let log2_p = (ZZ.get_ring().principal_ideal_generator(&ideal.prime) as f64).log2();
622        return ((log2_max_coeff as f64 + poly_deg as f64 + (self.rank() as f64).log2()) / log2_p * HEURISTIC_FACTOR_SIZE_OVER_POLY_SIZE_FACTOR).ceil() as usize + 1;
623    }
624
625    fn random_suitable_ideal<'ring, F>(&'ring self, mut rng: F) -> Self::SuitableIdeal<'ring>
626        where F: FnMut() -> u64
627    {
628        let QQ = self.base.base_ring();
629        let ZZ = QQ.base_ring();
630        let ZZX = DensePolyRing::new(ZZ, "X");
631        let gen_poly = self.base.generating_poly(&ZZX, LambdaHom::new(QQ, ZZ, |QQ, ZZ, x| {
632            assert!(ZZ.is_one(QQ.get_ring().den(&x)));
633            ZZ.clone_el(QQ.get_ring().num(&x))
634        }));
635
636        // search for a prime `p` such that the minimal polynomial is unramified modulo `p`
637        for _ in 0..MAX_PROBABILISTIC_REPETITIONS {
638            let p = ZZ.get_ring().random_suitable_ideal(&mut rng);
639            assert_eq!(1, ZZ.get_ring().maximal_ideal_factor_count(&p));
640
641            let Fp_as_ring = ZZ.get_ring().local_ring_at(&p, 1, 0);
642            let FpX = DensePolyRing::new(ZZ.get_ring().local_field_at(&p, 0), "X");
643            let Fp = FpX.base_ring();
644            let ZZ_to_Fp = Fp.can_hom(&Fp_as_ring).unwrap().compose(PolyGCDLocallyReductionMap::new(ZZ.get_ring(), &p, &Fp_as_ring, 1, 0));
645
646            let gen_poly_mod_p = FpX.from_terms(ZZX.terms(&gen_poly).map(|(c, i)| (ZZ_to_Fp.map_ref(c), i)));
647            let (factorization, _) = poly_factor_finite_field(&FpX, &gen_poly_mod_p);
648            if factorization.iter().all(|(_, e)| *e == 1) {
649
650                return NumberRingIdeal {
651                    minpoly_factors_mod_p: factorization.into_iter().map(|(f, _)| f).collect(),
652                    number_field_poly: gen_poly,
653                    FpX: FpX,
654                    ZZX: ZZX,
655                    Fp_as_ring: Fp_as_ring,
656                    prime: p
657                };
658            }
659        }
660        unreachable!()
661    }
662
663    fn local_field_at<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, idx: usize) -> Self::LocalField<'ring>
664        where Self: 'ring
665    {
666        assert!(idx < self.maximal_ideal_factor_count(ideal));
667        let QQ = self.base.base_ring();
668        let ZZ = QQ.base_ring();
669        let Fp = ZZ.get_ring().local_field_at(&ideal.prime, 0);
670        let FpX = &ideal.FpX;
671        assert!(Fp.get_ring() == FpX.base_ring().get_ring());
672
673        let irred_poly = &ideal.minpoly_factors_mod_p[idx];
674        let mut x_pow_rank = SparseMapVector::new(FpX.degree(irred_poly).unwrap(), ZZ.get_ring().local_field_at(&ideal.prime, 0));
675        for (c, i) in FpX.terms(irred_poly) {
676            if i < x_pow_rank.len() {
677                *x_pow_rank.at_mut(i) = Fp.negate(Fp.clone_el(c));
678            }
679        }
680        _ = x_pow_rank.at_mut(0);
681        return AsField::from(AsFieldBase::promise_is_perfect_field(FreeAlgebraImpl::new(Fp, FpX.degree(irred_poly).unwrap(), x_pow_rank)));
682    }
683
684    fn local_ring_at<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, e: usize, idx: usize) -> Self::LocalRing<'ring>
685        where Self: 'ring
686    {
687        assert!(idx < self.maximal_ideal_factor_count(ideal));
688        let QQ = self.base.base_ring();
689        let ZZ = QQ.base_ring();
690        let (ZpeX, factors) = ideal.lifted_factorization(e);
691        let Zpe = ZpeX.base_ring();
692
693        let irred_poly = &factors[idx];
694        let degree = ZpeX.degree(irred_poly).unwrap();
695        let mut x_pow_rank = SparseMapVector::new(degree, ZZ.get_ring().local_ring_at(&ideal.prime, e, 0));
696        for (c, i) in ZpeX.terms(irred_poly) {
697            if i < x_pow_rank.len() {
698                *x_pow_rank.at_mut(i) = Zpe.negate(Zpe.clone_el(c));
699            }
700        }
701        _ = x_pow_rank.at_mut(0);
702        return FreeAlgebraImpl::new(ZZ.get_ring().local_ring_at(&ideal.prime, e, 0), degree, x_pow_rank);
703    }
704
705    fn reduce_ring_el<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, to: (&Self::LocalRing<'ring>, usize), idx: usize, x: Self::Element) -> El<Self::LocalRing<'ring>>
706        where Self: 'ring
707    {
708        assert!(idx < self.maximal_ideal_factor_count(ideal));
709        let QQ = self.base.base_ring();
710        let ZZ = QQ.base_ring();
711        let ZZX = &ideal.ZZX;
712        let partial_QQ_to_ZZ = LambdaHom::new(QQ, ZZ, |QQ, ZZ, x| {
713            assert!(ZZ.is_one(QQ.get_ring().den(&x)));
714            ZZ.clone_el(QQ.get_ring().num(&x))
715        });
716        let ZZ_to_Zpe = PolyGCDLocallyReductionMap::new(ZZ.get_ring(), &ideal.prime, to.0.base_ring(), to.1, 0);
717
718        ZZX.evaluate(
719            &self.base.poly_repr(ZZX, &x, partial_QQ_to_ZZ), 
720            &to.0.canonical_gen(), 
721            to.0.inclusion().compose(ZZ_to_Zpe)
722        )
723    }
724
725    fn reduce_partial<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, from: (&Self::LocalRing<'ring>, usize), to: (&Self::LocalRing<'ring>, usize), idx: usize, x: El<Self::LocalRing<'ring>>) -> El<Self::LocalRing<'ring>>
726        where Self: 'ring
727    {
728        assert!(idx < self.maximal_ideal_factor_count(ideal));
729        let QQ = self.base.base_ring();
730        let ZZ = QQ.base_ring();
731        to.0.from_canonical_basis(from.0.wrt_canonical_basis(&x).iter().map(|c| ZZ.get_ring().reduce_partial(&ideal.prime, (from.0.base_ring(), from.1), (to.0.base_ring(), to.1), 0, c)))
732    }
733
734    fn lift_partial<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, from: (&Self::LocalRing<'ring>, usize), to: (&Self::LocalRing<'ring>, usize), idx: usize, x: El<Self::LocalRing<'ring>>) -> El<Self::LocalRing<'ring>>
735        where Self: 'ring
736    {
737        assert!(idx < self.maximal_ideal_factor_count(ideal));
738        let QQ = self.base.base_ring();
739        let ZZ = QQ.base_ring();
740        to.0.from_canonical_basis(from.0.wrt_canonical_basis(&x).iter().map(|c| ZZ.get_ring().lift_partial(&ideal.prime, (from.0.base_ring(), from.1), (to.0.base_ring(), to.1), 0, c)))
741    }
742
743    fn reconstruct_ring_el<'local, 'element, 'ring, V1, V2>(&self, ideal: &Self::SuitableIdeal<'ring>, from: V1, e: usize, x: V2) -> Self::Element
744        where Self: 'ring,
745            V1: VectorFn<&'local Self::LocalRing<'ring>>,
746            V2: VectorFn<&'element El<Self::LocalRing<'ring>>>,
747            Self::LocalRing<'ring>: 'local,
748            El<Self::LocalRing<'ring>>: 'element,
749            'ring: 'local + 'element
750    {
751        assert_eq!(self.maximal_ideal_factor_count(ideal), from.len());
752        assert_eq!(self.maximal_ideal_factor_count(ideal), x.len());
753        let QQ = self.base.base_ring();
754        let ZZ = QQ.base_ring();
755        let Zpe = from.at(0).base_ring();
756        assert!(from.iter().all(|ring| ring.base_ring().get_ring() == Zpe.get_ring()));
757        let ZpeX = DensePolyRing::new(Zpe, "X");
758        let ZZ_to_Zpe = PolyGCDLocallyReductionMap::new(ZZ.get_ring(), &ideal.prime, Zpe, e, 0);
759
760        // compute data necessary for inverse CRT
761        let mut unit_vectors = (0..self.maximal_ideal_factor_count(ideal)).map(|_| ZpeX.zero()).collect::<Vec<_>>();
762        product_except_one(&ZpeX, (&from).map_fn(|galois_ring| galois_ring.generating_poly(&ZpeX, Zpe.identity())), &mut unit_vectors);
763        let complete_product = ZpeX.mul_ref_fst(&unit_vectors[0], from.at(0).generating_poly(&ZpeX, Zpe.identity()));
764        assert_el_eq!(&ZpeX, &complete_product, &self.base.generating_poly(&ZpeX, ZZ_to_Zpe.compose(LambdaHom::new(QQ, ZZ, |QQ, ZZ, x| {
765            assert!(ZZ.is_one(QQ.get_ring().den(&x)));
766            ZZ.clone_el(QQ.get_ring().num(&x))
767        }))));
768
769        for i in 0..self.maximal_ideal_factor_count(ideal) {
770            let galois_ring = from.at(i);
771            let inv_normalization_factor = ZpeX.evaluate(unit_vectors.at(i), &galois_ring.canonical_gen(), galois_ring.inclusion());
772            let normalization_factor = galois_ring.invert(&inv_normalization_factor).unwrap();
773            let lifted_normalization_factor = galois_ring.poly_repr(&ZpeX, &normalization_factor, Zpe.identity());
774            let unreduced_new_unit_vector = ZpeX.mul(std::mem::replace(&mut unit_vectors[i], ZpeX.zero()), lifted_normalization_factor);
775            unit_vectors[i] = ZpeX.div_rem_monic(unreduced_new_unit_vector, &complete_product).1;
776        }
777
778        // now apply inverse CRT to get the value over ZpeX
779        let combined = <_ as RingStore>::sum(&ZpeX, (0..self.maximal_ideal_factor_count(ideal)).map(|i| {
780            let galois_ring = from.at(i);
781            let unreduced_result = ZpeX.mul_ref_snd(galois_ring.poly_repr(&ZpeX, x.at(i), Zpe.identity()), &unit_vectors[i]);
782            ZpeX.div_rem_monic(unreduced_result, &complete_product).1
783        }));
784
785        for i in 0..self.maximal_ideal_factor_count(ideal) {
786            let galois_ring = from.at(i);
787            debug_assert!(galois_ring.eq_el(x.at(i), &ZpeX.evaluate(&combined, &galois_ring.canonical_gen(), galois_ring.inclusion())));
788        }
789
790        // now lift the polynomial modulo `p^e` to the rationals
791        let Zpe_as_zn = ZZ.get_ring().local_ring_as_zn(&Zpe);
792        let Zpe_to_as_zn = Zpe_as_zn.can_hom(Zpe).unwrap();
793        let result = self.from_canonical_basis((0..self.rank()).map(|i| {
794            let (num, den) = balanced_rational_reconstruction(Zpe_as_zn, Zpe_to_as_zn.map_ref(ZpeX.coefficient_at(&combined, i)));
795            return QQ.div(&QQ.inclusion().map(int_cast(num, ZZ, Zpe_as_zn.integer_ring())), &QQ.inclusion().map(int_cast(den, ZZ, Zpe_as_zn.integer_ring())));
796        }));
797        return result;
798    }
799
800    fn dbg_ideal<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, out: &mut std::fmt::Formatter) -> std::fmt::Result
801        where Self: 'ring
802    {
803        let QQ = self.base.base_ring();
804        QQ.base_ring().get_ring().dbg_ideal(&ideal.prime, out)
805    }
806}
807
808#[cfg(test)]
809use crate::RANDOM_TEST_INSTANCE_COUNT;
810#[cfg(test)]
811use crate::iters::multi_cartesian_product;
812
813#[test]
814fn test_principal_ideal_ring_axioms() {
815    let ZZ = BigIntRing::RING;
816    let ZZX = DensePolyRing::new(ZZ, "X");
817
818    let [f] = ZZX.with_wrapped_indeterminate(|X| [X.pow_ref(2) + 1]);
819    let K = NumberField::new(&ZZX, &f);
820
821    let elements = multi_cartesian_product([(-4..4), (-2..2)].into_iter(), |slice| K.from_canonical_basis(slice.iter().map(|x| K.base_ring().int_hom().map(*x))), |_, x| *x).collect::<Vec<_>>();
822
823    crate::pid::generic_tests::test_principal_ideal_ring_axioms(&K, elements.iter().map(|x| K.clone_el(x)));
824}
825
826#[test]
827fn test_adjoin_root() {
828    let ZZ = BigIntRing::RING;
829    let QQ = RationalField::new(ZZ);
830    let QQX = DensePolyRing::new(QQ, "X");
831    let [f] = QQX.with_wrapped_indeterminate(|X| [2 * X.pow_ref(3) - 1]);
832    let (K, a) = NumberField::adjoin_root(&QQX, &f);
833    assert_el_eq!(&K, K.zero(), K.sub(K.mul(K.int_hom().map(2), K.pow(a, 3)), K.one()));
834}
835
836#[test]
837fn test_poly_gcd_number_field() {
838    let ZZ = BigIntRing::RING;
839    let ZZX = DensePolyRing::new(ZZ, "X");
840
841    let [f] = ZZX.with_wrapped_indeterminate(|X| [X.pow_ref(2) + 1]);
842    let K = NumberField::new(&ZZX, &f);
843    let KY = DensePolyRing::new(&K, "Y");
844
845    let i = RingElementWrapper::new(&KY, KY.inclusion().map(K.canonical_gen()));
846    let [g, h, expected] = KY.with_wrapped_indeterminate(|Y| [
847        (Y.pow_ref(3) + 1) * (Y - &i),
848        (Y.pow_ref(4) + 2) * (Y.pow_ref(2) + 1),
849        Y - i
850    ]);
851    assert_el_eq!(&KY, &expected, <_ as PolyTFracGCDRing>::gcd(&KY, &g, &h));
852
853    let [f] = ZZX.with_wrapped_indeterminate(|X| [X.pow_ref(4) - 20 * X.pow_ref(2) + 16]);
854    let K = NumberField::new(&ZZX, &f);
855    let KY = DensePolyRing::new(&K, "Y");
856
857    let [sqrt3, sqrt7] = K.with_wrapped_generator(|a| [a.pow_ref(3) / 8 - 2 * a, a.pow_ref(3) / 8 - 3 * a]);
858    assert_el_eq!(&K, K.int_hom().map(3), K.pow(K.clone_el(&sqrt3), 2));
859    assert_el_eq!(&K, K.int_hom().map(7), K.pow(K.clone_el(&sqrt7), 2));
860
861    let half = RingElementWrapper::new(&KY, KY.inclusion().map(K.invert(&K.int_hom().map(2)).unwrap()));
862    let sqrt3 = RingElementWrapper::new(&KY, KY.inclusion().map(sqrt3));
863    let sqrt7 = RingElementWrapper::new(&KY, KY.inclusion().map(sqrt7));
864    let [g, h, expected] = KY.with_wrapped_indeterminate(|Y| [
865        Y.pow_ref(2) - &sqrt3 * Y - 1,
866        Y.pow_ref(2) + &sqrt7 * Y + 1,
867        Y - (sqrt3 - sqrt7) * half
868    ]);
869    let actual = <_ as PolyTFracGCDRing>::gcd(&KY, &g, &h);
870    assert_el_eq!(&KY, &expected, &actual);
871}
872
873#[test]
874#[ignore]
875fn random_test_poly_gcd_number_field() {
876    let ZZ = BigIntRing::RING;
877    let QQ = RationalField::new(ZZ);
878    let ZZX = DensePolyRing::new(ZZ, "X");
879    let mut rng = oorandom::Rand64::new(1);
880    let bound = QQ.base_ring().int_hom().map(1000);
881    let rank = 6;
882
883    for _ in 0..RANDOM_TEST_INSTANCE_COUNT {
884        let genpoly = ZZX.from_terms((0..rank).map(|i| (ZZ.get_uniformly_random(&bound, || rng.rand_u64()), i)).chain([(ZZ.one(), rank)].into_iter()));
885
886        let K = NumberField::new(&ZZX, &genpoly);
887        let KY = DensePolyRing::new(&K, "Y");
888
889        let mut random_element_K = || K.from_canonical_basis((0..6).map(|_| QQ.inclusion().map(QQ.base_ring().get_uniformly_random(&bound, || rng.rand_u64()))));
890        let f = KY.from_terms((0..=5).map(|i| (random_element_K(), i)));
891        let g = KY.from_terms((0..=5).map(|i| (random_element_K(), i)));
892        let h = KY.from_terms((0..=4).map(|i| (random_element_K(), i)));
893        // println!("Testing gcd on ({}) * ({}) and ({}) * ({})", poly_ring.format(&f), poly_ring.format(&h), poly_ring.format(&g), poly_ring.format(&h));
894        let lhs = KY.mul_ref(&f, &h);
895        let rhs = KY.mul_ref(&g, &h);
896
897        let gcd = <_ as PolyTFracGCDRing>::gcd(&KY, &lhs, &rhs);
898        // println!("Result {}", poly_ring.format(&gcd));
899
900        assert!(KY.divides(&lhs, &gcd));
901        assert!(KY.divides(&rhs, &gcd));
902        assert!(KY.divides(&gcd, &h));
903    }
904}