feanor_math/rings/extension/
number_field.rs

1use std::fmt::{Debug, Formatter};
2use std::alloc::Global;
3use std::marker::PhantomData;
4
5use crate::algorithms::interpolate::product_except_one;
6use crate::algorithms::newton::{self, absolute_error_of_poly_eval};
7use crate::algorithms::poly_factor::extension::poly_factor_extension;
8use crate::algorithms::poly_factor::factor_locally::{factor_and_lift_mod_pe, FactorAndLiftModpeResult};
9use crate::algorithms::poly_gcd::squarefree_part::poly_power_decomposition_local;
10use crate::algorithms::poly_gcd::gcd::poly_gcd_local;
11use crate::algorithms::resultant::ComputeResultantRing;
12use crate::reduce_lift::poly_factor_gcd::*;
13use crate::rings::extension::number_field::newton::find_approximate_complex_root;
14use crate::algorithms::rational_reconstruction::balanced_rational_reconstruction;
15use crate::computation::*;
16use crate::delegate::*;
17use crate::specialization::*;
18use crate::algorithms::convolution::*;
19use crate::algorithms::eea::signed_lcm;
20use crate::algorithms::poly_gcd::*;
21use crate::MAX_PROBABILISTIC_REPETITIONS;
22use crate::integer::*;
23use crate::pid::*;
24use crate::ring::*;
25use crate::rings::field::AsField;
26use crate::rings::poly::*;
27use crate::rings::zn::ZnRingStore;
28use crate::rings::rational::*;
29use crate::divisibility::*;
30use crate::rings::extension::*;
31use crate::rings::extension::extension_impl::*;
32use crate::rings::float_complex::{Complex64Base, Complex64};
33use crate::serialization::*;
34use crate::rings::extension::sparse::SparseMapVector;
35
36use feanor_serde::newtype_struct::*;
37use serde::{Serialize, Deserialize, Serializer, Deserializer};
38use serde::de::DeserializeSeed;
39
40use super::extension_impl::FreeAlgebraImpl;
41use super::Field;
42use super::FreeAlgebra;
43
44const TRY_FIND_INERT_PRIME_ATTEMPTS: usize = 10;
45const TRY_FACTOR_DIRECTLY_ATTEMPTS: usize = 5;
46
47///
48/// An algebraic number field, i.e. a finite rank field extension of the rationals.
49/// 
50/// This type only wraps an underlying implementation of the ring arithmetic, and adds
51/// some number-field specific functionality. However, the implementation type defaults to
52/// [`DefaultNumberFieldImpl`], which should be sufficient for almost all purposes.
53/// Note that the only way to create a number field that does not use the default
54/// implementation is via [`NumberFieldBase::create()`].
55/// 
56/// # Example
57/// 
58/// ```rust
59/// # use feanor_math::assert_el_eq;
60/// # use feanor_math::ring::*;
61/// # use feanor_math::rings::extension::*;
62/// # use feanor_math::rings::extension::number_field::*;
63/// # use feanor_math::rings::poly::*;
64/// # use feanor_math::rings::poly::dense_poly::*;
65/// # use feanor_math::rings::rational::*;
66/// # use feanor_math::integer::*;
67/// let ZZ = BigIntRing::RING;
68/// let ZZX = DensePolyRing::new(ZZ, "X");
69/// let [gen_poly] = ZZX.with_wrapped_indeterminate(|X| [X.pow_ref(2) + 1]);
70/// // the Gaussian numbers `QQ[i]`
71/// let QQi = NumberField::new(&ZZX, &gen_poly);
72/// let i = QQi.canonical_gen();
73/// assert_el_eq!(&QQi, QQi.neg_one(), QQi.pow(i, 2));
74/// ```
75/// So far, we could have done the same with just [`FreeAlgebraImpl`], which indeed
76/// is used as the default implementation of the arithmetic. However, [`NumberField`]
77/// provides additional functionality, that is not available for general extensions.
78/// ```rust
79/// # use feanor_math::assert_el_eq;
80/// # use feanor_math::ring::*;
81/// # use feanor_math::rings::extension::*;
82/// # use feanor_math::rings::extension::number_field::*;
83/// # use feanor_math::rings::poly::*;
84/// # use feanor_math::rings::poly::dense_poly::*;
85/// # use feanor_math::rings::rational::*;
86/// # use feanor_math::algorithms::poly_factor::*;
87/// # use feanor_math::integer::*;
88/// # let ZZ = BigIntRing::RING;
89/// # let ZZX = DensePolyRing::new(ZZ, "X");
90/// # let [gen_poly] = ZZX.with_wrapped_indeterminate(|X| [X.pow_ref(2) + 1]);
91/// # let QQi = NumberField::new(&ZZX, &gen_poly);
92/// # let i = QQi.canonical_gen();
93/// let QQiX = DensePolyRing::new(&QQi, "X");
94/// let [f] = QQiX.with_wrapped_indeterminate(|X| [X.pow_ref(2) + 4]);
95/// let (factorization, _) = <_ as FactorPolyField>::factor_poly(&QQiX, &f);
96/// assert_eq!(2, factorization.len());
97/// ```
98/// The internal generating polynomial of a number field is currently always
99/// integral, but you can create a number field also from a rational polynomial
100/// using [`NumberField::adjoin_root()`].
101/// ```rust
102/// # use feanor_math::assert_el_eq;
103/// # use feanor_math::ring::*;
104/// # use feanor_math::homomorphism::*;
105/// # use feanor_math::divisibility::*;
106/// # use feanor_math::rings::extension::*;
107/// # use feanor_math::rings::extension::number_field::*;
108/// # use feanor_math::rings::poly::*;
109/// # use feanor_math::rings::poly::dense_poly::*;
110/// # use feanor_math::rings::rational::*;
111/// # use feanor_math::integer::*;
112/// let ZZ = BigIntRing::RING;
113/// let QQ = RationalField::new(ZZ);
114/// let QQX = DensePolyRing::new(&QQ, "X");
115/// // take `gen_poly = X^2 + 1/4`
116/// let gen_poly = QQX.add(QQX.pow(QQX.indeterminate(), 2), QQX.inclusion().map(QQ.invert(&QQ.int_hom().map(4)).unwrap()));
117/// // this still gives the Gaussian numbers `QQ[i]`
118/// let (QQi, i_half) = NumberField::adjoin_root(&QQX, &gen_poly);
119/// assert_el_eq!(&QQi, QQi.neg_one(), QQi.pow(QQi.int_hom().mul_ref_map(&i_half, &2), 2));
120/// // however the canonical generator might not be `i/2`
121/// assert!(!QQi.eq_el(&QQi.canonical_gen(), &i_half));
122/// ```
123/// 
124/// # Why not relative number fields?
125/// 
126/// Same as [`crate::rings::extension::galois_field::GaloisFieldBase`], this type represents
127/// number fields globally, i.e. always in the form `Q[X]/(f(X))`. By the primitive element
128/// theorem, each number field can be written in this form. However, it might be more natural
129/// in some applications to write it as an extension of a smaller number field, say `L = K[X]/(f(X))`.
130/// 
131/// I tried this before, and it turned out to be a constant fight with the type system.
132/// The final code worked more or less (see git commit b1ef445cf14733f63d035b39314c2dd66fd7fcb5),
133/// but it looks terrible, since we need quite a few "helper" traits to be able to provide all the
134/// expected functionality. Basically, every functionality must now be represented by one (or many)
135/// traits that are implemented by `QQ` and by any extension `K[X]/(f(X))` for which `K` implements 
136/// it. In some cases (like polynomial factorization), we want to have "functorial" functions that
137/// map a number field to something else (e.g. one of its orders), and each of those now requires
138/// a complete parallel hierarchy of traits. If you are not yet frightened, checkout the above
139/// commit and see if you can make sense of the corresponding code.
140/// 
141/// To summarize, all number fields are represented absolutely, i.e. as extensions of `QQ`.
142/// 
143/// # Factoring out denominators
144/// 
145/// TODO: At next breaking release, investigate whether it is sensible to have `Impl` be an
146/// algebraic extension of `Z` instead of `Q`, and store the joint denominator once for every
147/// element.
148/// 
149/// # Choice of blanket implementations of [`CanHomFrom`]
150/// 
151/// This is done analogously to [`crate::rings::extension::galois_field::GaloisFieldBase`], see
152/// the description there.
153/// 
154#[stability::unstable(feature = "enable")]
155pub struct NumberFieldBase<Impl, I>
156    where Impl: RingStore,
157        Impl::Type: Field + FreeAlgebra,
158        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
159        I: RingStore,
160        I::Type: IntegerRing
161{
162    base: Impl
163}
164
165///
166/// An embedding of a number field `K` into the complex numbers `CC`, represented
167/// approximately via floating point numbers.
168/// 
169#[stability::unstable(feature = "enable")]
170pub struct ComplexEmbedding<K, Impl, I>
171    where K: RingStore<Type = NumberFieldBase<Impl, I>>,
172        Impl: RingStore,
173        Impl::Type: Field + FreeAlgebra,
174        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
175        I: RingStore,
176        I::Type: IntegerRing
177{
178    from: K,
179    image_of_generator: El<Complex64>,
180    absolute_error_image_of_generator: f64
181}
182
183impl<K, Impl, I> ComplexEmbedding<K, Impl, I>
184    where K: RingStore<Type = NumberFieldBase<Impl, I>>,
185        Impl: RingStore,
186        Impl::Type: Field + FreeAlgebra,
187        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
188        I: RingStore,
189        I::Type: IntegerRing
190{
191    ///
192    /// Returns `epsilon > 0` such that when evaluating this homomorphism
193    /// at point `x`, the given result is at most `epsilon` from the actual
194    /// result (i.e. the result when computed with infinite precision).
195    /// 
196    #[stability::unstable(feature = "enable")]
197    pub fn absolute_error_bound_at(&self, x: &<NumberFieldBase<Impl, I> as RingBase>::Element) -> f64 {
198        let CC = Complex64::RING;
199        let CCX = DensePolyRing::new(CC, "X");
200        let f = self.from.poly_repr(&CCX, x, CC.can_hom(self.from.base_ring()).unwrap());
201        return absolute_error_of_poly_eval(&CCX, &f, self.from.rank(), self.image_of_generator, self.absolute_error_image_of_generator / CC.abs(self.image_of_generator));
202    }
203}
204
205impl<K, Impl, I> Homomorphism<NumberFieldBase<Impl, I>, Complex64Base> for ComplexEmbedding<K, Impl, I>
206    where K: RingStore<Type = NumberFieldBase<Impl, I>>,
207        Impl: RingStore,
208        Impl::Type: Field + FreeAlgebra,
209        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
210        I: RingStore,
211        I::Type: IntegerRing
212{
213    type DomainStore = K;
214    type CodomainStore = Complex64;
215
216    fn codomain<'a>(&'a self) -> &'a Self::CodomainStore {
217        &Complex64::RING
218    }
219
220    fn domain<'a>(&'a self) -> &'a Self::DomainStore {
221        &self.from
222    }
223
224    fn map_ref(&self, x: &<NumberFieldBase<Impl, I> as RingBase>::Element) -> <Complex64Base as RingBase>::Element {
225        let poly_ring = DensePolyRing::new(*self.codomain(), "X");
226        let hom = self.codomain().can_hom(self.from.base_ring()).unwrap();
227        return poly_ring.evaluate(&self.from.poly_repr(&poly_ring, &x, &hom), &self.image_of_generator, self.codomain().identity());
228    }
229
230    fn map(&self, x: <NumberFieldBase<Impl, I> as RingBase>::Element) -> <Complex64Base as RingBase>::Element {
231        self.map_ref(&x)
232    }
233}
234
235#[stability::unstable(feature = "enable")]
236pub type DefaultNumberFieldImpl = AsField<FreeAlgebraImpl<RationalField<BigIntRing>, Vec<El<RationalField<BigIntRing>>>, Global, KaratsubaAlgorithm>>;
237#[stability::unstable(feature = "enable")]
238pub type NumberField<Impl = DefaultNumberFieldImpl, I = BigIntRing> = RingValue<NumberFieldBase<Impl, I>>;
239
240impl NumberField {
241
242    ///
243    /// If the given polynomial is irreducible, returns the number field generated
244    /// by it (with a root of the polynomial as canonical generator). Otherwise,
245    /// `None` is returned.
246    /// 
247    /// If the given polynomial is not integral or not monic, consider using
248    /// [`NumberField::try_adjoin_root()`] instead.
249    /// 
250    #[stability::unstable(feature = "enable")]
251    pub fn try_new<P>(poly_ring: P, generating_poly: &El<P>) -> Option<Self>
252        where P: RingStore,
253            P::Type: PolyRing,
254            <P::Type as RingExtension>::BaseRing: RingStore<Type = BigIntRingBase>
255    {
256        assert!(poly_ring.base_ring().is_one(poly_ring.lc(generating_poly).unwrap()));
257        let QQ = RationalField::new(BigIntRing::RING);
258        let rank = poly_ring.degree(generating_poly).unwrap();
259        let modulus = (0..rank).map(|i| QQ.negate(QQ.inclusion().map_ref(poly_ring.coefficient_at(generating_poly, i)))).collect::<Vec<_>>();
260        return FreeAlgebraImpl::new_with_convolution(QQ, rank, modulus, "θ", Global, STANDARD_CONVOLUTION).as_field().ok().map(Self::create);
261    }
262    
263    ///
264    /// Given a monic, integral and irreducible polynomial, returns the number field 
265    /// generated by it (with a root of the polynomial as canonical generator).
266    /// 
267    /// Panics if the polynomial is not irreducible.
268    /// 
269    /// If the given polynomial is not integral or not monic, consider using
270    /// [`NumberField::adjoin_root()`] instead.
271    /// 
272    #[stability::unstable(feature = "enable")]
273    pub fn new<P>(poly_ring: P, generating_poly: &El<P>) -> Self
274        where P: RingStore,
275            P::Type: PolyRing,
276            <P::Type as RingExtension>::BaseRing: RingStore<Type = BigIntRingBase>
277    {
278        Self::try_new(poly_ring, generating_poly).unwrap()
279    }
280
281    ///
282    /// If the given polynopmial is irreducible, computes the number field generated
283    /// by one of its roots, and returns it together with the root (which is not necessarily
284    /// the canonical generator of the number field). Otherwise, `None` is returned.
285    /// 
286    #[stability::unstable(feature = "enable")]
287    pub fn try_adjoin_root<P>(poly_ring: P, generating_poly: &El<P>) -> Option<(Self, El<Self>)>
288        where P: RingStore,
289            P::Type: PolyRing,
290            <P::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<BigIntRing>>
291    {
292        let QQ = poly_ring.base_ring();
293        let ZZ = QQ.base_ring();
294        let denominator = poly_ring.terms(generating_poly).map(|(c, _)| QQ.get_ring().den(c)).fold(
295            ZZ.one(), 
296            |a, b| signed_lcm(a, ZZ.clone_el(b), ZZ)
297        );
298        let rank = poly_ring.degree(generating_poly).unwrap();
299        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();
300        let ZZX = DensePolyRing::new(ZZ, "X");
301        let new_generating_poly = ZZX.from_terms(poly_ring.terms(generating_poly).map(|(c, i)| if i == rank {
302            (ZZ.one(), rank)
303        } else {
304            (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)
305        }));
306        return Self::try_new(ZZX, &new_generating_poly).map(|res| {
307            let root = res.inclusion().mul_map(res.canonical_gen(), QQ.invert(&QQ.inclusion().map(scaled_lc)).unwrap());
308            return (res, root);
309        });
310    }
311    
312    #[stability::unstable(feature = "enable")]
313    pub fn adjoin_root<P>(poly_ring: P, generating_poly: &El<P>) -> (Self, El<Self>)
314        where P: RingStore,
315            P::Type: PolyRing,
316            <P::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<BigIntRing>>
317    {
318        Self::try_adjoin_root(poly_ring, generating_poly).unwrap()
319    }
320}
321
322impl<Impl, I> NumberField<Impl, I>
323    where Impl: RingStore,
324        Impl::Type: Field + FreeAlgebra,
325        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
326        I: RingStore,
327        I::Type: IntegerRing
328{
329    ///
330    /// Creates a new number field with the given underlying implementation.
331    /// 
332    /// Requires that all coefficients of the generating polynomial are integral.
333    /// 
334    #[stability::unstable(feature = "enable")]
335    pub fn create(implementation: Impl) -> Self {
336        let poly_ring = DensePolyRing::new(implementation.base_ring(), "X");
337        let gen_poly = implementation.generating_poly(&poly_ring, poly_ring.base_ring().identity());
338        assert!(poly_ring.terms(&gen_poly).all(|(c, _)| poly_ring.base_ring().base_ring().is_one(poly_ring.base_ring().get_ring().den(c))));
339        RingValue::from(NumberFieldBase {
340            base: implementation,
341        })
342    }
343
344    #[stability::unstable(feature = "enable")]
345    pub fn into_choose_complex_embedding(self) -> ComplexEmbedding<Self, Impl, I> {
346        let ZZ = self.base_ring().base_ring();
347        let poly_ring = DensePolyRing::new(ZZ, "X");
348        let poly = self.get_ring().generating_poly_as_int(&poly_ring);
349        let (root, error) = find_approximate_complex_root(&poly_ring, &poly).unwrap();
350        return ComplexEmbedding {
351            from: self,
352            image_of_generator: root,
353            absolute_error_image_of_generator: error
354        };
355    }
356
357    #[stability::unstable(feature = "enable")]
358    pub fn choose_complex_embedding<'a>(&'a self) -> ComplexEmbedding<&'a Self, Impl, I> {
359        let ZZ = self.base_ring().base_ring();
360        let poly_ring = DensePolyRing::new(ZZ, "X");
361        let poly = self.get_ring().generating_poly_as_int(&poly_ring);
362        let (root, error) = find_approximate_complex_root(&poly_ring, &poly).unwrap();
363        return ComplexEmbedding {
364            from: self,
365            image_of_generator: root,
366            absolute_error_image_of_generator: error
367        };
368    }
369}
370
371impl<Impl, I> NumberFieldBase<Impl, I>
372    where Impl: RingStore,
373        Impl::Type: Field + FreeAlgebra,
374        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
375        I: RingStore,
376        I::Type: IntegerRing
377{
378    fn generating_poly_as_int<'a>(&self, ZZX: &DensePolyRing<&'a I>) -> El<DensePolyRing<&'a I>> {
379        let ZZ = *ZZX.base_ring();
380        let assume_in_ZZ = LambdaHom::new(self.base_ring(), ZZ, |from, to, x| to.checked_div(from.get_ring().num(x), from.get_ring().den(x)).unwrap());
381        return self.base.generating_poly(ZZX, &assume_in_ZZ);
382    }
383}
384
385impl<Impl, I> Clone for NumberFieldBase<Impl, I>
386    where Impl: RingStore + Clone,
387        Impl::Type: Field + FreeAlgebra,
388        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
389        I: RingStore,
390        I::Type: IntegerRing
391{
392    fn clone(&self) -> Self {
393        Self {
394            base: self.base.clone(),
395        }
396    }
397}
398
399impl<Impl, I> Copy for NumberFieldBase<Impl, I>
400    where Impl: RingStore + Copy,
401        Impl::Type: Field + FreeAlgebra,
402        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
403        I: RingStore,
404        I::Type: IntegerRing,
405        El<Impl>: Copy,
406        El<I>: Copy
407{}
408
409impl<Impl, I> PartialEq for NumberFieldBase<Impl, I>
410    where Impl: RingStore,
411        Impl::Type: Field + FreeAlgebra,
412        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
413        I: RingStore,
414        I::Type: IntegerRing
415{
416    fn eq(&self, other: &Self) -> bool {
417        self.base.get_ring() == other.base.get_ring()
418    }
419}
420
421impl<Impl, I> DelegateRing for NumberFieldBase<Impl, I>
422    where Impl: RingStore,
423        Impl::Type: Field + FreeAlgebra,
424        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
425        I: RingStore,
426        I::Type: IntegerRing
427{
428    type Base = Impl::Type;
429    type Element = El<Impl>;
430
431    fn get_delegate(&self) -> &Self::Base {
432        self.base.get_ring()
433    }
434
435    fn delegate(&self, el: Self::Element) -> <Self::Base as RingBase>::Element { el }
436    fn delegate_mut<'a>(&self, el: &'a mut Self::Element) -> &'a mut <Self::Base as RingBase>::Element { el }
437    fn delegate_ref<'a>(&self, el: &'a Self::Element) -> &'a <Self::Base as RingBase>::Element { el }
438    fn rev_delegate(&self, el: <Self::Base as RingBase>::Element) -> Self::Element { el }
439}
440
441impl<Impl, I> DelegateRingImplEuclideanRing for NumberFieldBase<Impl, I>
442    where Impl: RingStore,
443        Impl::Type: Field + FreeAlgebra,
444        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
445        I: RingStore,
446        I::Type: IntegerRing
447{}
448
449impl<Impl, I> Debug for NumberFieldBase<Impl, I>
450    where Impl: RingStore,
451        Impl::Type: Field + FreeAlgebra + Debug,
452        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
453        I: RingStore,
454        I::Type: IntegerRing
455{
456    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
457        write!(f, "NumberField({:?})", self.base.get_ring())
458    }
459}
460
461impl<Impl, I> FiniteRingSpecializable for NumberFieldBase<Impl, I>
462    where Impl: RingStore,
463        Impl::Type: Field + FreeAlgebra,
464        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
465        I: RingStore,
466        I::Type: IntegerRing
467{
468    fn specialize<O: FiniteRingOperation<Self>>(op: O) -> O::Output {
469        op.fallback()
470    }
471}
472
473impl<Impl, I> Field for NumberFieldBase<Impl, I>
474    where Impl: RingStore,
475        Impl::Type: Field + FreeAlgebra,
476        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
477        I: RingStore,
478        I::Type: IntegerRing
479{}
480
481impl<Impl, I> PerfectField for NumberFieldBase<Impl, I>
482    where Impl: RingStore,
483        Impl::Type: Field + FreeAlgebra,
484        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
485        I: RingStore,
486        I::Type: IntegerRing
487{}
488
489impl<Impl, I> Domain for NumberFieldBase<Impl, I>
490    where Impl: RingStore,
491        Impl::Type: Field + FreeAlgebra,
492        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
493        I: RingStore,
494        I::Type: IntegerRing
495{}
496
497impl<Impl, I> PolyTFracGCDRing for NumberFieldBase<Impl, I>
498    where Impl: RingStore,
499        Impl::Type: Field + FreeAlgebra,
500        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
501        I: RingStore,
502        I::Type: IntegerRing
503{
504    fn gcd<P>(poly_ring: P, lhs: &El<P>, rhs: &El<P>) -> El<P>
505        where P: RingStore + Copy,
506            P::Type: PolyRing + DivisibilityRing,
507            <P::Type as RingExtension>::BaseRing: RingStore<Type = Self>
508    {
509        let self_ = NumberFieldByOrder { base: RingRef::new(poly_ring.base_ring().get_ring()) };
510
511        let order_poly_ring = DensePolyRing::new(RingRef::new(&self_), "X");
512        let lhs_order = self_.scale_poly_to_order(poly_ring, &order_poly_ring, lhs);
513        let rhs_order = self_.scale_poly_to_order(poly_ring, &order_poly_ring, rhs);
514
515        let result = poly_gcd_local(&order_poly_ring, order_poly_ring.clone_el(&lhs_order), order_poly_ring.clone_el(&rhs_order), DontObserve);
516
517        return self_.normalize_map_back_from_order(&order_poly_ring, poly_ring, &result);
518    }
519
520    fn power_decomposition<P>(poly_ring: P, poly: &El<P>) -> Vec<(El<P>, usize)>
521        where P: RingStore + Copy,
522            P::Type: PolyRing + DivisibilityRing,
523            <P::Type as RingExtension>::BaseRing: RingStore<Type = Self> 
524    {
525        let self_ = NumberFieldByOrder { base: RingRef::new(poly_ring.base_ring().get_ring()) };
526        let order_poly_ring = DensePolyRing::new(RingRef::new(&self_), "X");
527        let poly_order = self_.scale_poly_to_order(poly_ring, &order_poly_ring, poly);
528
529        let result = poly_power_decomposition_local(&order_poly_ring, poly_order, DontObserve);
530
531        return result.into_iter().map(|(f, k)| (self_.normalize_map_back_from_order(&order_poly_ring, poly_ring, &f), k)).collect();
532    }
533}
534
535enum HeuristicFactorPolyInOrderResult<P>
536    where P: RingStore,
537        P::Type: PolyRing
538{
539    PartialFactorization(Vec<(El<P>, usize)>),
540    Irreducible,
541    Unknown
542}
543
544///
545/// Tries to factor the polynomial directly, by first finding an inert prime `p`, so that
546/// the number ring modulo `p` becomes a finite field. Then we factor the polynomial over
547/// the finite field, and hensel-lift it to a factorization in the order. This can fail
548/// if we don't find an inert prime - note that they don't have to exist. Note also that the
549/// returned factorization may be only a partial factorization.
550/// 
551/// # Inert primes don't have to exist
552/// 
553/// E.g. `X^4 - 10 X^2 + 1` is reducible modulo every prime. In fact, it is a theorem that
554/// there exists inert primes if and only if the Galois group of the extension is cyclic.
555/// 
556fn heuristic_factor_poly_directly_in_order<'a, P, Impl, I, Controller>(poly_ring: P, poly: &El<P>, controller: Controller) -> HeuristicFactorPolyInOrderResult<P>
557    where Impl: 'a + RingStore,
558        Impl::Type: Field + FreeAlgebra,
559        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
560        I: 'a + RingStore,
561        I::Type: IntegerRing,
562        P: RingStore + Copy,
563        P::Type: PolyRing + DivisibilityRing,
564        <P::Type as RingExtension>::BaseRing: RingStore<Type = NumberFieldByOrder<'a, Impl, I>>,
565        Controller: ComputationController
566{
567    controller.run_computation(format_args!("factor_direct(deg={}, extdeg={})", poly_ring.degree(poly).unwrap(), poly_ring.base_ring().rank()), |controller| {
568        let mut rng = oorandom::Rand64::new(1);
569        let self_ = poly_ring.base_ring();
570
571        // first, we try to find an inert prime `p` and lift a factorization modulo `p` to the ring
572        'try_factor_directly: for _ in 0..TRY_FACTOR_DIRECTLY_ATTEMPTS {
573            let mut inert_prime = None;
574            for _ in 0..(TRY_FIND_INERT_PRIME_ATTEMPTS * self_.rank()) {
575                let p = self_.get_ring().random_suitable_ideal(|| rng.rand_u64());
576                if p.minpoly_factors_mod_p.len() == 1 {
577                    inert_prime = Some(p);
578                    break;
579                }
580            }
581            if let Some(p) = inert_prime {
582                log_progress!(controller, "(inert_prime={})", IdealDisplayWrapper::new(self_.base_ring().base_ring().get_ring(), &p.prime));
583                let lc_poly = self_.clone_el(poly_ring.lc(poly).unwrap());
584                let monic_poly = evaluate_aX(poly_ring, poly, &lc_poly);
585                let e = 2 * self_.get_ring().heuristic_exponent(&p, poly_ring.degree(&monic_poly).unwrap(), poly_ring.terms(&monic_poly).map(|(c, _)| c));
586                match factor_and_lift_mod_pe(poly_ring, &p, e, &monic_poly, controller.clone()) {
587                    FactorAndLiftModpeResult::PartialFactorization(factorization) => {
588                        log_progress!(controller, "(partial_success)");
589                        debug_assert!(poly_ring.eq_el(&monic_poly, &poly_ring.normalize(poly_ring.prod(factorization.iter().map(|f| poly_ring.clone_el(f))))));
590                        let result: Vec<_> = factorization.into_iter().map(|f| (unevaluate_aX(poly_ring, &f, &lc_poly), 1)).collect();
591                        debug_assert!(poly_ring.eq_el(&poly_ring.normalize(poly_ring.clone_el(poly)), &poly_ring.normalize(poly_ring.prod(result.iter().map(|(f, e)| poly_ring.pow(poly_ring.clone_el(f), *e))))));
592                        return HeuristicFactorPolyInOrderResult::PartialFactorization(result);
593                    },
594                    FactorAndLiftModpeResult::Irreducible => {
595                        return HeuristicFactorPolyInOrderResult::Irreducible;
596                    },
597                    FactorAndLiftModpeResult::NotSquarefreeModpe => {
598                        // probably not square-free
599                        let power_decomposition = poly_power_decomposition_local(poly_ring, poly_ring.clone_el(poly), controller.clone());
600                        if power_decomposition.len() > 1 {
601                            log_progress!(controller, "(partial_success)");
602                            return HeuristicFactorPolyInOrderResult::PartialFactorization(power_decomposition);
603                        }
604                    },
605                    FactorAndLiftModpeResult::Unknown => {}
606                }
607            } else {
608                break 'try_factor_directly;
609            }
610        }
611        log_progress!(controller, "(fail)");
612        return HeuristicFactorPolyInOrderResult::Unknown;
613    })
614}
615
616impl<Impl, I> FactorPolyField for NumberFieldBase<Impl, I>
617    where Impl: RingStore,
618        Impl::Type: Field + FreeAlgebra,
619        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
620        I: RingStore,
621        I::Type: IntegerRing + ComputeResultantRing
622{
623    fn factor_poly<P>(poly_ring: P, poly: &El<P>) -> (Vec<(El<P>, usize)>, Self::Element)
624        where P: RingStore + Copy,
625            P::Type: PolyRing + EuclideanRing,
626            <P::Type as RingExtension>::BaseRing: RingStore<Type = Self>
627    {
628        Self::factor_poly_with_controller(poly_ring, poly, DontObserve)
629    }
630
631    fn factor_poly_with_controller<P, Controller>(poly_ring: P, poly: &El<P>, controller: Controller) -> (Vec<(El<P>, usize)>, Self::Element)
632        where P: RingStore + Copy,
633            P::Type: PolyRing + EuclideanRing,
634            <P::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
635            Controller: ComputationController
636    {
637        let self_ = NumberFieldByOrder { base: RingRef::new(poly_ring.base_ring().get_ring()) };
638        let order_poly_ring = DensePolyRing::new(RingRef::new(&self_), "X");
639
640        let mut to_factor = vec![(poly_ring.clone_el(poly), 1)];
641        let mut result = Vec::new();
642        while let Some((current, e_base)) = to_factor.pop() {
643            if poly_ring.degree(&current).unwrap() == 1 {
644                result.push((poly_ring.normalize(current), 1));
645            } else {
646                let poly_order = self_.scale_poly_to_order(poly_ring, &order_poly_ring, &current);
647                // try the direct factorization
648                match heuristic_factor_poly_directly_in_order(&order_poly_ring, &poly_order, controller.clone()) {
649                    HeuristicFactorPolyInOrderResult::PartialFactorization(partial_factorization) => to_factor.extend(
650                        partial_factorization.into_iter().map(|(f, e)| (self_.normalize_map_back_from_order(&order_poly_ring, poly_ring, &f), e * e_base))
651                    ),
652                    HeuristicFactorPolyInOrderResult::Irreducible => result.push((current, e_base)),
653                    HeuristicFactorPolyInOrderResult::Unknown => result.extend(
654                        poly_factor_extension(&poly_ring, &current, controller.clone()).0.into_iter().map(|(f, e)| (f, e * e_base))
655                    )
656                }
657            }
658        }
659        return (result, poly_ring.base_ring().clone_el(poly_ring.lc(poly).unwrap()));
660    }
661}
662
663///
664/// Implements [`PolyGCDLocallyDomain`] for [`NumberField`].
665/// 
666/// We don't want to expose the interface of [`PolyGCDLocallyDomain`] for number
667/// fields generally, thus use a private newtype.
668/// 
669/// Note that this does not actually represent the order, since during
670/// `reconstruct_ring_el()` we might reconstruct an element outside of the
671/// order. Hence, it should remain private.
672/// 
673struct NumberFieldByOrder<'a, Impl, I>
674    where Impl: RingStore,
675        Impl::Type: Field + FreeAlgebra,
676        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
677        I: RingStore,
678        I::Type: IntegerRing
679{
680    base: RingRef<'a, NumberFieldBase<Impl, I>>
681}
682
683impl<'a, Impl, I> NumberFieldByOrder<'a, Impl, I>
684    where Impl: RingStore,
685        Impl::Type: Field + FreeAlgebra,
686        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
687        I: RingStore,
688        I::Type: IntegerRing
689{
690    ///
691    /// Multiplies the given polynomial with the lcm of the denominators of all coefficients,
692    /// and returns the polynomial as element of the current order.
693    /// 
694    fn scale_poly_to_order<'ring, P1, P2>(&self, from: P1, to: P2, poly: &El<P1>) -> El<P2>
695        where P1: RingStore,
696            P1::Type: PolyRing,
697            <P1::Type as RingExtension>::BaseRing: RingStore<Type = NumberFieldBase<Impl, I>>,
698            P2: RingStore,
699            P2::Type: PolyRing,
700            <P2::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
701            Self: 'ring
702    {
703        debug_assert!(self.base.get_ring() == from.base_ring().get_ring());
704        debug_assert!(self.base.get_ring() == to.base_ring().get_ring().base.get_ring());
705        let QQ = self.base.base_ring();
706        let ZZ = QQ.base_ring();
707        let denominator = QQ.inclusion().map(from.terms(poly).map(|(c, _)| 
708            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))
709        ).fold(ZZ.one(), |a, b| signed_lcm(a, b, ZZ)));
710        debug_assert!(!QQ.is_zero(&denominator));
711        return to.from_terms(from.terms(poly).map(|(c, i)| (self.base.inclusion().mul_ref_map(c, &denominator), i)));
712    }
713
714    fn normalize_map_back_from_order<'ring, P1, P2>(&self, from: P1, to: P2, poly: &El<P1>) -> El<P2>
715        where P1: RingStore,
716            P1::Type: PolyRing,
717            <P1::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
718            P2: RingStore,
719            P2::Type: PolyRing,
720            <P2::Type as RingExtension>::BaseRing: RingStore<Type = NumberFieldBase<Impl, I>>,
721            Self: 'ring
722    {
723        debug_assert!(self.base.get_ring() == to.base_ring().get_ring());
724        debug_assert!(self.base.get_ring() == from.base_ring().get_ring().base.get_ring());
725        let result = to.from_terms(from.terms(poly).map(|(c, i)| (self.clone_el(c), i)));
726        return to.normalize(result);
727    }
728}
729
730impl<'a, Impl, I> PartialEq for NumberFieldByOrder<'a, Impl, I>
731    where Impl: RingStore,
732        Impl::Type: Field + FreeAlgebra,
733        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
734        I: RingStore,
735        I::Type: IntegerRing
736{
737    fn eq(&self, other: &Self) -> bool {
738        self.base.get_ring() == other.base.get_ring()
739    }
740}
741
742impl<'a, Impl, I> FiniteRingSpecializable for NumberFieldByOrder<'a, Impl, I>
743    where Impl: RingStore,
744        Impl::Type: Field + FreeAlgebra,
745        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
746        I: RingStore,
747        I::Type: IntegerRing
748{
749    fn specialize<O: FiniteRingOperation<Self>>(op: O) -> O::Output {
750        op.fallback()
751    }
752}
753
754impl<'a, Impl, I> DelegateRing for NumberFieldByOrder<'a, Impl, I>
755    where Impl: RingStore,
756        Impl::Type: Field + FreeAlgebra,
757        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
758        I: RingStore,
759        I::Type: IntegerRing
760{
761    type Base = Impl::Type;
762    type Element = El<Impl>;
763
764    fn get_delegate(&self) -> &Self::Base {
765        self.base.get_ring().base.get_ring()
766    }
767
768    fn delegate(&self, el: Self::Element) -> <Self::Base as RingBase>::Element { el }
769    fn delegate_mut<'b>(&self, el: &'b mut Self::Element) -> &'b mut <Self::Base as RingBase>::Element { el }
770    fn delegate_ref<'b>(&self, el: &'b Self::Element) -> &'b <Self::Base as RingBase>::Element { el }
771    fn rev_delegate(&self, el: <Self::Base as RingBase>::Element) -> Self::Element { el }
772}
773
774impl<'a, Impl, I> Domain for NumberFieldByOrder<'a, Impl, I>
775    where Impl: RingStore,
776        Impl::Type: Field + FreeAlgebra,
777        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
778        I: RingStore,
779        I::Type: IntegerRing
780{}
781
782type LocalRing<'ring, I> = <<I as RingStore>::Type as PolyGCDLocallyDomain>::LocalRing<'ring>;
783
784type ImplementationRing<'ring, I> = AsFieldBase<FreeAlgebraImpl<
785    AsField<<<I as RingStore>::Type as IntegerPolyGCDRing>::LocalRingAsZn<'ring>>, 
786    SparseMapVector<AsField<<<I as RingStore>::Type as IntegerPolyGCDRing>::LocalRingAsZn<'ring>>>>
787>;
788
789struct NumberFieldOrderQuotient<'ring, I>
790    where I: 'ring + RingStore,
791        I::Type: IntegerRing
792{
793    implementation: RingValue<ImplementationRing<'ring, I>>
794}
795
796impl<'ring, I> Clone for NumberFieldOrderQuotient<'ring, I>
797    where I: 'ring + RingStore,
798        I::Type: IntegerRing
799{
800    fn clone(&self) -> Self {
801        Self { implementation: self.implementation.clone() }
802    }
803}
804
805impl<'ring, I> PartialEq for NumberFieldOrderQuotient<'ring, I>
806    where I: 'ring + RingStore,
807        I::Type: IntegerRing
808{
809    fn eq(&self, other: &Self) -> bool {
810        self.implementation.get_ring() == other.implementation.get_ring()
811    }
812}
813
814impl<'ring, I> DelegateRing for NumberFieldOrderQuotient<'ring, I>
815    where I: 'ring + RingStore,
816        I::Type: IntegerRing
817{
818    type Base = ImplementationRing<'ring, I>;
819    type Element = <ImplementationRing<'ring, I> as RingBase>::Element;
820
821    fn get_delegate(&self) -> &Self::Base {
822        self.implementation.get_ring()
823    }
824
825    fn delegate(&self, el: Self::Element) -> <Self::Base as RingBase>::Element { el }
826    fn delegate_mut<'b>(&self, el: &'b mut Self::Element) -> &'b mut <Self::Base as RingBase>::Element { el }
827    fn delegate_ref<'b>(&self, el: &'b Self::Element) -> &'b <Self::Base as RingBase>::Element { el }
828    fn rev_delegate(&self, el: <Self::Base as RingBase>::Element) -> Self::Element { el }
829}
830
831impl<'ring, I> Domain for NumberFieldOrderQuotient<'ring, I>
832    where I: 'ring + RingStore,
833        I::Type: IntegerRing
834{}
835
836impl<'ring, I> DelegateRingImplEuclideanRing for NumberFieldOrderQuotient<'ring, I>
837    where I: 'ring + RingStore,
838        I::Type: IntegerRing
839{}
840
841impl<'ring, I> Field for NumberFieldOrderQuotient<'ring, I>
842    where I: 'ring + RingStore,
843        I::Type: IntegerRing
844{}
845
846impl<'ring, I> DelegateRingImplFiniteRing for NumberFieldOrderQuotient<'ring, I>
847    where I: 'ring + RingStore,
848        I::Type: IntegerRing
849{}
850
851impl<'ring, I> CanHomFrom<Self> for NumberFieldOrderQuotient<'ring, I>
852    where I: 'ring + RingStore,
853        I::Type: IntegerRing
854{
855    type Homomorphism = ();
856
857    fn has_canonical_hom(&self, from: &Self) -> Option<Self::Homomorphism> {
858        if self == from {
859            Some(())
860        } else {
861            None
862        }
863    }
864
865    fn map_in(&self, _from: &Self, el: <Self as RingBase>::Element, _hom: &Self::Homomorphism) -> Self::Element {
866        el
867    }
868}
869
870impl<'ring, I> CanIsoFromTo<Self> for NumberFieldOrderQuotient<'ring, I>
871    where I: 'ring + RingStore,
872        I::Type: IntegerRing
873{
874    type Isomorphism = <Self as CanHomFrom<Self>>::Homomorphism;
875
876    fn has_canonical_iso(&self, from: &Self) -> Option<Self::Isomorphism> {
877        from.has_canonical_hom(self)
878    }
879
880    fn map_out(&self, from: &Self, el: Self::Element, iso: &Self::Isomorphism) -> <Self as RingBase>::Element {
881        from.map_in(self, el, iso)
882    }
883}
884
885///
886/// A prime ideal of a [`NumberField`].
887/// 
888/// Used for various implementations that work on the ring modulus prime ideals,
889/// and lift the result back to the ring.
890/// 
891pub struct NumberRingIdeal<'ring, I>
892    where I: RingStore,
893        I::Type: IntegerRing,
894        I: 'ring
895{
896    prime: <I::Type as PolyGCDLocallyDomain>::SuitableIdeal<'ring>,
897    ZZX: DensePolyRing<&'ring I>,
898    number_field_poly: El<DensePolyRing<&'ring I>>,
899    FpX: DensePolyRing<<I::Type as PolyGCDLocallyDomain>::LocalField<'ring>>,
900    Fp_as_ring: <I::Type as PolyGCDLocallyDomain>::LocalRing<'ring>,
901    Fp_as_zn: AsField<<I::Type as IntegerPolyGCDRing>::LocalRingAsZn<'ring>>,
902    minpoly_factors_mod_p: Vec<El<DensePolyRing<<I::Type as PolyGCDLocallyDomain>::LocalField<'ring>>>>
903}
904
905impl<'ring, I> NumberRingIdeal<'ring, I>
906    where I: RingStore,
907        I::Type: IntegerRing,
908        I: 'ring
909{
910    fn lifted_factorization<'a>(&'a self, e: usize) -> (DensePolyRing<<I::Type as PolyGCDLocallyDomain>::LocalRing<'ring>>, Vec<El<DensePolyRing<<I::Type as PolyGCDLocallyDomain>::LocalRing<'ring>>>>) {
911        let ZZX = &self.ZZX;
912        let ZZ = ZZX.base_ring();
913        let ZpeX = DensePolyRing::new(ZZ.get_ring().local_ring_at(&self.prime, e, 0), "X");
914        let Zpe = ZpeX.base_ring();
915        let FpX = &self.FpX;
916        let Zpe_to_Fp = PolyGCDLocallyIntermediateReductionMap::new(ZZ.get_ring(), &self.prime, Zpe, e, &self.Fp_as_ring, 1, 0);
917        let ZZ_to_Zpe = PolyGCDLocallyReductionMap::new(ZZ.get_ring(), &self.prime, &Zpe, e, 0);
918
919        let factors = hensel::hensel_lift_factorization(
920            &Zpe_to_Fp,
921            &ZpeX,
922            FpX,
923            &ZpeX.lifted_hom(ZZX, ZZ_to_Zpe).map_ref(&self.number_field_poly),
924            &self.minpoly_factors_mod_p[..],
925            DontObserve
926        );
927        
928        return (ZpeX, factors);
929    }
930}
931
932impl<'ring, I> Debug for NumberRingIdeal<'ring, I>
933    where I: RingStore,
934        I::Type: IntegerRing,
935        I: 'ring,
936        <I::Type as PolyGCDLocallyDomain>::SuitableIdeal<'ring>: Debug
937{
938    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
939        f.debug_struct("NumberRingIdeal")
940            .field("prime", &self.prime)
941            .finish()
942    }
943}
944
945impl<'a, Impl, I> PolyGCDLocallyDomain for NumberFieldByOrder<'a, Impl, I>
946    where Impl: RingStore,
947        Impl::Type: Field + FreeAlgebra,
948        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
949        I: RingStore,
950        I::Type: IntegerRing
951{
952    type LocalRingBase<'ring> = FreeAlgebraImplBase<
953        LocalRing<'ring, I>, 
954        SparseMapVector<LocalRing<'ring, I>>
955    >
956        where Self: 'ring;
957
958    type LocalRing<'ring> = RingValue<Self::LocalRingBase<'ring>>
959        where Self: 'ring;
960
961    type LocalFieldBase<'ring> = NumberFieldOrderQuotient<'ring, I>
962        where Self: 'ring;
963
964    type LocalField<'ring> = RingValue<Self::LocalFieldBase<'ring>>
965        where Self: 'ring;
966
967    type SuitableIdeal<'ring> = NumberRingIdeal<'ring, I>
968        where Self: 'ring;
969
970    fn maximal_ideal_factor_count<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>) -> usize
971        where Self: 'ring
972    {
973        ideal.minpoly_factors_mod_p.len()
974    }
975
976    fn heuristic_exponent<'ring, 'b, J>(&self, ideal: &Self::SuitableIdeal<'ring>, poly_deg: usize, coefficients: J) -> usize
977        where J: Iterator<Item = &'b Self::Element>,
978            Self: 'b,
979            Self: 'ring
980    {
981        const HEURISTIC_FACTOR_SIZE_OVER_POLY_SIZE_FACTOR: f64 = 0.25;
982
983        let QQ = self.base.base_ring();
984        let ZZ = QQ.base_ring();
985        // to give any mathematically justifiable value, we would probably have to consider the canonical norm;
986        // I don't want to deal with this here, so let's just use the coefficient norm instead...
987        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);
988        let log2_p = BigIntRing::RING.to_float_approx(&ZZ.get_ring().principal_ideal_generator(&ideal.prime)).log2();
989        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;
990    }
991
992    fn random_suitable_ideal<'ring, F>(&'ring self, mut rng: F) -> Self::SuitableIdeal<'ring>
993        where F: FnMut() -> u64
994    {
995        let QQ = self.base.base_ring();
996        let ZZ = QQ.base_ring();
997        let ZZX = DensePolyRing::new(ZZ, "X");
998        let gen_poly = self.base.generating_poly(&ZZX, LambdaHom::new(QQ, ZZ, |QQ, ZZ, x| {
999            assert!(ZZ.is_one(QQ.get_ring().den(&x)));
1000            ZZ.clone_el(QQ.get_ring().num(&x))
1001        }));
1002
1003        // search for a prime `p` such that the minimal polynomial is unramified modulo `p`
1004        for _ in 0..MAX_PROBABILISTIC_REPETITIONS {
1005            let p = ZZ.get_ring().random_suitable_ideal(&mut rng);
1006            assert_eq!(1, ZZ.get_ring().maximal_ideal_factor_count(&p));
1007
1008            let Fp_as_ring = ZZ.get_ring().local_ring_at(&p, 1, 0);
1009            let FpX = DensePolyRing::new(ZZ.get_ring().local_field_at(&p, 0), "X");
1010            let Fp = FpX.base_ring();
1011            let ZZ_to_Fp = LambdaHom::new(ZZ, Fp, |ZZ, Fp, x| ZZ.get_ring().base_ring_to_field(&p, Fp_as_ring.get_ring(), Fp.get_ring(), 0, 
1012                ZZ.get_ring().reduce_ring_el(&p, (Fp_as_ring.get_ring(), 1), 0, ZZ.clone_el(x))));
1013
1014            let gen_poly_mod_p = FpX.from_terms(ZZX.terms(&gen_poly).map(|(c, i)| (ZZ_to_Fp.map_ref(c), i)));
1015            let (factorization, _) = <_ as FactorPolyField>::factor_poly(&FpX, &gen_poly_mod_p);
1016            if factorization.iter().all(|(_, e)| *e == 1) {
1017
1018                return NumberRingIdeal {
1019                    minpoly_factors_mod_p: factorization.into_iter().map(|(f, _)| f).collect(),
1020                    number_field_poly: gen_poly,
1021                    FpX: FpX,
1022                    ZZX: ZZX,
1023                    Fp_as_zn: ZZ.get_ring().local_ring_into_zn(Fp_as_ring.clone()).as_field().ok().unwrap(),
1024                    Fp_as_ring: Fp_as_ring,
1025                    prime: p
1026                };
1027            }
1028        }
1029        unreachable!()
1030    }
1031
1032    fn local_field_at<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, idx: usize) -> Self::LocalField<'ring>
1033        where Self: 'ring
1034    {
1035        assert!(idx < self.maximal_ideal_factor_count(ideal));
1036        let QQ = self.base.base_ring();
1037        let ZZ = QQ.base_ring();
1038        assert_eq!(1, ZZ.get_ring().maximal_ideal_factor_count(&ideal.prime));
1039        let FpX = &ideal.FpX;
1040        let Fp_to_Fp = WrapHom::to_delegate_ring(ideal.Fp_as_zn.get_ring())
1041            .compose(RingRef::new(ideal.Fp_as_zn.get_ring().get_delegate()).into_can_hom(&ideal.Fp_as_ring).ok().unwrap())
1042            .compose(PolyGCDLocallyBaseRingToFieldIso::new(ZZ.get_ring(), &ideal.prime, ideal.Fp_as_ring.get_ring(), FpX.base_ring().get_ring(), 0).inv());
1043
1044        let irred_poly = &ideal.minpoly_factors_mod_p[idx];
1045        let mut x_pow_rank = SparseMapVector::new(FpX.degree(irred_poly).unwrap(), ideal.Fp_as_zn.clone());
1046        for (c, i) in FpX.terms(irred_poly) {
1047            if i < x_pow_rank.len() {
1048                *x_pow_rank.at_mut(i) = Fp_to_Fp.codomain().negate(Fp_to_Fp.map_ref(c));
1049            }
1050        }
1051        _ = x_pow_rank.at_mut(0);
1052        return RingValue::from(NumberFieldOrderQuotient {
1053            implementation: AsField::from(AsFieldBase::promise_is_perfect_field(FreeAlgebraImpl::new(ideal.Fp_as_zn.clone(), FpX.degree(irred_poly).unwrap(), x_pow_rank))),
1054        });
1055    }
1056
1057    fn local_ring_at<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, e: usize, idx: usize) -> Self::LocalRing<'ring>
1058        where Self: 'ring
1059    {
1060        assert!(idx < self.maximal_ideal_factor_count(ideal));
1061        let QQ = self.base.base_ring();
1062        let ZZ = QQ.base_ring();
1063        let (ZpeX, factors) = ideal.lifted_factorization(e);
1064        let Zpe = ZZ.get_ring().local_ring_at(&ideal.prime, e, 0);
1065        assert!(Zpe.get_ring() == ZpeX.base_ring().get_ring());
1066
1067        let irred_poly = &factors[idx];
1068        let degree = ZpeX.degree(irred_poly).unwrap();
1069        let mut x_pow_rank = SparseMapVector::new(degree, Zpe.clone());
1070        for (c, i) in ZpeX.terms(irred_poly) {
1071            if i < x_pow_rank.len() {
1072                *x_pow_rank.at_mut(i) = Zpe.negate(Zpe.clone_el(c));
1073            }
1074        }
1075        _ = x_pow_rank.at_mut(0);
1076        return FreeAlgebraImpl::new(Zpe, degree, x_pow_rank);
1077    }
1078
1079    fn reduce_ring_el<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, to: (&Self::LocalRingBase<'ring>, usize), idx: usize, x: Self::Element) -> El<Self::LocalRing<'ring>>
1080        where Self: 'ring
1081    {
1082        assert!(idx < self.maximal_ideal_factor_count(ideal));
1083        let QQ = self.base.base_ring();
1084        let ZZ = QQ.base_ring();
1085        let ZZX = &ideal.ZZX;
1086        let partial_QQ_to_ZZ = LambdaHom::new(QQ, ZZ, |QQ, ZZ, x| {
1087            assert!(ZZ.is_one(QQ.get_ring().den(&x)));
1088            ZZ.clone_el(QQ.get_ring().num(&x))
1089        });
1090        let ZZ_to_Zpe = PolyGCDLocallyReductionMap::new(ZZ.get_ring(), &ideal.prime, to.0.base_ring(), to.1, 0);
1091
1092        ZZX.evaluate(
1093            &self.base.poly_repr(ZZX, &x, partial_QQ_to_ZZ), 
1094            &to.0.canonical_gen(), 
1095            RingRef::new(to.0).into_inclusion().compose(ZZ_to_Zpe)
1096        )
1097    }
1098
1099    fn base_ring_to_field<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, from: &Self::LocalRingBase<'ring>, to: &Self::LocalFieldBase<'ring>, idx: usize, x: El<Self::LocalRing<'ring>>) -> El<Self::LocalField<'ring>>
1100        where Self: 'ring
1101    {
1102        assert!(idx < self.maximal_ideal_factor_count(ideal));
1103        let hom = WrapHom::to_delegate_ring(to.base_ring().get_ring()).compose(RingRef::new(to.base_ring().get_ring().get_delegate()).into_can_hom(from.base_ring()).ok().unwrap());
1104        to.from_canonical_basis(from.wrt_canonical_basis(&x).iter().map(|c| hom.map(c)))
1105    }
1106
1107    fn field_to_base_ring<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, from: &Self::LocalFieldBase<'ring>, to: &Self::LocalRingBase<'ring>, idx: usize, x: El<Self::LocalField<'ring>>) -> El<Self::LocalRing<'ring>>
1108        where Self: 'ring
1109    {
1110        assert!(idx < self.maximal_ideal_factor_count(ideal));
1111        assert!(idx < self.maximal_ideal_factor_count(ideal));
1112        let hom = RingRef::new(from.base_ring().get_ring().get_delegate()).into_can_iso(to.base_ring()).ok().unwrap().compose(UnwrapHom::from_delegate_ring(from.base_ring().get_ring()));
1113        to.from_canonical_basis(from.wrt_canonical_basis(&x).iter().map(|c| hom.map(c)))
1114    }
1115
1116    fn reduce_partial<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, from: (&Self::LocalRingBase<'ring>, usize), to: (&Self::LocalRingBase<'ring>, usize), idx: usize, x: El<Self::LocalRing<'ring>>) -> El<Self::LocalRing<'ring>>
1117        where Self: 'ring
1118    {
1119        assert!(idx < self.maximal_ideal_factor_count(ideal));
1120        let QQ = self.base.base_ring();
1121        let ZZ = QQ.base_ring();
1122        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().get_ring(), from.1), (to.0.base_ring().get_ring(), to.1), 0, c)))
1123    }
1124
1125    fn lift_partial<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, from: (&Self::LocalRingBase<'ring>, usize), to: (&Self::LocalRingBase<'ring>, usize), idx: usize, x: El<Self::LocalRing<'ring>>) -> El<Self::LocalRing<'ring>>
1126        where Self: 'ring
1127    {
1128        assert!(idx < self.maximal_ideal_factor_count(ideal));
1129        let QQ = self.base.base_ring();
1130        let ZZ = QQ.base_ring();
1131        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().get_ring(), from.1), (to.0.base_ring().get_ring(), to.1), 0, c)))
1132    }
1133
1134    fn reconstruct_ring_el<'local, 'element, 'ring, V1, V2>(&self, ideal: &Self::SuitableIdeal<'ring>, from: V1, e: usize, x: V2) -> Self::Element
1135        where Self: 'ring,
1136            V1: VectorFn<&'local Self::LocalRing<'ring>>,
1137            V2: VectorFn<&'element El<Self::LocalRing<'ring>>>,
1138            Self::LocalRing<'ring>: 'local,
1139            El<Self::LocalRing<'ring>>: 'element,
1140            'ring: 'local + 'element
1141    {
1142        assert_eq!(self.maximal_ideal_factor_count(ideal), from.len());
1143        assert_eq!(self.maximal_ideal_factor_count(ideal), x.len());
1144        let QQ = self.base.base_ring();
1145        let ZZ = QQ.base_ring();
1146        let Zpe = from.at(0).base_ring();
1147        assert!(from.iter().all(|ring| ring.base_ring().get_ring() == Zpe.get_ring()));
1148        let ZpeX = DensePolyRing::new(Zpe, "X");
1149        let ZZ_to_Zpe = PolyGCDLocallyReductionMap::new(ZZ.get_ring(), &ideal.prime, Zpe, e, 0);
1150
1151        // compute data necessary for inverse CRT
1152        let mut unit_vectors = (0..self.maximal_ideal_factor_count(ideal)).map(|_| ZpeX.zero()).collect::<Vec<_>>();
1153        product_except_one(&ZpeX, (&from).map_fn(|galois_ring| galois_ring.generating_poly(&ZpeX, Zpe.identity())), &mut unit_vectors);
1154        let complete_product = ZpeX.mul_ref_fst(&unit_vectors[0], from.at(0).generating_poly(&ZpeX, Zpe.identity()));
1155        assert_el_eq!(&ZpeX, &complete_product, &self.base.generating_poly(&ZpeX, ZZ_to_Zpe.compose(LambdaHom::new(QQ, ZZ, |QQ, ZZ, x| {
1156            assert!(ZZ.is_one(QQ.get_ring().den(&x)));
1157            ZZ.clone_el(QQ.get_ring().num(&x))
1158        }))));
1159
1160        for i in 0..self.maximal_ideal_factor_count(ideal) {
1161            let galois_ring = from.at(i);
1162            let inv_normalization_factor = ZpeX.evaluate(unit_vectors.at(i), &galois_ring.canonical_gen(), galois_ring.inclusion());
1163            let normalization_factor = galois_ring.invert(&inv_normalization_factor).unwrap();
1164            let lifted_normalization_factor = galois_ring.poly_repr(&ZpeX, &normalization_factor, Zpe.identity());
1165            let unreduced_new_unit_vector = ZpeX.mul(std::mem::replace(&mut unit_vectors[i], ZpeX.zero()), lifted_normalization_factor);
1166            unit_vectors[i] = ZpeX.div_rem_monic(unreduced_new_unit_vector, &complete_product).1;
1167        }
1168
1169        // now apply inverse CRT to get the value over ZpeX
1170        let combined = <_ as RingStore>::sum(&ZpeX, (0..self.maximal_ideal_factor_count(ideal)).map(|i| {
1171            let galois_ring = from.at(i);
1172            let unreduced_result = ZpeX.mul_ref_snd(galois_ring.poly_repr(&ZpeX, x.at(i), Zpe.identity()), &unit_vectors[i]);
1173            ZpeX.div_rem_monic(unreduced_result, &complete_product).1
1174        }));
1175
1176        for i in 0..self.maximal_ideal_factor_count(ideal) {
1177            let galois_ring = from.at(i);
1178            debug_assert!(galois_ring.eq_el(x.at(i), &ZpeX.evaluate(&combined, &galois_ring.canonical_gen(), galois_ring.inclusion())));
1179        }
1180
1181        // now lift the polynomial modulo `p^e` to the rationals
1182        let Zpe_as_zn = ZZ.get_ring().local_ring_as_zn(&Zpe);
1183        let Zpe_to_as_zn = Zpe_as_zn.can_hom(Zpe).unwrap();
1184        let result = self.from_canonical_basis((0..self.rank()).map(|i| {
1185            let (num, den) = balanced_rational_reconstruction(Zpe_as_zn, Zpe_to_as_zn.map_ref(ZpeX.coefficient_at(&combined, i)));
1186            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())));
1187        }));
1188        return result;
1189    }
1190
1191    fn dbg_ideal<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, out: &mut std::fmt::Formatter) -> std::fmt::Result
1192        where Self: 'ring
1193    {
1194        let QQ = self.base.base_ring();
1195        QQ.base_ring().get_ring().dbg_ideal(&ideal.prime, out)
1196    }
1197}
1198
1199impl<Impl, I> Serialize for NumberFieldBase<Impl, I>
1200    where Impl: RingStore + Serialize,
1201        Impl::Type: Field + FreeAlgebra + SerializableElementRing,
1202        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
1203        I: RingStore,
1204        I::Type: IntegerRing
1205{
1206    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1207        where S: Serializer
1208    {
1209        SerializableNewtypeStruct::new("NumberField", &self.base).serialize(serializer)
1210    }
1211}
1212
1213impl<'de, Impl, I> Deserialize<'de> for NumberFieldBase<Impl, I>
1214    where Impl: RingStore + Deserialize<'de>,
1215        Impl::Type: Field + FreeAlgebra + SerializableElementRing,
1216        <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
1217        I: RingStore,
1218        I::Type: IntegerRing
1219{
1220    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1221        where D: Deserializer<'de>
1222    {
1223        DeserializeSeedNewtypeStruct::new("NumberField", PhantomData::<Impl>).deserialize(deserializer).map(|res| NumberField::create(res).into())
1224    }
1225}
1226
1227#[cfg(test)]
1228use crate::RANDOM_TEST_INSTANCE_COUNT;
1229#[cfg(test)]
1230use crate::iters::multi_cartesian_product;
1231
1232#[test]
1233fn test_principal_ideal_ring_axioms() {
1234    let ZZ = BigIntRing::RING;
1235    let ZZX = DensePolyRing::new(ZZ, "X");
1236
1237    let [f] = ZZX.with_wrapped_indeterminate(|X| [X.pow_ref(2) + 1]);
1238    let K = NumberField::new(&ZZX, &f);
1239
1240    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<_>>();
1241
1242    crate::pid::generic_tests::test_principal_ideal_ring_axioms(&K, elements.iter().map(|x| K.clone_el(x)));
1243}
1244
1245#[test]
1246fn test_adjoin_root() {
1247    let ZZ = BigIntRing::RING;
1248    let QQ = RationalField::new(ZZ);
1249    let QQX = DensePolyRing::new(QQ, "X");
1250    let [f] = QQX.with_wrapped_indeterminate(|X| [2 * X.pow_ref(3) - 1]);
1251    let (K, a) = NumberField::adjoin_root(&QQX, &f);
1252    assert_el_eq!(&K, K.zero(), K.sub(K.mul(K.int_hom().map(2), K.pow(a, 3)), K.one()));
1253}
1254
1255#[test]
1256fn test_poly_gcd_number_field() {
1257    let ZZ = BigIntRing::RING;
1258    let ZZX = DensePolyRing::new(ZZ, "X");
1259
1260    let [f] = ZZX.with_wrapped_indeterminate(|X| [X.pow_ref(2) + 1]);
1261    let K = NumberField::new(&ZZX, &f);
1262    let KY = DensePolyRing::new(&K, "Y");
1263
1264    let i = RingElementWrapper::new(&KY, KY.inclusion().map(K.canonical_gen()));
1265    let [g, h, expected] = KY.with_wrapped_indeterminate(|Y| [
1266        (Y.pow_ref(3) + 1) * (Y - &i),
1267        (Y.pow_ref(4) + 2) * (Y.pow_ref(2) + 1),
1268        Y - i
1269    ]);
1270    assert_el_eq!(&KY, &expected, <_ as PolyTFracGCDRing>::gcd(&KY, &g, &h));
1271
1272    let [f] = ZZX.with_wrapped_indeterminate(|X| [X.pow_ref(4) - 20 * X.pow_ref(2) + 16]);
1273    let K = NumberField::new(&ZZX, &f);
1274    let KY = DensePolyRing::new(&K, "Y");
1275
1276    let [sqrt3, sqrt7] = K.with_wrapped_generator(|a| [a.pow_ref(3) / 8 - 2 * a, a.pow_ref(3) / 8 - 3 * a]);
1277    assert_el_eq!(&K, K.int_hom().map(3), K.pow(K.clone_el(&sqrt3), 2));
1278    assert_el_eq!(&K, K.int_hom().map(7), K.pow(K.clone_el(&sqrt7), 2));
1279
1280    let half = RingElementWrapper::new(&KY, KY.inclusion().map(K.invert(&K.int_hom().map(2)).unwrap()));
1281    let sqrt3 = RingElementWrapper::new(&KY, KY.inclusion().map(sqrt3));
1282    let sqrt7 = RingElementWrapper::new(&KY, KY.inclusion().map(sqrt7));
1283    let [g, h, expected] = KY.with_wrapped_indeterminate(|Y| [
1284        Y.pow_ref(2) - &sqrt3 * Y - 1,
1285        Y.pow_ref(2) + &sqrt7 * Y + 1,
1286        Y - (sqrt3 - sqrt7) * half
1287    ]);
1288    let actual = <_ as PolyTFracGCDRing>::gcd(&KY, &g, &h);
1289    assert_el_eq!(&KY, &expected, &actual);
1290}
1291
1292#[test]
1293#[ignore]
1294fn random_test_poly_gcd_number_field() {
1295    let ZZ = BigIntRing::RING;
1296    let QQ = RationalField::new(ZZ);
1297    let ZZX = DensePolyRing::new(ZZ, "X");
1298    let mut rng = oorandom::Rand64::new(1);
1299    let bound = QQ.base_ring().int_hom().map(1000);
1300    let rank = 6;
1301
1302    for _ in 0..RANDOM_TEST_INSTANCE_COUNT {
1303        let genpoly = ZZX.from_terms((0..rank).map(|i| (ZZ.get_uniformly_random(&bound, || rng.rand_u64()), i)).chain([(ZZ.one(), rank)].into_iter()));
1304
1305        let K = NumberField::new(&ZZX, &genpoly);
1306        let KY = DensePolyRing::new(&K, "Y");
1307
1308        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()))));
1309        let f = KY.from_terms((0..=5).map(|i| (random_element_K(), i)));
1310        let g = KY.from_terms((0..=5).map(|i| (random_element_K(), i)));
1311        let h = KY.from_terms((0..=4).map(|i| (random_element_K(), i)));
1312        // println!("Testing gcd on ({}) * ({}) and ({}) * ({})", poly_ring.format(&f), poly_ring.format(&h), poly_ring.format(&g), poly_ring.format(&h));
1313        let lhs = KY.mul_ref(&f, &h);
1314        let rhs = KY.mul_ref(&g, &h);
1315
1316        let gcd = <_ as PolyTFracGCDRing>::gcd(&KY, &lhs, &rhs);
1317        // println!("Result {}", poly_ring.format(&gcd));
1318
1319        assert!(KY.divides(&lhs, &gcd));
1320        assert!(KY.divides(&rhs, &gcd));
1321        assert!(KY.divides(&gcd, &h));
1322    }
1323}