1use std::alloc::Global;
2use std::fmt::{Debug, Formatter};
3use std::marker::PhantomData;
4
5use feanor_serde::newtype_struct::*;
6use serde::de::DeserializeSeed;
7use serde::{Deserialize, Deserializer, Serialize, Serializer};
8
9use super::extension_impl::FreeAlgebraImpl;
10use super::{Field, FreeAlgebra};
11use crate::MAX_PROBABILISTIC_REPETITIONS;
12use crate::algorithms::convolution::*;
13use crate::algorithms::eea::signed_lcm;
14use crate::algorithms::interpolate::product_except_one;
15use crate::algorithms::newton::{self, absolute_error_of_poly_eval};
16use crate::algorithms::poly_factor::extension::poly_factor_extension;
17use crate::algorithms::poly_factor::factor_locally::{FactorAndLiftModpeResult, factor_and_lift_mod_pe};
18use crate::algorithms::poly_gcd::gcd::poly_gcd_local;
19use crate::algorithms::poly_gcd::squarefree_part::poly_power_decomposition_local;
20use crate::algorithms::poly_gcd::*;
21use crate::algorithms::rational_reconstruction::balanced_rational_reconstruction;
22use crate::algorithms::resultant::ComputeResultantRing;
23use crate::computation::*;
24use crate::delegate::*;
25use crate::divisibility::*;
26use crate::integer::*;
27use crate::pid::*;
28use crate::reduce_lift::poly_factor_gcd::*;
29use crate::ring::*;
30use crate::rings::extension::extension_impl::*;
31use crate::rings::extension::number_field::newton::find_approximate_complex_root;
32use crate::rings::extension::sparse::SparseMapVector;
33use crate::rings::extension::*;
34use crate::rings::field::AsField;
35use crate::rings::float_complex::{Complex64, Complex64Base};
36use crate::rings::rational::*;
37use crate::rings::zn::ZnRingStore;
38use crate::serialization::*;
39use crate::specialization::*;
40
41const TRY_FIND_INERT_PRIME_ATTEMPTS: usize = 10;
42const TRY_FACTOR_DIRECTLY_ATTEMPTS: usize = 5;
43
44#[stability::unstable(feature = "enable")]
159pub struct NumberFieldBase<Impl, I>
160where
161 Impl: RingStore,
162 Impl::Type: Field + FreeAlgebra,
163 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
164 I: RingStore,
165 I::Type: IntegerRing,
166{
167 base: Impl,
168}
169
170#[stability::unstable(feature = "enable")]
173pub struct ComplexEmbedding<K, Impl, I>
174where
175 K: RingStore<Type = NumberFieldBase<Impl, I>>,
176 Impl: RingStore,
177 Impl::Type: Field + FreeAlgebra,
178 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
179 I: RingStore,
180 I::Type: IntegerRing,
181{
182 from: K,
183 image_of_generator: El<Complex64>,
184 absolute_error_image_of_generator: f64,
185}
186
187impl<K, Impl, I> ComplexEmbedding<K, Impl, I>
188where
189 K: RingStore<Type = NumberFieldBase<Impl, I>>,
190 Impl: RingStore,
191 Impl::Type: Field + FreeAlgebra,
192 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
193 I: RingStore,
194 I::Type: IntegerRing,
195{
196 #[stability::unstable(feature = "enable")]
200 pub fn absolute_error_bound_at(&self, x: &<NumberFieldBase<Impl, I> as RingBase>::Element) -> f64 {
201 let CC = Complex64::RING;
202 let CCX = DensePolyRing::new(CC, "X");
203 let f = self.from.poly_repr(&CCX, x, CC.can_hom(self.from.base_ring()).unwrap());
204 return absolute_error_of_poly_eval(
205 &CCX,
206 &f,
207 self.from.rank(),
208 self.image_of_generator,
209 self.absolute_error_image_of_generator / CC.abs(self.image_of_generator),
210 );
211 }
212}
213
214impl<K, Impl, I> Homomorphism<NumberFieldBase<Impl, I>, Complex64Base> for ComplexEmbedding<K, Impl, I>
215where
216 K: RingStore<Type = NumberFieldBase<Impl, I>>,
217 Impl: RingStore,
218 Impl::Type: Field + FreeAlgebra,
219 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
220 I: RingStore,
221 I::Type: IntegerRing,
222{
223 type DomainStore = K;
224 type CodomainStore = Complex64;
225
226 fn codomain(&self) -> &Self::CodomainStore { &Complex64::RING }
227
228 fn domain(&self) -> &Self::DomainStore { &self.from }
229
230 fn map_ref(&self, x: &<NumberFieldBase<Impl, I> as RingBase>::Element) -> <Complex64Base as RingBase>::Element {
231 let poly_ring = DensePolyRing::new(*self.codomain(), "X");
232 let hom = self.codomain().can_hom(self.from.base_ring()).unwrap();
233 return poly_ring.evaluate(
234 &self.from.poly_repr(&poly_ring, x, &hom),
235 &self.image_of_generator,
236 self.codomain().identity(),
237 );
238 }
239
240 fn map(&self, x: <NumberFieldBase<Impl, I> as RingBase>::Element) -> <Complex64Base as RingBase>::Element {
241 self.map_ref(&x)
242 }
243}
244
245#[stability::unstable(feature = "enable")]
246pub type DefaultNumberFieldImpl =
247 AsField<FreeAlgebraImpl<RationalField<BigIntRing>, Vec<El<RationalField<BigIntRing>>>, Global, KaratsubaAlgorithm>>;
248#[stability::unstable(feature = "enable")]
249pub type NumberField<Impl = DefaultNumberFieldImpl, I = BigIntRing> = RingValue<NumberFieldBase<Impl, I>>;
250
251impl NumberField {
252 #[stability::unstable(feature = "enable")]
259 pub fn try_new<P>(poly_ring: P, generating_poly: &El<P>) -> Option<Self>
260 where
261 P: RingStore,
262 P::Type: PolyRing,
263 <P::Type as RingExtension>::BaseRing: RingStore<Type = BigIntRingBase>,
264 {
265 assert!(poly_ring.base_ring().is_one(poly_ring.lc(generating_poly).unwrap()));
266 let QQ = RationalField::new(BigIntRing::RING);
267 let rank = poly_ring.degree(generating_poly).unwrap();
268 let modulus = (0..rank)
269 .map(|i| QQ.negate(QQ.inclusion().map_ref(poly_ring.coefficient_at(generating_poly, i))))
270 .collect::<Vec<_>>();
271 return FreeAlgebraImpl::new_with_convolution(QQ, rank, modulus, "θ", Global, STANDARD_CONVOLUTION)
272 .as_field()
273 .ok()
274 .map(Self::create);
275 }
276
277 #[stability::unstable(feature = "enable")]
285 pub fn new<P>(poly_ring: P, generating_poly: &El<P>) -> Self
286 where
287 P: RingStore,
288 P::Type: PolyRing,
289 <P::Type as RingExtension>::BaseRing: RingStore<Type = BigIntRingBase>,
290 {
291 Self::try_new(poly_ring, generating_poly).unwrap()
292 }
293
294 #[stability::unstable(feature = "enable")]
298 pub fn try_adjoin_root<P>(poly_ring: P, generating_poly: &El<P>) -> Option<(Self, El<Self>)>
299 where
300 P: RingStore,
301 P::Type: PolyRing,
302 <P::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<BigIntRing>>,
303 {
304 let QQ = poly_ring.base_ring();
305 let ZZ = QQ.base_ring();
306 let denominator = poly_ring
307 .terms(generating_poly)
308 .map(|(c, _)| QQ.get_ring().den(c))
309 .fold(ZZ.one(), |a, b| signed_lcm(a, ZZ.clone_el(b), ZZ));
310 let rank = poly_ring.degree(generating_poly).unwrap();
311 let scaled_lc = ZZ
312 .checked_div(
313 &ZZ.mul_ref(&denominator, QQ.get_ring().num(poly_ring.lc(generating_poly).unwrap())),
314 QQ.get_ring().den(poly_ring.lc(generating_poly).unwrap()),
315 )
316 .unwrap();
317 let ZZX = DensePolyRing::new(ZZ, "X");
318 let new_generating_poly = ZZX.from_terms(poly_ring.terms(generating_poly).map(|(c, i)| {
319 if i == rank {
320 (ZZ.one(), rank)
321 } else {
322 (
323 ZZ.checked_div(
324 &ZZ.mul_ref_fst(
325 &denominator,
326 ZZ.mul_ref_fst(QQ.get_ring().num(c), ZZ.pow(ZZ.clone_el(&scaled_lc), rank - i - 1)),
327 ),
328 QQ.get_ring().den(c),
329 )
330 .unwrap(),
331 i,
332 )
333 }
334 }));
335 return Self::try_new(ZZX, &new_generating_poly).map(|res| {
336 let root = res
337 .inclusion()
338 .mul_map(res.canonical_gen(), QQ.invert(&QQ.inclusion().map(scaled_lc)).unwrap());
339 return (res, root);
340 });
341 }
342
343 #[stability::unstable(feature = "enable")]
344 pub fn adjoin_root<P>(poly_ring: P, generating_poly: &El<P>) -> (Self, El<Self>)
345 where
346 P: RingStore,
347 P::Type: PolyRing,
348 <P::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<BigIntRing>>,
349 {
350 Self::try_adjoin_root(poly_ring, generating_poly).unwrap()
351 }
352}
353
354impl<Impl, I> NumberField<Impl, I>
355where
356 Impl: RingStore,
357 Impl::Type: Field + FreeAlgebra,
358 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
359 I: RingStore,
360 I::Type: IntegerRing,
361{
362 #[stability::unstable(feature = "enable")]
366 pub fn create(implementation: Impl) -> Self {
367 let poly_ring = DensePolyRing::new(implementation.base_ring(), "X");
368 let gen_poly = implementation.generating_poly(&poly_ring, poly_ring.base_ring().identity());
369 assert!(poly_ring.terms(&gen_poly).all(|(c, _)| {
370 poly_ring
371 .base_ring()
372 .base_ring()
373 .is_one(poly_ring.base_ring().get_ring().den(c))
374 }));
375 RingValue::from(NumberFieldBase { base: implementation })
376 }
377
378 #[stability::unstable(feature = "enable")]
379 pub fn into_choose_complex_embedding(self) -> ComplexEmbedding<Self, Impl, I> {
380 let ZZ = self.base_ring().base_ring();
381 let poly_ring = DensePolyRing::new(ZZ, "X");
382 let poly = self.get_ring().generating_poly_as_int(&poly_ring);
383 let (root, error) = find_approximate_complex_root(&poly_ring, &poly).unwrap();
384 return ComplexEmbedding {
385 from: self,
386 image_of_generator: root,
387 absolute_error_image_of_generator: error,
388 };
389 }
390
391 #[stability::unstable(feature = "enable")]
392 pub fn choose_complex_embedding<'a>(&'a self) -> ComplexEmbedding<&'a Self, Impl, I> {
393 let ZZ = self.base_ring().base_ring();
394 let poly_ring = DensePolyRing::new(ZZ, "X");
395 let poly = self.get_ring().generating_poly_as_int(&poly_ring);
396 let (root, error) = find_approximate_complex_root(&poly_ring, &poly).unwrap();
397 return ComplexEmbedding {
398 from: self,
399 image_of_generator: root,
400 absolute_error_image_of_generator: error,
401 };
402 }
403}
404
405impl<Impl, I> NumberFieldBase<Impl, I>
406where
407 Impl: RingStore,
408 Impl::Type: Field + FreeAlgebra,
409 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
410 I: RingStore,
411 I::Type: IntegerRing,
412{
413 fn generating_poly_as_int<'a>(&self, ZZX: &DensePolyRing<&'a I>) -> El<DensePolyRing<&'a I>> {
414 let ZZ = *ZZX.base_ring();
415 let assume_in_ZZ = LambdaHom::new(self.base_ring(), ZZ, |from, to, x| {
416 to.checked_div(from.get_ring().num(x), from.get_ring().den(x)).unwrap()
417 });
418 return self.base.generating_poly(ZZX, &assume_in_ZZ);
419 }
420}
421
422impl<Impl, I> Clone for NumberFieldBase<Impl, I>
423where
424 Impl: RingStore + Clone,
425 Impl::Type: Field + FreeAlgebra,
426 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
427 I: RingStore,
428 I::Type: IntegerRing,
429{
430 fn clone(&self) -> Self {
431 Self {
432 base: self.base.clone(),
433 }
434 }
435}
436
437impl<Impl, I> Copy for NumberFieldBase<Impl, I>
438where
439 Impl: RingStore + Copy,
440 Impl::Type: Field + FreeAlgebra,
441 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
442 I: RingStore,
443 I::Type: IntegerRing,
444 El<Impl>: Copy,
445 El<I>: Copy,
446{
447}
448
449impl<Impl, I> PartialEq for NumberFieldBase<Impl, I>
450where
451 Impl: RingStore,
452 Impl::Type: Field + FreeAlgebra,
453 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
454 I: RingStore,
455 I::Type: IntegerRing,
456{
457 fn eq(&self, other: &Self) -> bool { self.base.get_ring() == other.base.get_ring() }
458}
459
460impl<Impl, I> DelegateRing for NumberFieldBase<Impl, I>
461where
462 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 type Base = Impl::Type;
469 type Element = El<Impl>;
470
471 fn get_delegate(&self) -> &Self::Base { self.base.get_ring() }
472
473 fn delegate(&self, el: Self::Element) -> <Self::Base as RingBase>::Element { el }
474 fn delegate_mut<'a>(&self, el: &'a mut Self::Element) -> &'a mut <Self::Base as RingBase>::Element { el }
475 fn delegate_ref<'a>(&self, el: &'a Self::Element) -> &'a <Self::Base as RingBase>::Element { el }
476 fn rev_delegate(&self, el: <Self::Base as RingBase>::Element) -> Self::Element { el }
477}
478
479impl<Impl, I> DelegateRingImplEuclideanRing for NumberFieldBase<Impl, I>
480where
481 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}
488
489impl<Impl, I> Debug for NumberFieldBase<Impl, I>
490where
491 Impl: RingStore,
492 Impl::Type: Field + FreeAlgebra + Debug,
493 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
494 I: RingStore,
495 I::Type: IntegerRing,
496{
497 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "NumberField({:?})", self.base.get_ring()) }
498}
499
500impl<Impl, I> FiniteRingSpecializable for NumberFieldBase<Impl, I>
501where
502 Impl: RingStore,
503 Impl::Type: Field + FreeAlgebra,
504 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
505 I: RingStore,
506 I::Type: IntegerRing,
507{
508 fn specialize<O: FiniteRingOperation<Self>>(op: O) -> O::Output { op.fallback() }
509}
510
511impl<Impl, I> Field for NumberFieldBase<Impl, I>
512where
513 Impl: RingStore,
514 Impl::Type: Field + FreeAlgebra,
515 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
516 I: RingStore,
517 I::Type: IntegerRing,
518{
519}
520
521impl<Impl, I> PerfectField for NumberFieldBase<Impl, I>
522where
523 Impl: RingStore,
524 Impl::Type: Field + FreeAlgebra,
525 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
526 I: RingStore,
527 I::Type: IntegerRing,
528{
529}
530
531impl<Impl, I> Domain for NumberFieldBase<Impl, I>
532where
533 Impl: RingStore,
534 Impl::Type: Field + FreeAlgebra,
535 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
536 I: RingStore,
537 I::Type: IntegerRing,
538{
539}
540
541impl<Impl, I> PolyTFracGCDRing for NumberFieldBase<Impl, I>
542where
543 Impl: RingStore,
544 Impl::Type: Field + FreeAlgebra,
545 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
546 I: RingStore,
547 I::Type: IntegerRing,
548{
549 fn gcd<P>(poly_ring: P, lhs: &El<P>, rhs: &El<P>) -> El<P>
550 where
551 P: RingStore + Copy,
552 P::Type: PolyRing + DivisibilityRing,
553 <P::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
554 {
555 let self_ = NumberFieldByOrder {
556 base: RingRef::new(poly_ring.base_ring().get_ring()),
557 };
558
559 let order_poly_ring = DensePolyRing::new(RingRef::new(&self_), "X");
560 let lhs_order = self_.scale_poly_to_order(poly_ring, &order_poly_ring, lhs);
561 let rhs_order = self_.scale_poly_to_order(poly_ring, &order_poly_ring, rhs);
562
563 let result = poly_gcd_local(
564 &order_poly_ring,
565 order_poly_ring.clone_el(&lhs_order),
566 order_poly_ring.clone_el(&rhs_order),
567 DontObserve,
568 );
569
570 return self_.normalize_map_back_from_order(&order_poly_ring, poly_ring, &result);
571 }
572
573 fn power_decomposition<P>(poly_ring: P, poly: &El<P>) -> Vec<(El<P>, usize)>
574 where
575 P: RingStore + Copy,
576 P::Type: PolyRing + DivisibilityRing,
577 <P::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
578 {
579 let self_ = NumberFieldByOrder {
580 base: RingRef::new(poly_ring.base_ring().get_ring()),
581 };
582 let order_poly_ring = DensePolyRing::new(RingRef::new(&self_), "X");
583 let poly_order = self_.scale_poly_to_order(poly_ring, &order_poly_ring, poly);
584
585 let result = poly_power_decomposition_local(&order_poly_ring, poly_order, DontObserve);
586
587 return result
588 .into_iter()
589 .map(|(f, k)| (self_.normalize_map_back_from_order(&order_poly_ring, poly_ring, &f), k))
590 .collect();
591 }
592}
593
594enum HeuristicFactorPolyInOrderResult<P>
595where
596 P: RingStore,
597 P::Type: PolyRing,
598{
599 PartialFactorization(Vec<(El<P>, usize)>),
600 Irreducible,
601 Unknown,
602}
603
604fn heuristic_factor_poly_directly_in_order<'a, P, Impl, I, Controller>(
615 poly_ring: P,
616 poly: &El<P>,
617 controller: Controller,
618) -> HeuristicFactorPolyInOrderResult<P>
619where
620 Impl: 'a + RingStore,
621 Impl::Type: Field + FreeAlgebra,
622 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
623 I: 'a + RingStore,
624 I::Type: IntegerRing,
625 P: RingStore + Copy,
626 P::Type: PolyRing + DivisibilityRing,
627 <P::Type as RingExtension>::BaseRing: RingStore<Type = NumberFieldByOrder<'a, Impl, I>>,
628 Controller: ComputationController,
629{
630 controller.run_computation(
631 format_args!(
632 "factor_direct(deg={}, extdeg={})",
633 poly_ring.degree(poly).unwrap(),
634 poly_ring.base_ring().rank()
635 ),
636 |controller| {
637 let mut rng = oorandom::Rand64::new(1);
638 let self_ = poly_ring.base_ring();
639
640 'try_factor_directly: for _ in 0..TRY_FACTOR_DIRECTLY_ATTEMPTS {
643 let mut inert_prime = None;
644 for _ in 0..(TRY_FIND_INERT_PRIME_ATTEMPTS * self_.rank()) {
645 let p = self_.get_ring().random_suitable_ideal(|| rng.rand_u64());
646 if p.minpoly_factors_mod_p.len() == 1 {
647 inert_prime = Some(p);
648 break;
649 }
650 }
651 if let Some(p) = inert_prime {
652 log_progress!(
653 controller,
654 "(inert_prime={})",
655 IdealDisplayWrapper::new(self_.base_ring().base_ring().get_ring(), &p.prime)
656 );
657 let lc_poly = self_.clone_el(poly_ring.lc(poly).unwrap());
658 let monic_poly = evaluate_aX(poly_ring, poly, &lc_poly);
659 let e = 2 * self_.get_ring().heuristic_exponent(
660 &p,
661 poly_ring.degree(&monic_poly).unwrap(),
662 poly_ring.terms(&monic_poly).map(|(c, _)| c),
663 );
664 match factor_and_lift_mod_pe(poly_ring, &p, e, &monic_poly, controller.clone()) {
665 FactorAndLiftModpeResult::PartialFactorization(factorization) => {
666 log_progress!(controller, "(partial_success)");
667 debug_assert!(
668 poly_ring.eq_el(
669 &monic_poly,
670 &poly_ring
671 .normalize(poly_ring.prod(factorization.iter().map(|f| poly_ring.clone_el(f))))
672 )
673 );
674 let result: Vec<_> = factorization
675 .into_iter()
676 .map(|f| (unevaluate_aX(poly_ring, &f, &lc_poly), 1))
677 .collect();
678 debug_assert!(
679 poly_ring.eq_el(
680 &poly_ring.normalize(poly_ring.clone_el(poly)),
681 &poly_ring.normalize(poly_ring.prod(
682 result.iter().map(|(f, e)| { poly_ring.pow(poly_ring.clone_el(f), *e) })
683 ))
684 )
685 );
686 return HeuristicFactorPolyInOrderResult::PartialFactorization(result);
687 }
688 FactorAndLiftModpeResult::Irreducible => {
689 return HeuristicFactorPolyInOrderResult::Irreducible;
690 }
691 FactorAndLiftModpeResult::NotSquarefreeModpe => {
692 let power_decomposition =
694 poly_power_decomposition_local(poly_ring, poly_ring.clone_el(poly), controller.clone());
695 if power_decomposition.len() > 1 {
696 log_progress!(controller, "(partial_success)");
697 return HeuristicFactorPolyInOrderResult::PartialFactorization(power_decomposition);
698 }
699 }
700 FactorAndLiftModpeResult::Unknown => {}
701 }
702 } else {
703 break 'try_factor_directly;
704 }
705 }
706 log_progress!(controller, "(fail)");
707 return HeuristicFactorPolyInOrderResult::Unknown;
708 },
709 )
710}
711
712impl<Impl, I> FactorPolyField for NumberFieldBase<Impl, I>
713where
714 Impl: RingStore,
715 Impl::Type: Field + FreeAlgebra,
716 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
717 I: RingStore,
718 I::Type: IntegerRing + ComputeResultantRing,
719{
720 fn factor_poly<P>(poly_ring: P, poly: &El<P>) -> (Vec<(El<P>, usize)>, Self::Element)
721 where
722 P: RingStore + Copy,
723 P::Type: PolyRing + EuclideanRing,
724 <P::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
725 {
726 Self::factor_poly_with_controller(poly_ring, poly, DontObserve)
727 }
728
729 fn factor_poly_with_controller<P, Controller>(
730 poly_ring: P,
731 poly: &El<P>,
732 controller: Controller,
733 ) -> (Vec<(El<P>, usize)>, Self::Element)
734 where
735 P: RingStore + Copy,
736 P::Type: PolyRing + EuclideanRing,
737 <P::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
738 Controller: ComputationController,
739 {
740 let self_ = NumberFieldByOrder {
741 base: RingRef::new(poly_ring.base_ring().get_ring()),
742 };
743 let order_poly_ring = DensePolyRing::new(RingRef::new(&self_), "X");
744
745 let mut to_factor = vec![(poly_ring.clone_el(poly), 1)];
746 let mut result = Vec::new();
747 while let Some((current, e_base)) = to_factor.pop() {
748 if poly_ring.degree(¤t).unwrap() == 1 {
749 result.push((poly_ring.normalize(current), 1));
750 } else {
751 let poly_order = self_.scale_poly_to_order(poly_ring, &order_poly_ring, ¤t);
752 match heuristic_factor_poly_directly_in_order(&order_poly_ring, &poly_order, controller.clone()) {
754 HeuristicFactorPolyInOrderResult::PartialFactorization(partial_factorization) => {
755 to_factor.extend(partial_factorization.into_iter().map(|(f, e)| {
756 (
757 self_.normalize_map_back_from_order(&order_poly_ring, poly_ring, &f),
758 e * e_base,
759 )
760 }))
761 }
762 HeuristicFactorPolyInOrderResult::Irreducible => result.push((current, e_base)),
763 HeuristicFactorPolyInOrderResult::Unknown => result.extend(
764 poly_factor_extension(&poly_ring, ¤t, controller.clone())
765 .0
766 .into_iter()
767 .map(|(f, e)| (f, e * e_base)),
768 ),
769 }
770 }
771 }
772 return (result, poly_ring.base_ring().clone_el(poly_ring.lc(poly).unwrap()));
773 }
774}
775
776struct NumberFieldByOrder<'a, Impl, I>
785where
786 Impl: RingStore,
787 Impl::Type: Field + FreeAlgebra,
788 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
789 I: RingStore,
790 I::Type: IntegerRing,
791{
792 base: RingRef<'a, NumberFieldBase<Impl, I>>,
793}
794
795impl<'a, Impl, I> NumberFieldByOrder<'a, Impl, I>
796where
797 Impl: RingStore,
798 Impl::Type: Field + FreeAlgebra,
799 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
800 I: RingStore,
801 I::Type: IntegerRing,
802{
803 fn scale_poly_to_order<'ring, P1, P2>(&self, from: P1, to: P2, poly: &El<P1>) -> El<P2>
806 where
807 P1: RingStore,
808 P1::Type: PolyRing,
809 <P1::Type as RingExtension>::BaseRing: RingStore<Type = NumberFieldBase<Impl, I>>,
810 P2: RingStore,
811 P2::Type: PolyRing,
812 <P2::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
813 Self: 'ring,
814 {
815 debug_assert!(self.base.get_ring() == from.base_ring().get_ring());
816 debug_assert!(self.base.get_ring() == to.base_ring().get_ring().base.get_ring());
817 let QQ = self.base.base_ring();
818 let ZZ = QQ.base_ring();
819 let denominator = QQ.inclusion().map(
820 from.terms(poly)
821 .map(|(c, _)| {
822 self.base
823 .wrt_canonical_basis(c)
824 .iter()
825 .map(|c| ZZ.clone_el(QQ.get_ring().den(&c)))
826 .fold(ZZ.one(), |a, b| signed_lcm(a, b, ZZ))
827 })
828 .fold(ZZ.one(), |a, b| signed_lcm(a, b, ZZ)),
829 );
830 debug_assert!(!QQ.is_zero(&denominator));
831 return to.from_terms(
832 from.terms(poly)
833 .map(|(c, i)| (self.base.inclusion().mul_ref_map(c, &denominator), i)),
834 );
835 }
836
837 fn normalize_map_back_from_order<'ring, P1, P2>(&self, from: P1, to: P2, poly: &El<P1>) -> El<P2>
838 where
839 P1: RingStore,
840 P1::Type: PolyRing,
841 <P1::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
842 P2: RingStore,
843 P2::Type: PolyRing,
844 <P2::Type as RingExtension>::BaseRing: RingStore<Type = NumberFieldBase<Impl, I>>,
845 Self: 'ring,
846 {
847 debug_assert!(self.base.get_ring() == to.base_ring().get_ring());
848 debug_assert!(self.base.get_ring() == from.base_ring().get_ring().base.get_ring());
849 let result = to.from_terms(from.terms(poly).map(|(c, i)| (self.clone_el(c), i)));
850 return to.normalize(result);
851 }
852}
853
854impl<'a, Impl, I> PartialEq for NumberFieldByOrder<'a, Impl, I>
855where
856 Impl: RingStore,
857 Impl::Type: Field + FreeAlgebra,
858 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
859 I: RingStore,
860 I::Type: IntegerRing,
861{
862 fn eq(&self, other: &Self) -> bool { self.base.get_ring() == other.base.get_ring() }
863}
864
865impl<'a, Impl, I> FiniteRingSpecializable for NumberFieldByOrder<'a, Impl, I>
866where
867 Impl: RingStore,
868 Impl::Type: Field + FreeAlgebra,
869 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
870 I: RingStore,
871 I::Type: IntegerRing,
872{
873 fn specialize<O: FiniteRingOperation<Self>>(op: O) -> O::Output { op.fallback() }
874}
875
876impl<'a, Impl, I> DelegateRing for NumberFieldByOrder<'a, Impl, I>
877where
878 Impl: RingStore,
879 Impl::Type: Field + FreeAlgebra,
880 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
881 I: RingStore,
882 I::Type: IntegerRing,
883{
884 type Base = Impl::Type;
885 type Element = El<Impl>;
886
887 fn get_delegate(&self) -> &Self::Base { self.base.get_ring().base.get_ring() }
888
889 fn delegate(&self, el: Self::Element) -> <Self::Base as RingBase>::Element { el }
890 fn delegate_mut<'b>(&self, el: &'b mut Self::Element) -> &'b mut <Self::Base as RingBase>::Element { el }
891 fn delegate_ref<'b>(&self, el: &'b Self::Element) -> &'b <Self::Base as RingBase>::Element { el }
892 fn rev_delegate(&self, el: <Self::Base as RingBase>::Element) -> Self::Element { el }
893}
894
895impl<'a, Impl, I> Domain for NumberFieldByOrder<'a, Impl, I>
896where
897 Impl: RingStore,
898 Impl::Type: Field + FreeAlgebra,
899 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
900 I: RingStore,
901 I::Type: IntegerRing,
902{
903}
904
905type LocalRing<'ring, I> = <<I as RingStore>::Type as PolyGCDLocallyDomain>::LocalRing<'ring>;
906
907type ImplementationRing<'ring, I> = AsFieldBase<
908 FreeAlgebraImpl<
909 AsField<<<I as RingStore>::Type as IntegerPolyGCDRing>::LocalRingAsZn<'ring>>,
910 SparseMapVector<AsField<<<I as RingStore>::Type as IntegerPolyGCDRing>::LocalRingAsZn<'ring>>>,
911 >,
912>;
913
914struct NumberFieldOrderQuotient<'ring, I>
915where
916 I: 'ring + RingStore,
917 I::Type: IntegerRing,
918{
919 implementation: RingValue<ImplementationRing<'ring, I>>,
920}
921
922impl<'ring, I> Clone for NumberFieldOrderQuotient<'ring, I>
923where
924 I: 'ring + RingStore,
925 I::Type: IntegerRing,
926{
927 fn clone(&self) -> Self {
928 Self {
929 implementation: self.implementation.clone(),
930 }
931 }
932}
933
934impl<'ring, I> PartialEq for NumberFieldOrderQuotient<'ring, I>
935where
936 I: 'ring + RingStore,
937 I::Type: IntegerRing,
938{
939 fn eq(&self, other: &Self) -> bool { self.implementation.get_ring() == other.implementation.get_ring() }
940}
941
942impl<'ring, I> DelegateRing for NumberFieldOrderQuotient<'ring, I>
943where
944 I: 'ring + RingStore,
945 I::Type: IntegerRing,
946{
947 type Base = ImplementationRing<'ring, I>;
948 type Element = <ImplementationRing<'ring, I> as RingBase>::Element;
949
950 fn get_delegate(&self) -> &Self::Base { self.implementation.get_ring() }
951
952 fn delegate(&self, el: Self::Element) -> <Self::Base as RingBase>::Element { el }
953 fn delegate_mut<'b>(&self, el: &'b mut Self::Element) -> &'b mut <Self::Base as RingBase>::Element { el }
954 fn delegate_ref<'b>(&self, el: &'b Self::Element) -> &'b <Self::Base as RingBase>::Element { el }
955 fn rev_delegate(&self, el: <Self::Base as RingBase>::Element) -> Self::Element { el }
956}
957
958impl<'ring, I> Domain for NumberFieldOrderQuotient<'ring, I>
959where
960 I: 'ring + RingStore,
961 I::Type: IntegerRing,
962{
963}
964
965impl<'ring, I> DelegateRingImplEuclideanRing for NumberFieldOrderQuotient<'ring, I>
966where
967 I: 'ring + RingStore,
968 I::Type: IntegerRing,
969{
970}
971
972impl<'ring, I> Field for NumberFieldOrderQuotient<'ring, I>
973where
974 I: 'ring + RingStore,
975 I::Type: IntegerRing,
976{
977}
978
979impl<'ring, I> DelegateRingImplFiniteRing for NumberFieldOrderQuotient<'ring, I>
980where
981 I: 'ring + RingStore,
982 I::Type: IntegerRing,
983{
984}
985
986impl<'ring, I> CanHomFrom<Self> for NumberFieldOrderQuotient<'ring, I>
987where
988 I: 'ring + RingStore,
989 I::Type: IntegerRing,
990{
991 type Homomorphism = ();
992
993 fn has_canonical_hom(&self, from: &Self) -> Option<Self::Homomorphism> {
994 if self == from { Some(()) } else { None }
995 }
996
997 fn map_in(&self, _from: &Self, el: <Self as RingBase>::Element, _hom: &Self::Homomorphism) -> Self::Element { el }
998}
999
1000impl<'ring, I> CanIsoFromTo<Self> for NumberFieldOrderQuotient<'ring, I>
1001where
1002 I: 'ring + RingStore,
1003 I::Type: IntegerRing,
1004{
1005 type Isomorphism = <Self as CanHomFrom<Self>>::Homomorphism;
1006
1007 fn has_canonical_iso(&self, from: &Self) -> Option<Self::Isomorphism> { from.has_canonical_hom(self) }
1008
1009 fn map_out(&self, from: &Self, el: Self::Element, iso: &Self::Isomorphism) -> <Self as RingBase>::Element {
1010 from.map_in(self, el, iso)
1011 }
1012}
1013
1014pub struct NumberRingIdeal<'ring, I>
1019where
1020 I: RingStore,
1021 I::Type: IntegerRing,
1022 I: 'ring,
1023{
1024 prime: <I::Type as PolyGCDLocallyDomain>::SuitableIdeal<'ring>,
1025 ZZX: DensePolyRing<&'ring I>,
1026 number_field_poly: El<DensePolyRing<&'ring I>>,
1027 FpX: DensePolyRing<<I::Type as PolyGCDLocallyDomain>::LocalField<'ring>>,
1028 Fp_as_ring: <I::Type as PolyGCDLocallyDomain>::LocalRing<'ring>,
1029 Fp_as_zn: AsField<<I::Type as IntegerPolyGCDRing>::LocalRingAsZn<'ring>>,
1030 minpoly_factors_mod_p: Vec<El<DensePolyRing<<I::Type as PolyGCDLocallyDomain>::LocalField<'ring>>>>,
1031}
1032
1033impl<'ring, I> NumberRingIdeal<'ring, I>
1034where
1035 I: RingStore,
1036 I::Type: IntegerRing,
1037 I: 'ring,
1038{
1039 fn lifted_factorization<'a>(
1040 &'a self,
1041 e: usize,
1042 ) -> (
1043 DensePolyRing<<I::Type as PolyGCDLocallyDomain>::LocalRing<'ring>>,
1044 Vec<El<DensePolyRing<<I::Type as PolyGCDLocallyDomain>::LocalRing<'ring>>>>,
1045 ) {
1046 let ZZX = &self.ZZX;
1047 let ZZ = ZZX.base_ring();
1048 let ZpeX = DensePolyRing::new(ZZ.get_ring().local_ring_at(&self.prime, e, 0), "X");
1049 let Zpe = ZpeX.base_ring();
1050 let FpX = &self.FpX;
1051 let Zpe_to_Fp =
1052 PolyGCDLocallyIntermediateReductionMap::new(ZZ.get_ring(), &self.prime, Zpe, e, &self.Fp_as_ring, 1, 0);
1053 let ZZ_to_Zpe = PolyGCDLocallyReductionMap::new(ZZ.get_ring(), &self.prime, Zpe, e, 0);
1054
1055 let factors = hensel::hensel_lift_factorization(
1056 &Zpe_to_Fp,
1057 &ZpeX,
1058 FpX,
1059 &ZpeX.lifted_hom(ZZX, ZZ_to_Zpe).map_ref(&self.number_field_poly),
1060 &self.minpoly_factors_mod_p[..],
1061 DontObserve,
1062 );
1063
1064 return (ZpeX, factors);
1065 }
1066}
1067
1068impl<'ring, I> Debug for NumberRingIdeal<'ring, I>
1069where
1070 I: RingStore,
1071 I::Type: IntegerRing,
1072 I: 'ring,
1073 <I::Type as PolyGCDLocallyDomain>::SuitableIdeal<'ring>: Debug,
1074{
1075 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1076 f.debug_struct("NumberRingIdeal").field("prime", &self.prime).finish()
1077 }
1078}
1079
1080impl<'a, Impl, I> PolyGCDLocallyDomain for NumberFieldByOrder<'a, Impl, I>
1081where
1082 Impl: RingStore,
1083 Impl::Type: Field + FreeAlgebra,
1084 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
1085 I: RingStore,
1086 I::Type: IntegerRing,
1087{
1088 type LocalRingBase<'ring>
1089 = FreeAlgebraImplBase<LocalRing<'ring, I>, SparseMapVector<LocalRing<'ring, I>>>
1090 where
1091 Self: 'ring;
1092
1093 type LocalRing<'ring>
1094 = RingValue<Self::LocalRingBase<'ring>>
1095 where
1096 Self: 'ring;
1097
1098 type LocalFieldBase<'ring>
1099 = NumberFieldOrderQuotient<'ring, I>
1100 where
1101 Self: 'ring;
1102
1103 type LocalField<'ring>
1104 = RingValue<Self::LocalFieldBase<'ring>>
1105 where
1106 Self: 'ring;
1107
1108 type SuitableIdeal<'ring>
1109 = NumberRingIdeal<'ring, I>
1110 where
1111 Self: 'ring;
1112
1113 fn maximal_ideal_factor_count<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>) -> usize
1114 where
1115 Self: 'ring,
1116 {
1117 ideal.minpoly_factors_mod_p.len()
1118 }
1119
1120 fn heuristic_exponent<'ring, 'b, J>(
1121 &self,
1122 ideal: &Self::SuitableIdeal<'ring>,
1123 poly_deg: usize,
1124 coefficients: J,
1125 ) -> usize
1126 where
1127 J: Iterator<Item = &'b Self::Element>,
1128 Self: 'b,
1129 Self: 'ring,
1130 {
1131 const HEURISTIC_FACTOR_SIZE_OVER_POLY_SIZE_FACTOR: f64 = 0.25;
1132
1133 let QQ = self.base.base_ring();
1134 let ZZ = QQ.base_ring();
1135 let log2_max_coeff = coefficients
1139 .map(|c| {
1140 self.base
1141 .wrt_canonical_basis(c)
1142 .iter()
1143 .map(|c| ZZ.abs_log2_ceil(QQ.get_ring().num(&c)).unwrap_or(0))
1144 .max()
1145 .unwrap()
1146 })
1147 .max()
1148 .unwrap_or(0);
1149 let log2_p = BigIntRing::RING
1150 .to_float_approx(&ZZ.get_ring().principal_ideal_generator(&ideal.prime))
1151 .log2();
1152 return ((log2_max_coeff as f64 + poly_deg as f64 + (self.rank() as f64).log2()) / log2_p
1153 * HEURISTIC_FACTOR_SIZE_OVER_POLY_SIZE_FACTOR)
1154 .ceil() as usize
1155 + 1;
1156 }
1157
1158 fn random_suitable_ideal<'ring, F>(&'ring self, mut rng: F) -> Self::SuitableIdeal<'ring>
1159 where
1160 F: FnMut() -> u64,
1161 {
1162 let QQ = self.base.base_ring();
1163 let ZZ = QQ.base_ring();
1164 let ZZX = DensePolyRing::new(ZZ, "X");
1165 let gen_poly = self.base.generating_poly(
1166 &ZZX,
1167 LambdaHom::new(QQ, ZZ, |QQ, ZZ, x| {
1168 assert!(ZZ.is_one(QQ.get_ring().den(x)));
1169 ZZ.clone_el(QQ.get_ring().num(x))
1170 }),
1171 );
1172
1173 for _ in 0..MAX_PROBABILISTIC_REPETITIONS {
1175 let p = ZZ.get_ring().random_suitable_ideal(&mut rng);
1176 assert_eq!(1, ZZ.get_ring().maximal_ideal_factor_count(&p));
1177
1178 let Fp_as_ring = ZZ.get_ring().local_ring_at(&p, 1, 0);
1179 let FpX = DensePolyRing::new(ZZ.get_ring().local_field_at(&p, 0), "X");
1180 let Fp = FpX.base_ring();
1181 let ZZ_to_Fp = LambdaHom::new(ZZ, Fp, |ZZ, Fp, x| {
1182 ZZ.get_ring().base_ring_to_field(
1183 &p,
1184 Fp_as_ring.get_ring(),
1185 Fp.get_ring(),
1186 0,
1187 ZZ.get_ring()
1188 .reduce_ring_el(&p, (Fp_as_ring.get_ring(), 1), 0, ZZ.clone_el(x)),
1189 )
1190 });
1191
1192 let gen_poly_mod_p = FpX.from_terms(ZZX.terms(&gen_poly).map(|(c, i)| (ZZ_to_Fp.map_ref(c), i)));
1193 let (factorization, _) = <_ as FactorPolyField>::factor_poly(&FpX, &gen_poly_mod_p);
1194 if factorization.iter().all(|(_, e)| *e == 1) {
1195 return NumberRingIdeal {
1196 minpoly_factors_mod_p: factorization.into_iter().map(|(f, _)| f).collect(),
1197 number_field_poly: gen_poly,
1198 FpX,
1199 ZZX,
1200 Fp_as_zn: ZZ
1201 .get_ring()
1202 .local_ring_into_zn(Fp_as_ring.clone())
1203 .as_field()
1204 .ok()
1205 .unwrap(),
1206 Fp_as_ring,
1207 prime: p,
1208 };
1209 }
1210 }
1211 unreachable!()
1212 }
1213
1214 fn local_field_at<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, idx: usize) -> Self::LocalField<'ring>
1215 where
1216 Self: 'ring,
1217 {
1218 assert!(idx < self.maximal_ideal_factor_count(ideal));
1219 let QQ = self.base.base_ring();
1220 let ZZ = QQ.base_ring();
1221 assert_eq!(1, ZZ.get_ring().maximal_ideal_factor_count(&ideal.prime));
1222 let FpX = &ideal.FpX;
1223 let Fp_to_Fp = WrapHom::to_delegate_ring(ideal.Fp_as_zn.get_ring())
1224 .compose(
1225 RingRef::new(ideal.Fp_as_zn.get_ring().get_delegate())
1226 .into_can_hom(&ideal.Fp_as_ring)
1227 .ok()
1228 .unwrap(),
1229 )
1230 .compose(
1231 PolyGCDLocallyBaseRingToFieldIso::new(
1232 ZZ.get_ring(),
1233 &ideal.prime,
1234 ideal.Fp_as_ring.get_ring(),
1235 FpX.base_ring().get_ring(),
1236 0,
1237 )
1238 .inv(),
1239 );
1240
1241 let irred_poly = &ideal.minpoly_factors_mod_p[idx];
1242 let mut x_pow_rank = SparseMapVector::new(FpX.degree(irred_poly).unwrap(), ideal.Fp_as_zn.clone());
1243 for (c, i) in FpX.terms(irred_poly) {
1244 if i < x_pow_rank.len() {
1245 *x_pow_rank.at_mut(i) = Fp_to_Fp.codomain().negate(Fp_to_Fp.map_ref(c));
1246 }
1247 }
1248 _ = x_pow_rank.at_mut(0);
1249 return RingValue::from(NumberFieldOrderQuotient {
1250 implementation: AsField::from(AsFieldBase::promise_is_perfect_field(FreeAlgebraImpl::new(
1251 ideal.Fp_as_zn.clone(),
1252 FpX.degree(irred_poly).unwrap(),
1253 x_pow_rank,
1254 ))),
1255 });
1256 }
1257
1258 fn local_ring_at<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, e: usize, idx: usize) -> Self::LocalRing<'ring>
1259 where
1260 Self: 'ring,
1261 {
1262 assert!(idx < self.maximal_ideal_factor_count(ideal));
1263 let QQ = self.base.base_ring();
1264 let ZZ = QQ.base_ring();
1265 let (ZpeX, factors) = ideal.lifted_factorization(e);
1266 let Zpe = ZZ.get_ring().local_ring_at(&ideal.prime, e, 0);
1267 assert!(Zpe.get_ring() == ZpeX.base_ring().get_ring());
1268
1269 let irred_poly = &factors[idx];
1270 let degree = ZpeX.degree(irred_poly).unwrap();
1271 let mut x_pow_rank = SparseMapVector::new(degree, Zpe.clone());
1272 for (c, i) in ZpeX.terms(irred_poly) {
1273 if i < x_pow_rank.len() {
1274 *x_pow_rank.at_mut(i) = Zpe.negate(Zpe.clone_el(c));
1275 }
1276 }
1277 _ = x_pow_rank.at_mut(0);
1278 return FreeAlgebraImpl::new(Zpe, degree, x_pow_rank);
1279 }
1280
1281 fn reduce_ring_el<'ring>(
1282 &self,
1283 ideal: &Self::SuitableIdeal<'ring>,
1284 to: (&Self::LocalRingBase<'ring>, usize),
1285 idx: usize,
1286 x: Self::Element,
1287 ) -> El<Self::LocalRing<'ring>>
1288 where
1289 Self: 'ring,
1290 {
1291 assert!(idx < self.maximal_ideal_factor_count(ideal));
1292 let QQ = self.base.base_ring();
1293 let ZZ = QQ.base_ring();
1294 let ZZX = &ideal.ZZX;
1295 let partial_QQ_to_ZZ = LambdaHom::new(QQ, ZZ, |QQ, ZZ, x| {
1296 assert!(ZZ.is_one(QQ.get_ring().den(x)));
1297 ZZ.clone_el(QQ.get_ring().num(x))
1298 });
1299 let ZZ_to_Zpe = PolyGCDLocallyReductionMap::new(ZZ.get_ring(), &ideal.prime, to.0.base_ring(), to.1, 0);
1300
1301 ZZX.evaluate(
1302 &self.base.poly_repr(ZZX, &x, partial_QQ_to_ZZ),
1303 &to.0.canonical_gen(),
1304 RingRef::new(to.0).into_inclusion().compose(ZZ_to_Zpe),
1305 )
1306 }
1307
1308 fn base_ring_to_field<'ring>(
1309 &self,
1310 ideal: &Self::SuitableIdeal<'ring>,
1311 from: &Self::LocalRingBase<'ring>,
1312 to: &Self::LocalFieldBase<'ring>,
1313 idx: usize,
1314 x: El<Self::LocalRing<'ring>>,
1315 ) -> El<Self::LocalField<'ring>>
1316 where
1317 Self: 'ring,
1318 {
1319 assert!(idx < self.maximal_ideal_factor_count(ideal));
1320 let hom = WrapHom::to_delegate_ring(to.base_ring().get_ring()).compose(
1321 RingRef::new(to.base_ring().get_ring().get_delegate())
1322 .into_can_hom(from.base_ring())
1323 .ok()
1324 .unwrap(),
1325 );
1326 to.from_canonical_basis(from.wrt_canonical_basis(&x).iter().map(|c| hom.map(c)))
1327 }
1328
1329 fn field_to_base_ring<'ring>(
1330 &self,
1331 ideal: &Self::SuitableIdeal<'ring>,
1332 from: &Self::LocalFieldBase<'ring>,
1333 to: &Self::LocalRingBase<'ring>,
1334 idx: usize,
1335 x: El<Self::LocalField<'ring>>,
1336 ) -> El<Self::LocalRing<'ring>>
1337 where
1338 Self: 'ring,
1339 {
1340 assert!(idx < self.maximal_ideal_factor_count(ideal));
1341 assert!(idx < self.maximal_ideal_factor_count(ideal));
1342 let hom = RingRef::new(from.base_ring().get_ring().get_delegate())
1343 .into_can_iso(to.base_ring())
1344 .ok()
1345 .unwrap()
1346 .compose(UnwrapHom::from_delegate_ring(from.base_ring().get_ring()));
1347 to.from_canonical_basis(from.wrt_canonical_basis(&x).iter().map(|c| hom.map(c)))
1348 }
1349
1350 fn reduce_partial<'ring>(
1351 &self,
1352 ideal: &Self::SuitableIdeal<'ring>,
1353 from: (&Self::LocalRingBase<'ring>, usize),
1354 to: (&Self::LocalRingBase<'ring>, usize),
1355 idx: usize,
1356 x: El<Self::LocalRing<'ring>>,
1357 ) -> El<Self::LocalRing<'ring>>
1358 where
1359 Self: 'ring,
1360 {
1361 assert!(idx < self.maximal_ideal_factor_count(ideal));
1362 let QQ = self.base.base_ring();
1363 let ZZ = QQ.base_ring();
1364 to.0.from_canonical_basis(from.0.wrt_canonical_basis(&x).iter().map(|c| {
1365 ZZ.get_ring().reduce_partial(
1366 &ideal.prime,
1367 (from.0.base_ring().get_ring(), from.1),
1368 (to.0.base_ring().get_ring(), to.1),
1369 0,
1370 c,
1371 )
1372 }))
1373 }
1374
1375 fn lift_partial<'ring>(
1376 &self,
1377 ideal: &Self::SuitableIdeal<'ring>,
1378 from: (&Self::LocalRingBase<'ring>, usize),
1379 to: (&Self::LocalRingBase<'ring>, usize),
1380 idx: usize,
1381 x: El<Self::LocalRing<'ring>>,
1382 ) -> El<Self::LocalRing<'ring>>
1383 where
1384 Self: 'ring,
1385 {
1386 assert!(idx < self.maximal_ideal_factor_count(ideal));
1387 let QQ = self.base.base_ring();
1388 let ZZ = QQ.base_ring();
1389 to.0.from_canonical_basis(from.0.wrt_canonical_basis(&x).iter().map(|c| {
1390 ZZ.get_ring().lift_partial(
1391 &ideal.prime,
1392 (from.0.base_ring().get_ring(), from.1),
1393 (to.0.base_ring().get_ring(), to.1),
1394 0,
1395 c,
1396 )
1397 }))
1398 }
1399
1400 fn reconstruct_ring_el<'local, 'element, 'ring, V1, V2>(
1401 &self,
1402 ideal: &Self::SuitableIdeal<'ring>,
1403 from: V1,
1404 e: usize,
1405 x: V2,
1406 ) -> Self::Element
1407 where
1408 Self: 'ring,
1409 V1: VectorFn<&'local Self::LocalRing<'ring>>,
1410 V2: VectorFn<&'element El<Self::LocalRing<'ring>>>,
1411 Self::LocalRing<'ring>: 'local,
1412 El<Self::LocalRing<'ring>>: 'element,
1413 'ring: 'local + 'element,
1414 {
1415 assert_eq!(self.maximal_ideal_factor_count(ideal), from.len());
1416 assert_eq!(self.maximal_ideal_factor_count(ideal), x.len());
1417 let QQ = self.base.base_ring();
1418 let ZZ = QQ.base_ring();
1419 let Zpe = from.at(0).base_ring();
1420 assert!(from.iter().all(|ring| ring.base_ring().get_ring() == Zpe.get_ring()));
1421 let ZpeX = DensePolyRing::new(Zpe, "X");
1422 let ZZ_to_Zpe = PolyGCDLocallyReductionMap::new(ZZ.get_ring(), &ideal.prime, Zpe, e, 0);
1423
1424 let mut unit_vectors = (0..self.maximal_ideal_factor_count(ideal))
1426 .map(|_| ZpeX.zero())
1427 .collect::<Vec<_>>();
1428 product_except_one(
1429 &ZpeX,
1430 (&from).map_fn(|galois_ring| galois_ring.generating_poly(&ZpeX, Zpe.identity())),
1431 &mut unit_vectors,
1432 );
1433 let complete_product = ZpeX.mul_ref_fst(&unit_vectors[0], from.at(0).generating_poly(&ZpeX, Zpe.identity()));
1434 assert_el_eq!(
1435 &ZpeX,
1436 &complete_product,
1437 &self.base.generating_poly(
1438 &ZpeX,
1439 ZZ_to_Zpe.compose(LambdaHom::new(QQ, ZZ, |QQ, ZZ, x| {
1440 assert!(ZZ.is_one(QQ.get_ring().den(x)));
1441 ZZ.clone_el(QQ.get_ring().num(x))
1442 }))
1443 )
1444 );
1445
1446 for i in 0..self.maximal_ideal_factor_count(ideal) {
1447 let galois_ring = from.at(i);
1448 let inv_normalization_factor = ZpeX.evaluate(
1449 unit_vectors.at(i),
1450 &galois_ring.canonical_gen(),
1451 galois_ring.inclusion(),
1452 );
1453 let normalization_factor = galois_ring.invert(&inv_normalization_factor).unwrap();
1454 let lifted_normalization_factor = galois_ring.poly_repr(&ZpeX, &normalization_factor, Zpe.identity());
1455 let unreduced_new_unit_vector = ZpeX.mul(
1456 std::mem::replace(&mut unit_vectors[i], ZpeX.zero()),
1457 lifted_normalization_factor,
1458 );
1459 unit_vectors[i] = ZpeX.div_rem_monic(unreduced_new_unit_vector, &complete_product).1;
1460 }
1461
1462 let combined = <_ as RingStore>::sum(
1464 &ZpeX,
1465 (0..self.maximal_ideal_factor_count(ideal)).map(|i| {
1466 let galois_ring = from.at(i);
1467 let unreduced_result =
1468 ZpeX.mul_ref_snd(galois_ring.poly_repr(&ZpeX, x.at(i), Zpe.identity()), &unit_vectors[i]);
1469 ZpeX.div_rem_monic(unreduced_result, &complete_product).1
1470 }),
1471 );
1472
1473 for i in 0..self.maximal_ideal_factor_count(ideal) {
1474 let galois_ring = from.at(i);
1475 debug_assert!(galois_ring.eq_el(
1476 x.at(i),
1477 &ZpeX.evaluate(&combined, &galois_ring.canonical_gen(), galois_ring.inclusion())
1478 ));
1479 }
1480
1481 let Zpe_as_zn = ZZ.get_ring().local_ring_as_zn(Zpe);
1483 let Zpe_to_as_zn = Zpe_as_zn.can_hom(Zpe).unwrap();
1484 let result = self.from_canonical_basis((0..self.rank()).map(|i| {
1485 let (num, den) =
1486 balanced_rational_reconstruction(Zpe_as_zn, Zpe_to_as_zn.map_ref(ZpeX.coefficient_at(&combined, i)));
1487 return QQ.div(
1488 &QQ.inclusion().map(int_cast(num, ZZ, Zpe_as_zn.integer_ring())),
1489 &QQ.inclusion().map(int_cast(den, ZZ, Zpe_as_zn.integer_ring())),
1490 );
1491 }));
1492 return result;
1493 }
1494
1495 fn dbg_ideal<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, out: &mut std::fmt::Formatter) -> std::fmt::Result
1496 where
1497 Self: 'ring,
1498 {
1499 let QQ = self.base.base_ring();
1500 QQ.base_ring().get_ring().dbg_ideal(&ideal.prime, out)
1501 }
1502}
1503
1504impl<Impl, I> Serialize for NumberFieldBase<Impl, I>
1505where
1506 Impl: RingStore + Serialize,
1507 Impl::Type: Field + FreeAlgebra + SerializableElementRing,
1508 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
1509 I: RingStore,
1510 I::Type: IntegerRing,
1511{
1512 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1513 where
1514 S: Serializer,
1515 {
1516 SerializableNewtypeStruct::new("NumberField", &self.base).serialize(serializer)
1517 }
1518}
1519
1520impl<'de, Impl, I> Deserialize<'de> for NumberFieldBase<Impl, I>
1521where
1522 Impl: RingStore + Deserialize<'de>,
1523 Impl::Type: Field + FreeAlgebra + SerializableElementRing,
1524 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
1525 I: RingStore,
1526 I::Type: IntegerRing,
1527{
1528 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1529 where
1530 D: Deserializer<'de>,
1531 {
1532 DeserializeSeedNewtypeStruct::new("NumberField", PhantomData::<Impl>)
1533 .deserialize(deserializer)
1534 .map(|res| NumberField::create(res).into())
1535 }
1536}
1537
1538#[cfg(test)]
1539use crate::RANDOM_TEST_INSTANCE_COUNT;
1540#[cfg(test)]
1541use crate::iters::multi_cartesian_product;
1542
1543#[test]
1544fn test_principal_ideal_ring_axioms() {
1545 let ZZ = BigIntRing::RING;
1546 let ZZX = DensePolyRing::new(ZZ, "X");
1547
1548 let [f] = ZZX.with_wrapped_indeterminate(|X| [X.pow_ref(2) + 1]);
1549 let K = NumberField::new(&ZZX, &f);
1550
1551 let elements = multi_cartesian_product(
1552 [(-4..4), (-2..2)].into_iter(),
1553 |slice| K.from_canonical_basis(slice.iter().map(|x| K.base_ring().int_hom().map(*x))),
1554 |_, x| *x,
1555 )
1556 .collect::<Vec<_>>();
1557
1558 crate::pid::generic_tests::test_principal_ideal_ring_axioms(&K, elements.iter().map(|x| K.clone_el(x)));
1559}
1560
1561#[test]
1562fn test_adjoin_root() {
1563 let ZZ = BigIntRing::RING;
1564 let QQ = RationalField::new(ZZ);
1565 let QQX = DensePolyRing::new(QQ, "X");
1566 let [f] = QQX.with_wrapped_indeterminate(|X| [2 * X.pow_ref(3) - 1]);
1567 let (K, a) = NumberField::adjoin_root(&QQX, &f);
1568 assert_el_eq!(&K, K.zero(), K.sub(K.mul(K.int_hom().map(2), K.pow(a, 3)), K.one()));
1569}
1570
1571#[test]
1572fn test_poly_gcd_number_field() {
1573 let ZZ = BigIntRing::RING;
1574 let ZZX = DensePolyRing::new(ZZ, "X");
1575
1576 let [f] = ZZX.with_wrapped_indeterminate(|X| [X.pow_ref(2) + 1]);
1577 let K = NumberField::new(&ZZX, &f);
1578 let KY = DensePolyRing::new(&K, "Y");
1579
1580 let i = RingElementWrapper::new(&KY, KY.inclusion().map(K.canonical_gen()));
1581 let [g, h, expected] = KY.with_wrapped_indeterminate(|Y| {
1582 [
1583 (Y.pow_ref(3) + 1) * (Y - &i),
1584 (Y.pow_ref(4) + 2) * (Y.pow_ref(2) + 1),
1585 Y - i,
1586 ]
1587 });
1588 assert_el_eq!(&KY, &expected, <_ as PolyTFracGCDRing>::gcd(&KY, &g, &h));
1589
1590 let [f] = ZZX.with_wrapped_indeterminate(|X| [X.pow_ref(4) - 20 * X.pow_ref(2) + 16]);
1591 let K = NumberField::new(&ZZX, &f);
1592 let KY = DensePolyRing::new(&K, "Y");
1593
1594 let [sqrt3, sqrt7] = K.with_wrapped_generator(|a| [a.pow_ref(3) / 8 - 2 * a, a.pow_ref(3) / 8 - 3 * a]);
1595 assert_el_eq!(&K, K.int_hom().map(3), K.pow(K.clone_el(&sqrt3), 2));
1596 assert_el_eq!(&K, K.int_hom().map(7), K.pow(K.clone_el(&sqrt7), 2));
1597
1598 let half = RingElementWrapper::new(&KY, KY.inclusion().map(K.invert(&K.int_hom().map(2)).unwrap()));
1599 let sqrt3 = RingElementWrapper::new(&KY, KY.inclusion().map(sqrt3));
1600 let sqrt7 = RingElementWrapper::new(&KY, KY.inclusion().map(sqrt7));
1601 let [g, h, expected] = KY.with_wrapped_indeterminate(|Y| {
1602 [
1603 Y.pow_ref(2) - &sqrt3 * Y - 1,
1604 Y.pow_ref(2) + &sqrt7 * Y + 1,
1605 Y - (sqrt3 - sqrt7) * half,
1606 ]
1607 });
1608 let actual = <_ as PolyTFracGCDRing>::gcd(&KY, &g, &h);
1609 assert_el_eq!(&KY, &expected, &actual);
1610}
1611
1612#[test]
1613#[ignore]
1614fn random_test_poly_gcd_number_field() {
1615 let ZZ = BigIntRing::RING;
1616 let QQ = RationalField::new(ZZ);
1617 let ZZX = DensePolyRing::new(ZZ, "X");
1618 let mut rng = oorandom::Rand64::new(1);
1619 let bound = QQ.base_ring().int_hom().map(1000);
1620 let rank = 6;
1621
1622 for _ in 0..RANDOM_TEST_INSTANCE_COUNT {
1623 let genpoly = ZZX.from_terms(
1624 (0..rank)
1625 .map(|i| (ZZ.get_uniformly_random(&bound, || rng.rand_u64()), i))
1626 .chain([(ZZ.one(), rank)].into_iter()),
1627 );
1628
1629 let K = NumberField::new(&ZZX, &genpoly);
1630 let KY = DensePolyRing::new(&K, "Y");
1631
1632 let mut random_element_K = || {
1633 K.from_canonical_basis((0..6).map(|_| {
1634 QQ.inclusion()
1635 .map(QQ.base_ring().get_uniformly_random(&bound, || rng.rand_u64()))
1636 }))
1637 };
1638 let f = KY.from_terms((0..=5).map(|i| (random_element_K(), i)));
1639 let g = KY.from_terms((0..=5).map(|i| (random_element_K(), i)));
1640 let h = KY.from_terms((0..=4).map(|i| (random_element_K(), i)));
1641 let lhs = KY.mul_ref(&f, &h);
1644 let rhs = KY.mul_ref(&g, &h);
1645
1646 let gcd = <_ as PolyTFracGCDRing>::gcd(&KY, &lhs, &rhs);
1647 assert!(KY.divides(&lhs, &gcd));
1650 assert!(KY.divides(&rhs, &gcd));
1651 assert!(KY.divides(&gcd, &h));
1652 }
1653}