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#[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#[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 #[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 #[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 #[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 #[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 #[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
544fn 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 '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 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(¤t).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, ¤t);
647 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, ¤t, 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
663struct 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 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
885pub 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 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 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 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 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 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 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 assert!(KY.divides(&lhs, &gcd));
1320 assert!(KY.divides(&rhs, &gcd));
1321 assert!(KY.divides(&gcd, &h));
1322 }
1323}