1
2use std::alloc::Global;
3
4use extension_impl::FreeAlgebraImplBase;
5use gcd::poly_gcd_local;
6use local::*;
7use hensel::hensel_lift_factorization;
8use sparse::SparseMapVector;
9use squarefree_part::poly_power_decomposition_local;
10
11use crate::algorithms::interpolate::product_except_one;
12use crate::algorithms::poly_factor::finite::poly_factor_finite_field;
13use crate::algorithms::rational_reconstruction::balanced_rational_reconstruction;
14use crate::computation::*;
15use crate::delegate::DelegateRingImplEuclideanRing;
16use crate::specialization::*;
17use crate::algorithms::convolution::*;
18use crate::algorithms::eea::signed_lcm;
19use crate::algorithms::poly_factor::extension::poly_factor_extension;
20use crate::algorithms::poly_gcd::*;
21use crate::MAX_PROBABILISTIC_REPETITIONS;
22use crate::delegate::DelegateRing;
23use crate::integer::*;
24use crate::pid::*;
25use crate::ring::*;
26use crate::rings::field::AsField;
27use crate::rings::poly::*;
28use crate::rings::zn::ZnRingStore;
29use crate::rings::rational::*;
30use crate::divisibility::*;
31use crate::rings::extension::*;
32
33use super::extension_impl::FreeAlgebraImpl;
34use super::Field;
35use super::FreeAlgebra;
36
37#[stability::unstable(feature = "enable")]
139pub struct NumberFieldBase<Impl, I>
140 where Impl: RingStore,
141 Impl::Type: Field + FreeAlgebra,
142 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
143 I: RingStore,
144 I::Type: IntegerRing
145{
146 base: Impl
147}
148
149#[stability::unstable(feature = "enable")]
150pub type DefaultNumberFieldImpl = AsField<FreeAlgebraImpl<RationalField<BigIntRing>, Vec<El<RationalField<BigIntRing>>>, Global, KaratsubaAlgorithm>>;
151#[stability::unstable(feature = "enable")]
152pub type NumberField<Impl = DefaultNumberFieldImpl, I = BigIntRing> = RingValue<NumberFieldBase<Impl, I>>;
153
154impl NumberField {
155
156 #[stability::unstable(feature = "enable")]
165 pub fn try_new<P>(poly_ring: P, generating_poly: &El<P>) -> Option<Self>
166 where P: RingStore,
167 P::Type: PolyRing,
168 <P::Type as RingExtension>::BaseRing: RingStore<Type = BigIntRingBase>
169 {
170 assert!(poly_ring.base_ring().is_one(poly_ring.lc(generating_poly).unwrap()));
171 let QQ = RationalField::new(BigIntRing::RING);
172 let rank = poly_ring.degree(generating_poly).unwrap();
173 let modulus = (0..rank).map(|i| QQ.negate(QQ.inclusion().map_ref(poly_ring.coefficient_at(generating_poly, i)))).collect::<Vec<_>>();
174 return FreeAlgebraImpl::new_with(QQ, rank, modulus, "θ", Global, STANDARD_CONVOLUTION).as_field().ok().map(Self::create);
175 }
176
177 #[stability::unstable(feature = "enable")]
187 pub fn new<P>(poly_ring: P, generating_poly: &El<P>) -> Self
188 where P: RingStore,
189 P::Type: PolyRing,
190 <P::Type as RingExtension>::BaseRing: RingStore<Type = BigIntRingBase>
191 {
192 Self::try_new(poly_ring, generating_poly).unwrap()
193 }
194
195 #[stability::unstable(feature = "enable")]
201 pub fn try_adjoin_root<P>(poly_ring: P, generating_poly: &El<P>) -> Option<(Self, El<Self>)>
202 where P: RingStore,
203 P::Type: PolyRing,
204 <P::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<BigIntRing>>
205 {
206 let QQ = poly_ring.base_ring();
207 let ZZ = QQ.base_ring();
208 let denominator = poly_ring.terms(generating_poly).map(|(c, _)| QQ.get_ring().den(c)).fold(
209 ZZ.one(),
210 |a, b| signed_lcm(a, ZZ.clone_el(b), ZZ)
211 );
212 let rank = poly_ring.degree(generating_poly).unwrap();
213 let scaled_lc = ZZ.checked_div(&ZZ.mul_ref(&denominator, QQ.get_ring().num(poly_ring.lc(generating_poly).unwrap())), QQ.get_ring().den(poly_ring.lc(generating_poly).unwrap())).unwrap();
214 let ZZX = DensePolyRing::new(ZZ, "X");
215 let new_generating_poly = ZZX.from_terms(poly_ring.terms(generating_poly).map(|(c, i)| if i == rank {
216 (ZZ.one(), rank)
217 } else {
218 (ZZ.checked_div(&ZZ.mul_ref_fst(&denominator, ZZ.mul_ref_fst(QQ.get_ring().num(c), ZZ.pow(ZZ.clone_el(&scaled_lc), rank - i - 1))), QQ.get_ring().den(c)).unwrap(), i)
219 }));
220 return Self::try_new(ZZX, &new_generating_poly).map(|res| {
221 let root = res.inclusion().mul_map(res.canonical_gen(), QQ.invert(&QQ.inclusion().map(scaled_lc)).unwrap());
222 return (res, root);
223 });
224 }
225
226 #[stability::unstable(feature = "enable")]
227 pub fn adjoin_root<P>(poly_ring: P, generating_poly: &El<P>) -> (Self, El<Self>)
228 where P: RingStore,
229 P::Type: PolyRing,
230 <P::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<BigIntRing>>
231 {
232 Self::try_adjoin_root(poly_ring, generating_poly).unwrap()
233 }
234}
235
236impl<Impl, I> NumberField<Impl, I>
237 where Impl: RingStore,
238 Impl::Type: Field + FreeAlgebra,
239 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
240 I: RingStore,
241 I::Type: IntegerRing
242{
243 #[stability::unstable(feature = "enable")]
249 pub fn create(implementation: Impl) -> Self {
250 let poly_ring = DensePolyRing::new(implementation.base_ring(), "X");
251 let gen_poly = implementation.generating_poly(&poly_ring, poly_ring.base_ring().identity());
252 assert!(poly_ring.terms(&gen_poly).all(|(c, _)| poly_ring.base_ring().base_ring().is_one(poly_ring.base_ring().get_ring().den(c))));
253 RingValue::from(NumberFieldBase {
254 base: implementation,
255 })
256 }
257}
258
259impl<Impl, I> Clone for NumberFieldBase<Impl, I>
260 where Impl: RingStore + Clone,
261 Impl::Type: Field + FreeAlgebra,
262 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
263 I: RingStore,
264 I::Type: IntegerRing
265{
266 fn clone(&self) -> Self {
267 Self {
268 base: self.base.clone(),
269 }
270 }
271}
272
273impl<Impl, I> Copy for NumberFieldBase<Impl, I>
274 where Impl: RingStore + Copy,
275 Impl::Type: Field + FreeAlgebra,
276 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
277 I: RingStore,
278 I::Type: IntegerRing,
279 El<Impl>: Copy,
280 El<I>: Copy
281{}
282
283impl<Impl, I> PartialEq for NumberFieldBase<Impl, I>
284 where Impl: RingStore,
285 Impl::Type: Field + FreeAlgebra,
286 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
287 I: RingStore,
288 I::Type: IntegerRing
289{
290 fn eq(&self, other: &Self) -> bool {
291 self.base.get_ring() == other.base.get_ring()
292 }
293}
294
295impl<Impl, I> DelegateRing for NumberFieldBase<Impl, I>
296 where Impl: RingStore,
297 Impl::Type: Field + FreeAlgebra,
298 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
299 I: RingStore,
300 I::Type: IntegerRing
301{
302 type Base = Impl::Type;
303 type Element = El<Impl>;
304
305 fn get_delegate(&self) -> &Self::Base {
306 self.base.get_ring()
307 }
308
309 fn delegate(&self, el: Self::Element) -> <Self::Base as RingBase>::Element { el }
310 fn delegate_mut<'a>(&self, el: &'a mut Self::Element) -> &'a mut <Self::Base as RingBase>::Element { el }
311 fn delegate_ref<'a>(&self, el: &'a Self::Element) -> &'a <Self::Base as RingBase>::Element { el }
312 fn rev_delegate(&self, el: <Self::Base as RingBase>::Element) -> Self::Element { el }
313}
314
315impl<Impl, I> DelegateRingImplEuclideanRing for NumberFieldBase<Impl, I>
316 where Impl: RingStore,
317 Impl::Type: Field + FreeAlgebra,
318 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
319 I: RingStore,
320 I::Type: IntegerRing
321{}
322
323impl<Impl, I> FiniteRingSpecializable for NumberFieldBase<Impl, I>
324 where Impl: RingStore,
325 Impl::Type: Field + FreeAlgebra,
326 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
327 I: RingStore,
328 I::Type: IntegerRing
329{
330 fn specialize<O: FiniteRingOperation<Self>>(_op: O) -> Result<O::Output, ()> {
331 Err(())
332 }
333}
334
335impl<Impl, I> Field for NumberFieldBase<Impl, I>
336 where Impl: RingStore,
337 Impl::Type: Field + FreeAlgebra,
338 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
339 I: RingStore,
340 I::Type: IntegerRing
341{}
342
343impl<Impl, I> PerfectField for NumberFieldBase<Impl, I>
344 where Impl: RingStore,
345 Impl::Type: Field + FreeAlgebra,
346 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
347 I: RingStore,
348 I::Type: IntegerRing
349{}
350
351impl<Impl, I> Domain for NumberFieldBase<Impl, I>
352 where Impl: RingStore,
353 Impl::Type: Field + FreeAlgebra,
354 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
355 I: RingStore,
356 I::Type: IntegerRing
357{}
358
359impl<Impl, I> PolyTFracGCDRing for NumberFieldBase<Impl, I>
360 where Impl: RingStore,
361 Impl::Type: Field + FreeAlgebra,
362 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
363 I: RingStore,
364 I::Type: IntegerRing
365{
366 fn gcd<P>(poly_ring: P, lhs: &El<P>, rhs: &El<P>) -> El<P>
367 where P: RingStore + Copy,
368 P::Type: PolyRing + DivisibilityRing,
369 <P::Type as RingExtension>::BaseRing: RingStore<Type = Self>
370 {
371 let self_ = NumberFieldByOrder { base: RingRef::new(poly_ring.base_ring().get_ring()) };
372
373 let order_poly_ring = DensePolyRing::new(RingRef::new(&self_), "X");
374 let lhs_order = self_.scale_poly_to_order(poly_ring, &order_poly_ring, lhs);
375 let rhs_order = self_.scale_poly_to_order(poly_ring, &order_poly_ring, rhs);
376
377 let result = poly_gcd_local(&order_poly_ring, order_poly_ring.clone_el(&lhs_order), order_poly_ring.clone_el(&rhs_order), LogProgress);
378
379 return self_.normalize_map_back_from_order(&order_poly_ring, poly_ring, &result);
380 }
381
382 fn power_decomposition<P>(poly_ring: P, poly: &El<P>) -> Vec<(El<P>, usize)>
383 where P: RingStore + Copy,
384 P::Type: PolyRing + DivisibilityRing,
385 <P::Type as RingExtension>::BaseRing: RingStore<Type = Self>
386 {
387 let self_ = NumberFieldByOrder { base: RingRef::new(poly_ring.base_ring().get_ring()) };
388 let order_poly_ring = DensePolyRing::new(RingRef::new(&self_), "X");
389 let poly_order = self_.scale_poly_to_order(poly_ring, &order_poly_ring, poly);
390
391 let result = poly_power_decomposition_local(&order_poly_ring, poly_order, LogProgress);
392
393 return result.into_iter().map(|(f, k)| (self_.normalize_map_back_from_order(&order_poly_ring, poly_ring, &f), k)).collect();
394 }
395}
396
397impl<Impl, I> FactorPolyField for NumberFieldBase<Impl, I>
398 where Impl: RingStore,
399 Impl::Type: Field + FreeAlgebra,
400 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
401 I: RingStore,
402 I::Type: IntegerRing
403{
404 fn factor_poly<P>(poly_ring: P, poly: &El<P>) -> (Vec<(El<P>, usize)>, Self::Element)
405 where P: RingStore + Copy,
406 P::Type: PolyRing + EuclideanRing,
407 <P::Type as RingExtension>::BaseRing: RingStore<Type = Self>
408 {
409 let self_ = NumberFieldByOrder { base: RingRef::new(poly_ring.base_ring().get_ring()) };
410 let order_poly_ring = DensePolyRing::new(RingRef::new(&self_), "X");
411 let poly_order = self_.scale_poly_to_order(poly_ring, &order_poly_ring, poly);
412
413 let mut result = Vec::new();
414 for (irred_factor, e) in poly_factor_extension(&poly_ring, &self_.normalize_map_back_from_order(&order_poly_ring, poly_ring, &poly_order)).0 {
415 result.push((irred_factor, e));
416 }
417 return (result, self_.clone_el(poly_ring.lc(poly).unwrap()));
418 }
419}
420
421struct NumberFieldByOrder<'a, Impl, I>
428 where Impl: RingStore,
429 Impl::Type: Field + FreeAlgebra,
430 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
431 I: RingStore,
432 I::Type: IntegerRing
433{
434 base: RingRef<'a, NumberFieldBase<Impl, I>>
435}
436
437impl<'a, Impl, I> NumberFieldByOrder<'a, Impl, I>
438 where Impl: RingStore,
439 Impl::Type: Field + FreeAlgebra,
440 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
441 I: RingStore,
442 I::Type: IntegerRing
443{
444 fn scale_poly_to_order<'ring, P1, P2>(&self, from: P1, to: P2, poly: &El<P1>) -> El<P2>
445 where P1: RingStore,
446 P1::Type: PolyRing,
447 <P1::Type as RingExtension>::BaseRing: RingStore<Type = NumberFieldBase<Impl, I>>,
448 P2: RingStore,
449 P2::Type: PolyRing,
450 <P2::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
451 Self: 'ring
452 {
453 debug_assert!(self.base.get_ring() == from.base_ring().get_ring());
454 debug_assert!(self.base.get_ring() == to.base_ring().get_ring().base.get_ring());
455 let QQ = self.base.base_ring();
456 let ZZ = QQ.base_ring();
457 let denominator = QQ.inclusion().map(from.terms(poly).map(|(c, _)|
458 self.base.wrt_canonical_basis(c).iter().map(|c| ZZ.clone_el(QQ.get_ring().den(&c))).fold(ZZ.one(), |a, b| signed_lcm(a, b, ZZ))
459 ).fold(ZZ.one(), |a, b| signed_lcm(a, b, ZZ)));
460 debug_assert!(!QQ.is_zero(&denominator));
461 return to.from_terms(from.terms(poly).map(|(c, i)| (self.base.inclusion().mul_ref_map(c, &denominator), i)));
462 }
463
464 fn normalize_map_back_from_order<'ring, P1, P2>(&self, from: P1, to: P2, poly: &El<P1>) -> El<P2>
465 where P1: RingStore,
466 P1::Type: PolyRing,
467 <P1::Type as RingExtension>::BaseRing: RingStore<Type = Self>,
468 P2: RingStore,
469 P2::Type: PolyRing,
470 <P2::Type as RingExtension>::BaseRing: RingStore<Type = NumberFieldBase<Impl, I>>,
471 Self: 'ring
472 {
473 debug_assert!(self.base.get_ring() == to.base_ring().get_ring());
474 debug_assert!(self.base.get_ring() == from.base_ring().get_ring().base.get_ring());
475 let result = to.from_terms(from.terms(poly).map(|(c, i)| (self.clone_el(c), i)));
476 return to.normalize(result);
477 }
478}
479
480impl<'a, Impl, I> PartialEq for NumberFieldByOrder<'a, Impl, I>
481 where Impl: RingStore,
482 Impl::Type: Field + FreeAlgebra,
483 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
484 I: RingStore,
485 I::Type: IntegerRing
486{
487 fn eq(&self, other: &Self) -> bool {
488 self.base.get_ring() == other.base.get_ring()
489 }
490}
491
492impl<'a, Impl, I> FiniteRingSpecializable for NumberFieldByOrder<'a, Impl, I>
493 where Impl: RingStore,
494 Impl::Type: Field + FreeAlgebra,
495 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
496 I: RingStore,
497 I::Type: IntegerRing
498{
499 fn specialize<O: FiniteRingOperation<Self>>(_op: O) -> Result<O::Output, ()> {
500 Err(())
501 }
502}
503
504impl<'a, Impl, I> DelegateRing for NumberFieldByOrder<'a, Impl, I>
505 where Impl: RingStore,
506 Impl::Type: Field + FreeAlgebra,
507 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
508 I: RingStore,
509 I::Type: IntegerRing
510{
511 type Base = Impl::Type;
512 type Element = El<Impl>;
513
514 fn get_delegate(&self) -> &Self::Base {
515 self.base.get_ring().base.get_ring()
516 }
517
518 fn delegate(&self, el: Self::Element) -> <Self::Base as RingBase>::Element { el }
519 fn delegate_mut<'b>(&self, el: &'b mut Self::Element) -> &'b mut <Self::Base as RingBase>::Element { el }
520 fn delegate_ref<'b>(&self, el: &'b Self::Element) -> &'b <Self::Base as RingBase>::Element { el }
521 fn rev_delegate(&self, el: <Self::Base as RingBase>::Element) -> Self::Element { el }
522}
523
524impl<'a, Impl, I> Domain for NumberFieldByOrder<'a, Impl, I>
525 where Impl: RingStore,
526 Impl::Type: Field + FreeAlgebra,
527 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
528 I: RingStore,
529 I::Type: IntegerRing
530{}
531
532type LocalRing<'ring, I> = <<I as RingStore>::Type as PolyGCDLocallyDomain>::LocalRing<'ring>;
533type LocalField<'ring, I> = <<I as RingStore>::Type as PolyGCDLocallyDomain>::LocalField<'ring>;
534
535pub struct NumberRingIdeal<'ring, I>
536 where I: RingStore,
537 I::Type: IntegerRing,
538 I: 'ring
539{
540 prime: <I::Type as PolyGCDLocallyDomain>::SuitableIdeal<'ring>,
541 ZZX: DensePolyRing<&'ring I>,
542 number_field_poly: El<DensePolyRing<&'ring I>>,
543 FpX: DensePolyRing<<I::Type as PolyGCDLocallyDomain>::LocalField<'ring>>,
544 Fp_as_ring: <I::Type as PolyGCDLocallyDomain>::LocalRing<'ring>,
545 minpoly_factors_mod_p: Vec<El<DensePolyRing<<I::Type as PolyGCDLocallyDomain>::LocalField<'ring>>>>
546}
547
548impl<'ring, I> NumberRingIdeal<'ring, I>
549 where I: RingStore,
550 I::Type: IntegerRing,
551 I: 'ring
552{
553 fn lifted_factorization<'a>(&'a self, e: usize) -> (DensePolyRing<<I::Type as PolyGCDLocallyDomain>::LocalRing<'ring>>, Vec<El<DensePolyRing<<I::Type as PolyGCDLocallyDomain>::LocalRing<'ring>>>>) {
554 let ZZX = &self.ZZX;
555 let ZZ = ZZX.base_ring();
556 let ZpeX = DensePolyRing::new(ZZ.get_ring().local_ring_at(&self.prime, e, 0), "X");
557 let Zpe = ZpeX.base_ring();
558 let FpX = &self.FpX;
559 let Zpe_to_Fp = PolyGCDLocallyIntermediateReductionMap::new(ZZ.get_ring(), &self.prime, Zpe, e, &self.Fp_as_ring, 1, 0);
560 let ZZ_to_Zpe = PolyGCDLocallyReductionMap::new(ZZ.get_ring(), &self.prime, &Zpe, e, 0);
561
562 let factors = hensel_lift_factorization(
563 &Zpe_to_Fp,
564 &ZpeX,
565 FpX,
566 &ZpeX.lifted_hom(ZZX, ZZ_to_Zpe).map_ref(&self.number_field_poly),
567 &self.minpoly_factors_mod_p[..],
568 DontObserve
569 );
570
571 return (ZpeX, factors);
572 }
573}
574
575impl<'a, Impl, I> PolyGCDLocallyDomain for NumberFieldByOrder<'a, Impl, I>
576 where Impl: RingStore,
577 Impl::Type: Field + FreeAlgebra,
578 <Impl::Type as RingExtension>::BaseRing: RingStore<Type = RationalFieldBase<I>>,
579 I: RingStore,
580 I::Type: IntegerRing
581{
582 type LocalRingBase<'ring> = FreeAlgebraImplBase<
583 LocalRing<'ring, I>,
584 SparseMapVector<LocalRing<'ring, I>>
585 >
586 where Self: 'ring;
587
588 type LocalRing<'ring> = RingValue<Self::LocalRingBase<'ring>>
589 where Self: 'ring;
590
591 type LocalFieldBase<'ring> = AsFieldBase<FreeAlgebraImpl<
592 LocalField<'ring, I>,
593 SparseMapVector<LocalField<'ring, I>>
594 >>
595 where Self: 'ring;
596
597 type LocalField<'ring> = RingValue<Self::LocalFieldBase<'ring>>
598 where Self: 'ring;
599
600 type SuitableIdeal<'ring> = NumberRingIdeal<'ring, I>
601 where Self: 'ring;
602
603 fn maximal_ideal_factor_count<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>) -> usize
604 where Self: 'ring
605 {
606 ideal.minpoly_factors_mod_p.len()
607 }
608
609 fn heuristic_exponent<'ring, 'b, J>(&self, ideal: &Self::SuitableIdeal<'ring>, poly_deg: usize, coefficients: J) -> usize
610 where J: Iterator<Item = &'b Self::Element>,
611 Self: 'b,
612 Self: 'ring
613 {
614 const HEURISTIC_FACTOR_SIZE_OVER_POLY_SIZE_FACTOR: f64 = 0.25;
615
616 let QQ = self.base.base_ring();
617 let ZZ = QQ.base_ring();
618 let log2_max_coeff = coefficients.map(|c| self.base.wrt_canonical_basis(c).iter().map(|c| ZZ.abs_log2_ceil(QQ.get_ring().num(&c)).unwrap_or(0)).max().unwrap()).max().unwrap_or(0);
621 let log2_p = (ZZ.get_ring().principal_ideal_generator(&ideal.prime) as f64).log2();
622 return ((log2_max_coeff as f64 + poly_deg as f64 + (self.rank() as f64).log2()) / log2_p * HEURISTIC_FACTOR_SIZE_OVER_POLY_SIZE_FACTOR).ceil() as usize + 1;
623 }
624
625 fn random_suitable_ideal<'ring, F>(&'ring self, mut rng: F) -> Self::SuitableIdeal<'ring>
626 where F: FnMut() -> u64
627 {
628 let QQ = self.base.base_ring();
629 let ZZ = QQ.base_ring();
630 let ZZX = DensePolyRing::new(ZZ, "X");
631 let gen_poly = self.base.generating_poly(&ZZX, LambdaHom::new(QQ, ZZ, |QQ, ZZ, x| {
632 assert!(ZZ.is_one(QQ.get_ring().den(&x)));
633 ZZ.clone_el(QQ.get_ring().num(&x))
634 }));
635
636 for _ in 0..MAX_PROBABILISTIC_REPETITIONS {
638 let p = ZZ.get_ring().random_suitable_ideal(&mut rng);
639 assert_eq!(1, ZZ.get_ring().maximal_ideal_factor_count(&p));
640
641 let Fp_as_ring = ZZ.get_ring().local_ring_at(&p, 1, 0);
642 let FpX = DensePolyRing::new(ZZ.get_ring().local_field_at(&p, 0), "X");
643 let Fp = FpX.base_ring();
644 let ZZ_to_Fp = Fp.can_hom(&Fp_as_ring).unwrap().compose(PolyGCDLocallyReductionMap::new(ZZ.get_ring(), &p, &Fp_as_ring, 1, 0));
645
646 let gen_poly_mod_p = FpX.from_terms(ZZX.terms(&gen_poly).map(|(c, i)| (ZZ_to_Fp.map_ref(c), i)));
647 let (factorization, _) = poly_factor_finite_field(&FpX, &gen_poly_mod_p);
648 if factorization.iter().all(|(_, e)| *e == 1) {
649
650 return NumberRingIdeal {
651 minpoly_factors_mod_p: factorization.into_iter().map(|(f, _)| f).collect(),
652 number_field_poly: gen_poly,
653 FpX: FpX,
654 ZZX: ZZX,
655 Fp_as_ring: Fp_as_ring,
656 prime: p
657 };
658 }
659 }
660 unreachable!()
661 }
662
663 fn local_field_at<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, idx: usize) -> Self::LocalField<'ring>
664 where Self: 'ring
665 {
666 assert!(idx < self.maximal_ideal_factor_count(ideal));
667 let QQ = self.base.base_ring();
668 let ZZ = QQ.base_ring();
669 let Fp = ZZ.get_ring().local_field_at(&ideal.prime, 0);
670 let FpX = &ideal.FpX;
671 assert!(Fp.get_ring() == FpX.base_ring().get_ring());
672
673 let irred_poly = &ideal.minpoly_factors_mod_p[idx];
674 let mut x_pow_rank = SparseMapVector::new(FpX.degree(irred_poly).unwrap(), ZZ.get_ring().local_field_at(&ideal.prime, 0));
675 for (c, i) in FpX.terms(irred_poly) {
676 if i < x_pow_rank.len() {
677 *x_pow_rank.at_mut(i) = Fp.negate(Fp.clone_el(c));
678 }
679 }
680 _ = x_pow_rank.at_mut(0);
681 return AsField::from(AsFieldBase::promise_is_perfect_field(FreeAlgebraImpl::new(Fp, FpX.degree(irred_poly).unwrap(), x_pow_rank)));
682 }
683
684 fn local_ring_at<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, e: usize, idx: usize) -> Self::LocalRing<'ring>
685 where Self: 'ring
686 {
687 assert!(idx < self.maximal_ideal_factor_count(ideal));
688 let QQ = self.base.base_ring();
689 let ZZ = QQ.base_ring();
690 let (ZpeX, factors) = ideal.lifted_factorization(e);
691 let Zpe = ZpeX.base_ring();
692
693 let irred_poly = &factors[idx];
694 let degree = ZpeX.degree(irred_poly).unwrap();
695 let mut x_pow_rank = SparseMapVector::new(degree, ZZ.get_ring().local_ring_at(&ideal.prime, e, 0));
696 for (c, i) in ZpeX.terms(irred_poly) {
697 if i < x_pow_rank.len() {
698 *x_pow_rank.at_mut(i) = Zpe.negate(Zpe.clone_el(c));
699 }
700 }
701 _ = x_pow_rank.at_mut(0);
702 return FreeAlgebraImpl::new(ZZ.get_ring().local_ring_at(&ideal.prime, e, 0), degree, x_pow_rank);
703 }
704
705 fn reduce_ring_el<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, to: (&Self::LocalRing<'ring>, usize), idx: usize, x: Self::Element) -> El<Self::LocalRing<'ring>>
706 where Self: 'ring
707 {
708 assert!(idx < self.maximal_ideal_factor_count(ideal));
709 let QQ = self.base.base_ring();
710 let ZZ = QQ.base_ring();
711 let ZZX = &ideal.ZZX;
712 let partial_QQ_to_ZZ = LambdaHom::new(QQ, ZZ, |QQ, ZZ, x| {
713 assert!(ZZ.is_one(QQ.get_ring().den(&x)));
714 ZZ.clone_el(QQ.get_ring().num(&x))
715 });
716 let ZZ_to_Zpe = PolyGCDLocallyReductionMap::new(ZZ.get_ring(), &ideal.prime, to.0.base_ring(), to.1, 0);
717
718 ZZX.evaluate(
719 &self.base.poly_repr(ZZX, &x, partial_QQ_to_ZZ),
720 &to.0.canonical_gen(),
721 to.0.inclusion().compose(ZZ_to_Zpe)
722 )
723 }
724
725 fn reduce_partial<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, from: (&Self::LocalRing<'ring>, usize), to: (&Self::LocalRing<'ring>, usize), idx: usize, x: El<Self::LocalRing<'ring>>) -> El<Self::LocalRing<'ring>>
726 where Self: 'ring
727 {
728 assert!(idx < self.maximal_ideal_factor_count(ideal));
729 let QQ = self.base.base_ring();
730 let ZZ = QQ.base_ring();
731 to.0.from_canonical_basis(from.0.wrt_canonical_basis(&x).iter().map(|c| ZZ.get_ring().reduce_partial(&ideal.prime, (from.0.base_ring(), from.1), (to.0.base_ring(), to.1), 0, c)))
732 }
733
734 fn lift_partial<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, from: (&Self::LocalRing<'ring>, usize), to: (&Self::LocalRing<'ring>, usize), idx: usize, x: El<Self::LocalRing<'ring>>) -> El<Self::LocalRing<'ring>>
735 where Self: 'ring
736 {
737 assert!(idx < self.maximal_ideal_factor_count(ideal));
738 let QQ = self.base.base_ring();
739 let ZZ = QQ.base_ring();
740 to.0.from_canonical_basis(from.0.wrt_canonical_basis(&x).iter().map(|c| ZZ.get_ring().lift_partial(&ideal.prime, (from.0.base_ring(), from.1), (to.0.base_ring(), to.1), 0, c)))
741 }
742
743 fn reconstruct_ring_el<'local, 'element, 'ring, V1, V2>(&self, ideal: &Self::SuitableIdeal<'ring>, from: V1, e: usize, x: V2) -> Self::Element
744 where Self: 'ring,
745 V1: VectorFn<&'local Self::LocalRing<'ring>>,
746 V2: VectorFn<&'element El<Self::LocalRing<'ring>>>,
747 Self::LocalRing<'ring>: 'local,
748 El<Self::LocalRing<'ring>>: 'element,
749 'ring: 'local + 'element
750 {
751 assert_eq!(self.maximal_ideal_factor_count(ideal), from.len());
752 assert_eq!(self.maximal_ideal_factor_count(ideal), x.len());
753 let QQ = self.base.base_ring();
754 let ZZ = QQ.base_ring();
755 let Zpe = from.at(0).base_ring();
756 assert!(from.iter().all(|ring| ring.base_ring().get_ring() == Zpe.get_ring()));
757 let ZpeX = DensePolyRing::new(Zpe, "X");
758 let ZZ_to_Zpe = PolyGCDLocallyReductionMap::new(ZZ.get_ring(), &ideal.prime, Zpe, e, 0);
759
760 let mut unit_vectors = (0..self.maximal_ideal_factor_count(ideal)).map(|_| ZpeX.zero()).collect::<Vec<_>>();
762 product_except_one(&ZpeX, (&from).map_fn(|galois_ring| galois_ring.generating_poly(&ZpeX, Zpe.identity())), &mut unit_vectors);
763 let complete_product = ZpeX.mul_ref_fst(&unit_vectors[0], from.at(0).generating_poly(&ZpeX, Zpe.identity()));
764 assert_el_eq!(&ZpeX, &complete_product, &self.base.generating_poly(&ZpeX, ZZ_to_Zpe.compose(LambdaHom::new(QQ, ZZ, |QQ, ZZ, x| {
765 assert!(ZZ.is_one(QQ.get_ring().den(&x)));
766 ZZ.clone_el(QQ.get_ring().num(&x))
767 }))));
768
769 for i in 0..self.maximal_ideal_factor_count(ideal) {
770 let galois_ring = from.at(i);
771 let inv_normalization_factor = ZpeX.evaluate(unit_vectors.at(i), &galois_ring.canonical_gen(), galois_ring.inclusion());
772 let normalization_factor = galois_ring.invert(&inv_normalization_factor).unwrap();
773 let lifted_normalization_factor = galois_ring.poly_repr(&ZpeX, &normalization_factor, Zpe.identity());
774 let unreduced_new_unit_vector = ZpeX.mul(std::mem::replace(&mut unit_vectors[i], ZpeX.zero()), lifted_normalization_factor);
775 unit_vectors[i] = ZpeX.div_rem_monic(unreduced_new_unit_vector, &complete_product).1;
776 }
777
778 let combined = <_ as RingStore>::sum(&ZpeX, (0..self.maximal_ideal_factor_count(ideal)).map(|i| {
780 let galois_ring = from.at(i);
781 let unreduced_result = ZpeX.mul_ref_snd(galois_ring.poly_repr(&ZpeX, x.at(i), Zpe.identity()), &unit_vectors[i]);
782 ZpeX.div_rem_monic(unreduced_result, &complete_product).1
783 }));
784
785 for i in 0..self.maximal_ideal_factor_count(ideal) {
786 let galois_ring = from.at(i);
787 debug_assert!(galois_ring.eq_el(x.at(i), &ZpeX.evaluate(&combined, &galois_ring.canonical_gen(), galois_ring.inclusion())));
788 }
789
790 let Zpe_as_zn = ZZ.get_ring().local_ring_as_zn(&Zpe);
792 let Zpe_to_as_zn = Zpe_as_zn.can_hom(Zpe).unwrap();
793 let result = self.from_canonical_basis((0..self.rank()).map(|i| {
794 let (num, den) = balanced_rational_reconstruction(Zpe_as_zn, Zpe_to_as_zn.map_ref(ZpeX.coefficient_at(&combined, i)));
795 return QQ.div(&QQ.inclusion().map(int_cast(num, ZZ, Zpe_as_zn.integer_ring())), &QQ.inclusion().map(int_cast(den, ZZ, Zpe_as_zn.integer_ring())));
796 }));
797 return result;
798 }
799
800 fn dbg_ideal<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, out: &mut std::fmt::Formatter) -> std::fmt::Result
801 where Self: 'ring
802 {
803 let QQ = self.base.base_ring();
804 QQ.base_ring().get_ring().dbg_ideal(&ideal.prime, out)
805 }
806}
807
808#[cfg(test)]
809use crate::RANDOM_TEST_INSTANCE_COUNT;
810#[cfg(test)]
811use crate::iters::multi_cartesian_product;
812
813#[test]
814fn test_principal_ideal_ring_axioms() {
815 let ZZ = BigIntRing::RING;
816 let ZZX = DensePolyRing::new(ZZ, "X");
817
818 let [f] = ZZX.with_wrapped_indeterminate(|X| [X.pow_ref(2) + 1]);
819 let K = NumberField::new(&ZZX, &f);
820
821 let elements = multi_cartesian_product([(-4..4), (-2..2)].into_iter(), |slice| K.from_canonical_basis(slice.iter().map(|x| K.base_ring().int_hom().map(*x))), |_, x| *x).collect::<Vec<_>>();
822
823 crate::pid::generic_tests::test_principal_ideal_ring_axioms(&K, elements.iter().map(|x| K.clone_el(x)));
824}
825
826#[test]
827fn test_adjoin_root() {
828 let ZZ = BigIntRing::RING;
829 let QQ = RationalField::new(ZZ);
830 let QQX = DensePolyRing::new(QQ, "X");
831 let [f] = QQX.with_wrapped_indeterminate(|X| [2 * X.pow_ref(3) - 1]);
832 let (K, a) = NumberField::adjoin_root(&QQX, &f);
833 assert_el_eq!(&K, K.zero(), K.sub(K.mul(K.int_hom().map(2), K.pow(a, 3)), K.one()));
834}
835
836#[test]
837fn test_poly_gcd_number_field() {
838 let ZZ = BigIntRing::RING;
839 let ZZX = DensePolyRing::new(ZZ, "X");
840
841 let [f] = ZZX.with_wrapped_indeterminate(|X| [X.pow_ref(2) + 1]);
842 let K = NumberField::new(&ZZX, &f);
843 let KY = DensePolyRing::new(&K, "Y");
844
845 let i = RingElementWrapper::new(&KY, KY.inclusion().map(K.canonical_gen()));
846 let [g, h, expected] = KY.with_wrapped_indeterminate(|Y| [
847 (Y.pow_ref(3) + 1) * (Y - &i),
848 (Y.pow_ref(4) + 2) * (Y.pow_ref(2) + 1),
849 Y - i
850 ]);
851 assert_el_eq!(&KY, &expected, <_ as PolyTFracGCDRing>::gcd(&KY, &g, &h));
852
853 let [f] = ZZX.with_wrapped_indeterminate(|X| [X.pow_ref(4) - 20 * X.pow_ref(2) + 16]);
854 let K = NumberField::new(&ZZX, &f);
855 let KY = DensePolyRing::new(&K, "Y");
856
857 let [sqrt3, sqrt7] = K.with_wrapped_generator(|a| [a.pow_ref(3) / 8 - 2 * a, a.pow_ref(3) / 8 - 3 * a]);
858 assert_el_eq!(&K, K.int_hom().map(3), K.pow(K.clone_el(&sqrt3), 2));
859 assert_el_eq!(&K, K.int_hom().map(7), K.pow(K.clone_el(&sqrt7), 2));
860
861 let half = RingElementWrapper::new(&KY, KY.inclusion().map(K.invert(&K.int_hom().map(2)).unwrap()));
862 let sqrt3 = RingElementWrapper::new(&KY, KY.inclusion().map(sqrt3));
863 let sqrt7 = RingElementWrapper::new(&KY, KY.inclusion().map(sqrt7));
864 let [g, h, expected] = KY.with_wrapped_indeterminate(|Y| [
865 Y.pow_ref(2) - &sqrt3 * Y - 1,
866 Y.pow_ref(2) + &sqrt7 * Y + 1,
867 Y - (sqrt3 - sqrt7) * half
868 ]);
869 let actual = <_ as PolyTFracGCDRing>::gcd(&KY, &g, &h);
870 assert_el_eq!(&KY, &expected, &actual);
871}
872
873#[test]
874#[ignore]
875fn random_test_poly_gcd_number_field() {
876 let ZZ = BigIntRing::RING;
877 let QQ = RationalField::new(ZZ);
878 let ZZX = DensePolyRing::new(ZZ, "X");
879 let mut rng = oorandom::Rand64::new(1);
880 let bound = QQ.base_ring().int_hom().map(1000);
881 let rank = 6;
882
883 for _ in 0..RANDOM_TEST_INSTANCE_COUNT {
884 let genpoly = ZZX.from_terms((0..rank).map(|i| (ZZ.get_uniformly_random(&bound, || rng.rand_u64()), i)).chain([(ZZ.one(), rank)].into_iter()));
885
886 let K = NumberField::new(&ZZX, &genpoly);
887 let KY = DensePolyRing::new(&K, "Y");
888
889 let mut random_element_K = || K.from_canonical_basis((0..6).map(|_| QQ.inclusion().map(QQ.base_ring().get_uniformly_random(&bound, || rng.rand_u64()))));
890 let f = KY.from_terms((0..=5).map(|i| (random_element_K(), i)));
891 let g = KY.from_terms((0..=5).map(|i| (random_element_K(), i)));
892 let h = KY.from_terms((0..=4).map(|i| (random_element_K(), i)));
893 let lhs = KY.mul_ref(&f, &h);
895 let rhs = KY.mul_ref(&g, &h);
896
897 let gcd = <_ as PolyTFracGCDRing>::gcd(&KY, &lhs, &rhs);
898 assert!(KY.divides(&lhs, &gcd));
901 assert!(KY.divides(&rhs, &gcd));
902 assert!(KY.divides(&gcd, &h));
903 }
904}