1use std::fmt::{Debug, Display};
2
3use crate::algorithms::linsolve::LinSolveRing;
4use crate::algorithms::miller_rabin::is_prime;
5use crate::algorithms::poly_factor::FactorPolyField;
6use crate::algorithms::poly_gcd::PolyTFracGCDRing;
7use crate::computation::no_error;
8use crate::delegate::*;
9use crate::divisibility::*;
10use crate::field::Field;
11use crate::homomorphism::*;
12use crate::integer::*;
13use crate::ordered::OrderedRing;
14use crate::ring::*;
15use crate::rings::field::{AsField, AsFieldBase};
16use crate::rings::finite::FiniteRing;
17use crate::rings::zn::*;
18use crate::seq::*;
19use crate::specialization::FiniteRingSpecializable;
20
21#[stability::unstable(feature = "enable")]
87pub trait PolyGCDLocallyDomain: Domain + DivisibilityRing + FiniteRingSpecializable {
88 type LocalRingBase<'ring>: ?Sized + LinSolveRing
90 where
91 Self: 'ring;
92
93 type LocalRing<'ring>: RingStore<Type = Self::LocalRingBase<'ring>> + Clone
94 where
95 Self: 'ring;
96
97 type LocalFieldBase<'ring>: ?Sized + PolyTFracGCDRing + FactorPolyField + Field + SelfIso + FiniteRingSpecializable
102 where
103 Self: 'ring;
104
105 type LocalField<'ring>: RingStore<Type = Self::LocalFieldBase<'ring>> + Clone
106 where
107 Self: 'ring;
108
109 type SuitableIdeal<'ring>
112 where
113 Self: 'ring;
114
115 fn heuristic_exponent<'ring, 'a, I>(
122 &self,
123 _ideal: &Self::SuitableIdeal<'ring>,
124 _poly_deg: usize,
125 _coefficients: I,
126 ) -> usize
127 where
128 I: Iterator<Item = &'a Self::Element>,
129 Self: 'a,
130 Self: 'ring;
131
132 fn random_suitable_ideal<'ring, F>(&'ring self, rng: F) -> Self::SuitableIdeal<'ring>
134 where
135 F: FnMut() -> u64;
136
137 fn maximal_ideal_factor_count<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>) -> usize
139 where
140 Self: 'ring;
141
142 fn local_field_at<'ring>(
146 &self,
147 ideal: &Self::SuitableIdeal<'ring>,
148 max_ideal_idx: usize,
149 ) -> Self::LocalField<'ring>
150 where
151 Self: 'ring;
152
153 fn local_ring_at<'ring>(
155 &self,
156 ideal: &Self::SuitableIdeal<'ring>,
157 e: usize,
158 max_ideal_idx: usize,
159 ) -> Self::LocalRing<'ring>
160 where
161 Self: 'ring;
162
163 fn reduce_ring_el<'ring>(
169 &self,
170 ideal: &Self::SuitableIdeal<'ring>,
171 to: (&Self::LocalRingBase<'ring>, usize),
172 max_ideal_idx: usize,
173 x: Self::Element,
174 ) -> El<Self::LocalRing<'ring>>
175 where
176 Self: 'ring;
177
178 fn reduce_partial<'ring>(
184 &self,
185 ideal: &Self::SuitableIdeal<'ring>,
186 from: (&Self::LocalRingBase<'ring>, usize),
187 to: (&Self::LocalRingBase<'ring>, usize),
188 max_ideal_idx: usize,
189 x: El<Self::LocalRing<'ring>>,
190 ) -> El<Self::LocalRing<'ring>>
191 where
192 Self: 'ring;
193
194 fn base_ring_to_field<'ring>(
196 &self,
197 ideal: &Self::SuitableIdeal<'ring>,
198 from: &Self::LocalRingBase<'ring>,
199 to: &Self::LocalFieldBase<'ring>,
200 max_ideal_idx: usize,
201 x: El<Self::LocalRing<'ring>>,
202 ) -> El<Self::LocalField<'ring>>
203 where
204 Self: 'ring;
205
206 fn field_to_base_ring<'ring>(
208 &self,
209 ideal: &Self::SuitableIdeal<'ring>,
210 from: &Self::LocalFieldBase<'ring>,
211 to: &Self::LocalRingBase<'ring>,
212 max_ideal_idx: usize,
213 x: El<Self::LocalField<'ring>>,
214 ) -> El<Self::LocalRing<'ring>>
215 where
216 Self: 'ring;
217
218 fn lift_partial<'ring>(
222 &self,
223 ideal: &Self::SuitableIdeal<'ring>,
224 from: (&Self::LocalRingBase<'ring>, usize),
225 to: (&Self::LocalRingBase<'ring>, usize),
226 max_ideal_idx: usize,
227 x: El<Self::LocalRing<'ring>>,
228 ) -> El<Self::LocalRing<'ring>>
229 where
230 Self: 'ring;
231
232 fn reconstruct_ring_el<'local, 'element, 'ring, V1, V2>(
237 &self,
238 ideal: &Self::SuitableIdeal<'ring>,
239 from: V1,
240 e: usize,
241 x: V2,
242 ) -> Self::Element
243 where
244 Self: 'ring,
245 V1: VectorFn<&'local Self::LocalRing<'ring>>,
246 V2: VectorFn<&'element El<Self::LocalRing<'ring>>>,
247 Self::LocalRing<'ring>: 'local,
248 El<Self::LocalRing<'ring>>: 'element,
249 'ring: 'local + 'element;
250
251 fn dbg_ideal<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, out: &mut std::fmt::Formatter) -> std::fmt::Result
252 where
253 Self: 'ring;
254}
255
256#[stability::unstable(feature = "enable")]
259pub trait IntegerPolyGCDRing: PolyGCDLocallyDomain {
260 type LocalRingAsZnBase<'ring>: ?Sized + CanIsoFromTo<Self::LocalRingBase<'ring>> + ZnRing + SelfIso
263 where
264 Self: 'ring;
265
266 type LocalRingAsZn<'ring>: RingStore<Type = Self::LocalRingAsZnBase<'ring>> + Clone
267 where
268 Self: 'ring;
269
270 fn local_ring_as_zn<'a, 'ring>(&self, local_field: &'a Self::LocalRing<'ring>) -> &'a Self::LocalRingAsZn<'ring>;
271
272 fn local_ring_into_zn<'ring>(&self, local_field: Self::LocalRing<'ring>) -> Self::LocalRingAsZn<'ring>;
273
274 fn principal_ideal_generator<'ring>(&self, p: &Self::SuitableIdeal<'ring>) -> El<BigIntRing>
275 where
276 Self: 'ring,
277 {
278 assert_eq!(1, self.maximal_ideal_factor_count(p));
279 let Fp = self.local_ring_at(p, 1, 0);
280 let Fp = self.local_ring_as_zn(&Fp);
281 return int_cast(
282 Fp.integer_ring().clone_el(Fp.modulus()),
283 BigIntRing::RING,
284 Fp.integer_ring(),
285 );
286 }
287}
288
289#[stability::unstable(feature = "enable")]
290pub struct IdealDisplayWrapper<'a, 'ring, R: 'ring + ?Sized + PolyGCDLocallyDomain> {
291 ring: &'a R,
292 ideal: &'a R::SuitableIdeal<'ring>,
293}
294
295impl<'a, 'ring, R: 'ring + ?Sized + PolyGCDLocallyDomain> IdealDisplayWrapper<'a, 'ring, R> {
296 #[stability::unstable(feature = "enable")]
297 pub fn new(ring: &'a R, ideal: &'a R::SuitableIdeal<'ring>) -> Self { Self { ring, ideal } }
298}
299
300impl<'a, 'ring, R: 'ring + ?Sized + PolyGCDLocallyDomain> Display for IdealDisplayWrapper<'a, 'ring, R> {
301 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.ring.dbg_ideal(self.ideal, f) }
302}
303
304#[stability::unstable(feature = "enable")]
307pub struct PolyGCDLocallyReductionMap<'ring, 'data, 'local, R>
308where
309 R: 'ring + ?Sized + PolyGCDLocallyDomain,
310 'ring: 'data,
311{
312 ring: RingRef<'data, R>,
313 ideal: &'data R::SuitableIdeal<'ring>,
314 to: (&'local R::LocalRing<'ring>, usize),
315 max_ideal_idx: usize,
316}
317
318impl<'ring, 'data, 'local, R> PolyGCDLocallyReductionMap<'ring, 'data, 'local, R>
319where
320 R: 'ring + ?Sized + PolyGCDLocallyDomain,
321 'ring: 'data,
322{
323 #[stability::unstable(feature = "enable")]
324 pub fn new(
325 ring: &'data R,
326 ideal: &'data R::SuitableIdeal<'ring>,
327 to: &'local R::LocalRing<'ring>,
328 to_e: usize,
329 max_ideal_idx: usize,
330 ) -> Self {
331 assert!(to.get_ring() == ring.local_ring_at(ideal, to_e, max_ideal_idx).get_ring());
332 Self {
333 ring: RingRef::new(ring),
334 ideal,
335 to: (to, to_e),
336 max_ideal_idx,
337 }
338 }
339}
340
341impl<'ring, 'data, 'local, R> Homomorphism<R, R::LocalRingBase<'ring>>
342 for PolyGCDLocallyReductionMap<'ring, 'data, 'local, R>
343where
344 R: 'ring + ?Sized + PolyGCDLocallyDomain,
345 'ring: 'data,
346{
347 type CodomainStore = &'local R::LocalRing<'ring>;
348 type DomainStore = RingRef<'data, R>;
349
350 fn codomain(&self) -> &Self::CodomainStore { &self.to.0 }
351
352 fn domain(&self) -> &Self::DomainStore { &self.ring }
353
354 fn map(&self, x: <R as RingBase>::Element) -> <R::LocalRingBase<'ring> as RingBase>::Element {
355 self.ring
356 .get_ring()
357 .reduce_ring_el(self.ideal, (self.to.0.get_ring(), self.to.1), self.max_ideal_idx, x)
358 }
359}
360
361#[stability::unstable(feature = "enable")]
364pub struct PolyGCDLocallyIntermediateReductionMap<'ring, 'data, 'local, R>
365where
366 R: 'ring + ?Sized + PolyGCDLocallyDomain,
367 'ring: 'data,
368{
369 ring: RingRef<'data, R>,
370 ideal: &'data R::SuitableIdeal<'ring>,
371 from: (&'local R::LocalRing<'ring>, usize),
372 to: (&'local R::LocalRing<'ring>, usize),
373 max_ideal_idx: usize,
374}
375
376impl<'ring, 'data, 'local, R> PolyGCDLocallyIntermediateReductionMap<'ring, 'data, 'local, R>
377where
378 R: 'ring + ?Sized + PolyGCDLocallyDomain,
379 'ring: 'data,
380{
381 #[stability::unstable(feature = "enable")]
382 pub fn new(
383 ring: &'data R,
384 ideal: &'data R::SuitableIdeal<'ring>,
385 from: &'local R::LocalRing<'ring>,
386 from_e: usize,
387 to: &'local R::LocalRing<'ring>,
388 to_e: usize,
389 max_ideal_idx: usize,
390 ) -> Self {
391 assert!(ring.local_ring_at(ideal, from_e, max_ideal_idx).get_ring() == from.get_ring());
392 assert!(ring.local_ring_at(ideal, to_e, max_ideal_idx).get_ring() == to.get_ring());
393 Self {
394 ring: RingRef::new(ring),
395 ideal,
396 from: (from, from_e),
397 to: (to, to_e),
398 max_ideal_idx,
399 }
400 }
401
402 #[stability::unstable(feature = "enable")]
403 pub fn parent_ring<'a>(&'a self) -> RingRef<'a, R> { RingRef::new(self.ring.get_ring()) }
404
405 #[stability::unstable(feature = "enable")]
406 pub fn from_e(&self) -> usize { self.from.1 }
407
408 #[stability::unstable(feature = "enable")]
409 pub fn to_e(&self) -> usize { self.to.1 }
410
411 #[stability::unstable(feature = "enable")]
412 pub fn ideal<'a>(&'a self) -> &'a R::SuitableIdeal<'ring> { &self.ideal }
413
414 #[stability::unstable(feature = "enable")]
415 pub fn max_ideal_idx(&self) -> usize { self.max_ideal_idx }
416}
417
418impl<'ring, 'data, 'local, R> Homomorphism<R::LocalRingBase<'ring>, R::LocalRingBase<'ring>>
419 for PolyGCDLocallyIntermediateReductionMap<'ring, 'data, 'local, R>
420where
421 R: 'ring + ?Sized + PolyGCDLocallyDomain,
422 'ring: 'data,
423{
424 type CodomainStore = &'local R::LocalRing<'ring>;
425 type DomainStore = &'local R::LocalRing<'ring>;
426
427 fn codomain(&self) -> &Self::CodomainStore { &self.to.0 }
428
429 fn domain(&self) -> &Self::DomainStore { &self.from.0 }
430
431 fn map(&self, x: <R::LocalRingBase<'ring> as RingBase>::Element) -> <R::LocalRingBase<'ring> as RingBase>::Element {
432 self.ring.get_ring().reduce_partial(
433 self.ideal,
434 (self.from.0.get_ring(), self.from.1),
435 (self.to.0.get_ring(), self.to.1),
436 self.max_ideal_idx,
437 x,
438 )
439 }
440}
441
442#[stability::unstable(feature = "enable")]
446pub struct PolyGCDLocallyBaseRingToFieldIso<'ring, 'data, 'local, R>
447where
448 R: 'ring + ?Sized + PolyGCDLocallyDomain,
449 'ring: 'data,
450{
451 ring: RingRef<'data, R>,
452 ideal: &'data R::SuitableIdeal<'ring>,
453 from: RingRef<'local, R::LocalRingBase<'ring>>,
454 to: RingRef<'local, R::LocalFieldBase<'ring>>,
455 max_ideal_idx: usize,
456}
457
458impl<'ring, 'data, 'local, R> PolyGCDLocallyBaseRingToFieldIso<'ring, 'data, 'local, R>
459where
460 R: 'ring + ?Sized + PolyGCDLocallyDomain,
461 'ring: 'data,
462{
463 #[stability::unstable(feature = "enable")]
464 pub fn new(
465 ring: &'data R,
466 ideal: &'data R::SuitableIdeal<'ring>,
467 from: &'local R::LocalRingBase<'ring>,
468 to: &'local R::LocalFieldBase<'ring>,
469 max_ideal_idx: usize,
470 ) -> Self {
471 assert!(ring.local_ring_at(ideal, 1, max_ideal_idx).get_ring() == from);
472 assert!(ring.local_field_at(ideal, max_ideal_idx).get_ring() == to);
473 Self {
474 ring: RingRef::new(ring),
475 ideal,
476 from: RingRef::new(from),
477 to: RingRef::new(to),
478 max_ideal_idx,
479 }
480 }
481
482 #[stability::unstable(feature = "enable")]
483 pub fn inv(&self) -> PolyGCDLocallyFieldToBaseRingIso<'ring, 'data, 'local, R> {
484 PolyGCDLocallyFieldToBaseRingIso {
485 ring: self.ring,
486 ideal: self.ideal,
487 from: self.to,
488 to: self.from,
489 max_ideal_idx: self.max_ideal_idx,
490 }
491 }
492}
493
494impl<'ring, 'data, 'local, R> Homomorphism<R::LocalRingBase<'ring>, R::LocalFieldBase<'ring>>
495 for PolyGCDLocallyBaseRingToFieldIso<'ring, 'data, 'local, R>
496where
497 R: 'ring + ?Sized + PolyGCDLocallyDomain,
498 'ring: 'data,
499{
500 type DomainStore = RingRef<'local, R::LocalRingBase<'ring>>;
501 type CodomainStore = RingRef<'local, R::LocalFieldBase<'ring>>;
502
503 fn codomain(&self) -> &Self::CodomainStore { &self.to }
504
505 fn domain(&self) -> &Self::DomainStore { &self.from }
506
507 fn map(
508 &self,
509 x: <R::LocalRingBase<'ring> as RingBase>::Element,
510 ) -> <R::LocalFieldBase<'ring> as RingBase>::Element {
511 self.ring.get_ring().base_ring_to_field(
512 self.ideal,
513 self.from.get_ring(),
514 self.to.get_ring(),
515 self.max_ideal_idx,
516 x,
517 )
518 }
519}
520
521#[stability::unstable(feature = "enable")]
525pub struct PolyGCDLocallyFieldToBaseRingIso<'ring, 'data, 'local, R>
526where
527 R: 'ring + ?Sized + PolyGCDLocallyDomain,
528 'ring: 'data,
529{
530 ring: RingRef<'data, R>,
531 ideal: &'data R::SuitableIdeal<'ring>,
532 to: RingRef<'local, R::LocalRingBase<'ring>>,
533 from: RingRef<'local, R::LocalFieldBase<'ring>>,
534 max_ideal_idx: usize,
535}
536
537impl<'ring, 'data, 'local, R> PolyGCDLocallyFieldToBaseRingIso<'ring, 'data, 'local, R>
538where
539 R: 'ring + ?Sized + PolyGCDLocallyDomain,
540 'ring: 'data,
541{
542 #[stability::unstable(feature = "enable")]
543 pub fn inv(&self) -> PolyGCDLocallyBaseRingToFieldIso<'ring, 'data, 'local, R> {
544 PolyGCDLocallyBaseRingToFieldIso {
545 ring: self.ring,
546 ideal: self.ideal,
547 from: self.to,
548 to: self.from,
549 max_ideal_idx: self.max_ideal_idx,
550 }
551 }
552}
553
554impl<'ring, 'data, 'local, R> Homomorphism<R::LocalFieldBase<'ring>, R::LocalRingBase<'ring>>
555 for PolyGCDLocallyFieldToBaseRingIso<'ring, 'data, 'local, R>
556where
557 R: 'ring + ?Sized + PolyGCDLocallyDomain,
558 'ring: 'data,
559{
560 type DomainStore = RingRef<'local, R::LocalFieldBase<'ring>>;
561 type CodomainStore = RingRef<'local, R::LocalRingBase<'ring>>;
562
563 fn codomain(&self) -> &Self::CodomainStore { &self.to }
564
565 fn domain(&self) -> &Self::DomainStore { &self.from }
566
567 fn map(
568 &self,
569 x: <R::LocalFieldBase<'ring> as RingBase>::Element,
570 ) -> <R::LocalRingBase<'ring> as RingBase>::Element {
571 self.ring.get_ring().field_to_base_ring(
572 self.ideal,
573 self.from.get_ring(),
574 self.to.get_ring(),
575 self.max_ideal_idx,
576 x,
577 )
578 }
579}
580
581#[stability::unstable(feature = "enable")]
588pub struct ReductionContext<'ring, 'data, R>
589where
590 R: 'ring + ?Sized + PolyGCDLocallyDomain,
591 'ring: 'data,
592{
593 ring: RingRef<'data, R>,
594 ideal: &'data R::SuitableIdeal<'ring>,
595 from_e: usize,
596 from: Vec<R::LocalRing<'ring>>,
597 to: Vec<R::LocalRing<'ring>>,
598 to_fields: Vec<R::LocalField<'ring>>,
599}
600
601impl<'ring, 'data, R> ReductionContext<'ring, 'data, R>
602where
603 R: 'ring + ?Sized + PolyGCDLocallyDomain,
604 'ring: 'data,
605{
606 #[stability::unstable(feature = "enable")]
607 pub fn new(ring: &'data R, ideal: &'data R::SuitableIdeal<'ring>, e: usize) -> Self {
608 assert!(e >= 1);
609 let maximal_ideal_factor_count = ring.maximal_ideal_factor_count(ideal);
610 Self {
611 ring: RingRef::new(ring),
612 ideal,
613 from_e: e,
614 from: (0..maximal_ideal_factor_count)
615 .map(|idx| ring.local_ring_at(ideal, e, idx))
616 .collect::<Vec<_>>(),
617 to: (0..maximal_ideal_factor_count)
618 .map(|idx| ring.local_ring_at(ideal, 1, idx))
619 .collect::<Vec<_>>(),
620 to_fields: (0..maximal_ideal_factor_count)
621 .map(|idx| ring.local_field_at(ideal, idx))
622 .collect::<Vec<_>>(),
623 }
624 }
625
626 #[stability::unstable(feature = "enable")]
627 pub fn ideal(&self) -> &'data R::SuitableIdeal<'ring> { self.ideal }
628
629 #[stability::unstable(feature = "enable")]
630 pub fn main_ring_to_field_reduction<'local>(
631 &'local self,
632 max_ideal_idx: usize,
633 ) -> PolyGCDLocallyReductionMap<'ring, 'data, 'local, R> {
634 PolyGCDLocallyReductionMap {
635 ideal: self.ideal,
636 ring: self.ring,
637 to: (self.to.at(max_ideal_idx), 1),
638 max_ideal_idx,
639 }
640 }
641
642 #[stability::unstable(feature = "enable")]
643 pub fn main_ring_to_intermediate_ring_reduction<'local>(
644 &'local self,
645 max_ideal_idx: usize,
646 ) -> PolyGCDLocallyReductionMap<'ring, 'data, 'local, R> {
647 PolyGCDLocallyReductionMap {
648 ideal: self.ideal,
649 ring: self.ring,
650 to: (self.from.at(max_ideal_idx), self.from_e),
651 max_ideal_idx,
652 }
653 }
654
655 #[stability::unstable(feature = "enable")]
656 pub fn intermediate_ring_to_field_reduction<'local>(
657 &'local self,
658 max_ideal_idx: usize,
659 ) -> PolyGCDLocallyIntermediateReductionMap<'ring, 'data, 'local, R> {
660 PolyGCDLocallyIntermediateReductionMap {
661 from: (&self.from[max_ideal_idx], self.from_e),
662 to: (&self.to[max_ideal_idx], 1),
663 max_ideal_idx,
664 ring: self.ring,
665 ideal: self.ideal,
666 }
667 }
668
669 #[stability::unstable(feature = "enable")]
670 pub fn base_ring_to_field_iso<'local>(
671 &'local self,
672 max_ideal_idx: usize,
673 ) -> PolyGCDLocallyBaseRingToFieldIso<'ring, 'data, 'local, R> {
674 PolyGCDLocallyBaseRingToFieldIso {
675 ring: self.ring,
676 ideal: self.ideal,
677 from: RingRef::new(self.to[max_ideal_idx].get_ring()),
678 to: RingRef::new(self.to_fields[max_ideal_idx].get_ring()),
679 max_ideal_idx,
680 }
681 }
682
683 #[stability::unstable(feature = "enable")]
684 pub fn len(&self) -> usize { self.from.len() }
685
686 #[stability::unstable(feature = "enable")]
687 pub fn reconstruct_ring_el<'local, V>(&self, els: V) -> R::Element
688 where
689 V: VectorFn<&'local El<R::LocalRing<'ring>>>,
690 El<R::LocalRing<'ring>>: 'local,
691 'ring: 'local,
692 {
693 fn do_reconstruction<'ring, 'local, R, V>(
694 ring: &R,
695 ideal: &R::SuitableIdeal<'ring>,
696 local_rings: &[R::LocalRing<'ring>],
697 e: usize,
698 els: V,
699 ) -> R::Element
700 where
701 R: 'ring + ?Sized + PolyGCDLocallyDomain,
702 V: VectorFn<&'local El<R::LocalRing<'ring>>>,
703 El<R::LocalRing<'ring>>: 'local,
704 'ring: 'local,
705 {
706 ring.reconstruct_ring_el(ideal, local_rings.as_fn(), e, els)
707 }
708 do_reconstruction(self.ring.get_ring(), self.ideal, &self.from[..], self.from_e, els)
709 }
710}
711
712#[stability::unstable(feature = "enable")]
713pub const INTRING_HEURISTIC_FACTOR_SIZE_OVER_POLY_SIZE_FACTOR: f64 = 0.25;
714
715#[macro_export]
724macro_rules! impl_poly_gcd_locally_for_ZZ {
725 (IntegerPolyGCDRing for $int_ring_type:ty) => {
726 impl_poly_gcd_locally_for_ZZ!{ <{}> IntegerPolyGCDRing for $int_ring_type where }
727 };
728 (<{$($gen_args:tt)*}> IntegerPolyGCDRing for $int_ring_type:ty where $($constraints:tt)*) => {
729
730 impl<$($gen_args)*> $crate::reduce_lift::poly_factor_gcd::PolyGCDLocallyDomain for $int_ring_type
731 where $($constraints)*
732 {
733 type LocalRing<'ring> = $crate::rings::zn::zn_big::Zn<BigIntRing>
734 where Self: 'ring;
735 type LocalRingBase<'ring> = $crate::rings::zn::zn_big::ZnBase<BigIntRing>
736 where Self: 'ring;
737 type LocalFieldBase<'ring> = $crate::rings::field::AsFieldBase<$crate::rings::zn::zn_64::Zn>
738 where Self: 'ring;
739 type LocalField<'ring> = $crate::rings::field::AsField<$crate::rings::zn::zn_64::Zn>
740 where Self: 'ring;
741 type SuitableIdeal<'ring> = i64
742 where Self: 'ring;
743
744 fn reconstruct_ring_el<'local, 'element, 'ring, V1, V2>(&self, _p: &Self::SuitableIdeal<'ring>, from: V1, _e: usize, x: V2) -> Self::Element
745 where Self: 'ring,
746 V1: $crate::seq::VectorFn<&'local Self::LocalRing<'ring>>,
747 V2: $crate::seq::VectorFn<&'element El<Self::LocalRing<'ring>>>
748 {
749 use $crate::rings::zn::*;
750 #[allow(unused)]
751 use $crate::seq::*;
752 assert_eq!(1, from.len());
753 assert_eq!(1, x.len());
754 int_cast(from.at(0).smallest_lift(from.at(0).clone_el(x.at(0))), RingRef::new(self), BigIntRing::RING)
755 }
756
757 fn maximal_ideal_factor_count<'ring>(&self, _p: &Self::SuitableIdeal<'ring>) -> usize
758 where Self: 'ring
759 {
760 1
761 }
762
763 fn lift_partial<'ring>(&self, _p: &Self::SuitableIdeal<'ring>, from: (&Self::LocalRingBase<'ring>, usize), to: (&Self::LocalRingBase<'ring>, usize), max_ideal_idx: usize, x: El<Self::LocalRing<'ring>>) -> El<Self::LocalRing<'ring>>
764 where Self: 'ring
765 {
766 use $crate::rings::zn::*;
767 use $crate::homomorphism::*;
768
769 assert_eq!(0, max_ideal_idx);
770 assert!(from.1 <= to.1);
771 let hom = RingRef::new(to.0).into_can_hom(to.0.integer_ring()).ok().unwrap();
772 return hom.map(from.0.any_lift(x));
773 }
774
775 fn local_field_at<'ring>(&self, p: &Self::SuitableIdeal<'ring>, max_ideal_idx: usize) -> Self::LocalField<'ring>
776 where Self: 'ring
777 {
778 use $crate::rings::zn::*;
779
780 assert_eq!(0, max_ideal_idx);
781 $crate::rings::zn::zn_64::Zn::new(*p as u64).as_field().ok().unwrap()
782 }
783
784 fn local_ring_at<'ring>(&self, p: &Self::SuitableIdeal<'ring>, e: usize, max_ideal_idx: usize) -> Self::LocalRing<'ring>
785 where Self: 'ring
786 {
787 assert_eq!(0, max_ideal_idx);
788 $crate::rings::zn::zn_big::Zn::new(BigIntRing::RING, BigIntRing::RING.pow(int_cast(*p, BigIntRing::RING, StaticRing::<i64>::RING), e))
789 }
790
791 fn random_suitable_ideal<'ring, F>(&'ring self, rng: F) -> Self::SuitableIdeal<'ring>
792 where F: FnMut() -> u64
793 {
794 let lower_bound = StaticRing::<i64>::RING.get_ring().get_uniformly_random_bits(24, rng);
795 return $crate::algorithms::miller_rabin::next_prime(StaticRing::<i64>::RING, lower_bound);
796 }
797
798 fn base_ring_to_field<'ring>(&self, _ideal: &Self::SuitableIdeal<'ring>, from: &Self::LocalRingBase<'ring>, to: &Self::LocalFieldBase<'ring>, max_ideal_idx: usize, x: El<Self::LocalRing<'ring>>) -> El<Self::LocalField<'ring>>
799 where Self: 'ring
800 {
801 assert_eq!(0, max_ideal_idx);
802 assert_eq!(from.characteristic(StaticRing::<i64>::RING).unwrap(), to.characteristic(StaticRing::<i64>::RING).unwrap());
803 <_ as $crate::rings::zn::ZnRing>::from_int_promise_reduced(to, $crate::integer::int_cast(
804 <_ as $crate::rings::zn::ZnRing>::smallest_positive_lift(from, x),
805 <_ as $crate::rings::zn::ZnRing>::integer_ring(to),
806 <_ as $crate::rings::zn::ZnRing>::integer_ring(from),
807 ))
808 }
809
810 fn field_to_base_ring<'ring>(&self, _ideal: &Self::SuitableIdeal<'ring>, from: &Self::LocalFieldBase<'ring>, to: &Self::LocalRingBase<'ring>, max_ideal_idx: usize, x: El<Self::LocalField<'ring>>) -> El<Self::LocalRing<'ring>>
811 where Self: 'ring
812 {
813
814 assert_eq!(0, max_ideal_idx);
815 assert_eq!(from.characteristic(StaticRing::<i64>::RING).unwrap(), to.characteristic(StaticRing::<i64>::RING).unwrap());
816 <_ as $crate::rings::zn::ZnRing>::from_int_promise_reduced(to, $crate::integer::int_cast(
817 <_ as $crate::rings::zn::ZnRing>::smallest_positive_lift(from, x),
818 <_ as $crate::rings::zn::ZnRing>::integer_ring(to),
819 <_ as $crate::rings::zn::ZnRing>::integer_ring(from),
820 ))
821 }
822
823 fn reduce_ring_el<'ring>(&self, _p: &Self::SuitableIdeal<'ring>, to: (&Self::LocalRingBase<'ring>, usize), max_ideal_idx: usize, x: Self::Element) -> El<Self::LocalRing<'ring>>
824 where Self: 'ring
825 {
826 use $crate::homomorphism::*;
827
828 assert_eq!(0, max_ideal_idx);
829 let self_ref = RingRef::new(self);
830 let hom = RingRef::new(to.0).into_can_hom(&self_ref).ok().unwrap();
831 return hom.map(x);
832 }
833
834 fn reduce_partial<'ring>(&self, _p: &Self::SuitableIdeal<'ring>, from: (&Self::LocalRingBase<'ring>, usize), to: (&Self::LocalRingBase<'ring>, usize), max_ideal_idx: usize, x: El<Self::LocalRing<'ring>>) -> El<Self::LocalRing<'ring>>
835 where Self: 'ring
836 {
837 use $crate::rings::zn::*;
838 use $crate::homomorphism::*;
839
840 assert_eq!(0, max_ideal_idx);
841 assert!(from.1 >= to.1);
842 let hom = RingRef::new(to.0).into_can_hom(to.0.integer_ring()).ok().unwrap();
843 return hom.map(from.0.smallest_lift(x));
844 }
845
846 fn heuristic_exponent<'ring, 'a, I>(&self, p: &i64, poly_deg: usize, coefficients: I) -> usize
847 where I: Iterator<Item = &'a Self::Element>,
848 Self: 'a,
849 Self: 'ring
850 {
851 let log2_max_coeff = coefficients.map(|c| RingRef::new(self).abs_log2_ceil(c).unwrap_or(0)).max().unwrap_or(0);
852 return ((log2_max_coeff as f64 + poly_deg as f64) / (*p as f64).log2() * $crate::reduce_lift::poly_factor_gcd::INTRING_HEURISTIC_FACTOR_SIZE_OVER_POLY_SIZE_FACTOR).ceil() as usize + 1;
854 }
855
856 fn dbg_ideal<'ring>(&self, p: &Self::SuitableIdeal<'ring>, out: &mut std::fmt::Formatter) -> std::fmt::Result
857 where Self: 'ring
858 {
859 write!(out, "({})", p)
860 }
861 }
862
863 impl<$($gen_args)*> $crate::reduce_lift::poly_factor_gcd::IntegerPolyGCDRing for $int_ring_type
864 where $($constraints)*
865 {
866 type LocalRingAsZnBase<'ring> = Self::LocalRingBase<'ring>
867 where Self: 'ring;
868
869 type LocalRingAsZn<'ring> = Self::LocalRing<'ring>
870 where Self: 'ring;
871
872 fn local_ring_as_zn<'a, 'ring>(&self, local_field: &'a Self::LocalRing<'ring>) -> &'a Self::LocalRingAsZn<'ring>
873 where Self: 'ring
874 {
875 local_field
876 }
877
878 fn local_ring_into_zn<'ring>(&self, local_field: Self::LocalRing<'ring>) -> Self::LocalRingAsZn<'ring>
879 where Self: 'ring
880 {
881 local_field
882 }
883 }
884 };
885}
886
887#[allow(unused)]
896impl<R> PolyGCDLocallyDomain for R
897where
898 R: ?Sized + FiniteRing + FactorPolyField + Field + SelfIso,
899{
900 type LocalRingBase<'ring>
901 = Self
902 where
903 Self: 'ring;
904 type LocalRing<'ring>
905 = RingRef<'ring, Self>
906 where
907 Self: 'ring;
908
909 type LocalFieldBase<'ring>
910 = Self
911 where
912 Self: 'ring;
913 type LocalField<'ring>
914 = RingRef<'ring, Self>
915 where
916 Self: 'ring;
917 type SuitableIdeal<'ring>
918 = RingRef<'ring, Self>
919 where
920 Self: 'ring;
921
922 fn heuristic_exponent<'ring, 'element, IteratorType>(
923 &self,
924 _maximal_ideal: &Self::SuitableIdeal<'ring>,
925 _poly_deg: usize,
926 _coefficients: IteratorType,
927 ) -> usize
928 where
929 IteratorType: Iterator<Item = &'element Self::Element>,
930 Self: 'element,
931 Self: 'ring,
932 {
933 unreachable!(
934 "this should never be called for finite fields, since specialized functions are available in this case"
935 )
936 }
937
938 fn maximal_ideal_factor_count<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>) -> usize
939 where
940 Self: 'ring,
941 {
942 unreachable!(
943 "this should never be called for finite fields, since specialized functions are available in this case"
944 )
945 }
946
947 fn random_suitable_ideal<'ring, RandomNumberFunction>(
948 &'ring self,
949 rng: RandomNumberFunction,
950 ) -> Self::SuitableIdeal<'ring>
951 where
952 RandomNumberFunction: FnMut() -> u64,
953 {
954 unreachable!(
955 "this should never be called for finite fields, since specialized functions are available in this case"
956 )
957 }
958
959 fn local_field_at<'ring>(&self, p: &Self::SuitableIdeal<'ring>, max_ideal_idx: usize) -> Self::LocalField<'ring>
960 where
961 Self: 'ring,
962 {
963 unreachable!(
964 "this should never be called for finite fields, since specialized functions are available in this case"
965 )
966 }
967
968 fn local_ring_at<'ring>(
969 &self,
970 p: &Self::SuitableIdeal<'ring>,
971 e: usize,
972 max_ideal_idx: usize,
973 ) -> Self::LocalRing<'ring>
974 where
975 Self: 'ring,
976 {
977 unreachable!(
978 "this should never be called for finite fields, since specialized functions are available in this case"
979 )
980 }
981
982 fn reduce_ring_el<'ring>(
983 &self,
984 p: &Self::SuitableIdeal<'ring>,
985 to: (&Self::LocalRingBase<'ring>, usize),
986 max_ideal_idx: usize,
987 x: Self::Element,
988 ) -> El<Self::LocalRing<'ring>>
989 where
990 Self: 'ring,
991 {
992 unreachable!(
993 "this should never be called for finite fields, since specialized functions are available in this case"
994 )
995 }
996
997 fn base_ring_to_field<'ring>(
998 &self,
999 _ideal: &Self::SuitableIdeal<'ring>,
1000 from: &Self::LocalRingBase<'ring>,
1001 to: &Self::LocalFieldBase<'ring>,
1002 max_ideal_idx: usize,
1003 x: El<Self::LocalRing<'ring>>,
1004 ) -> El<Self::LocalField<'ring>>
1005 where
1006 Self: 'ring,
1007 {
1008 unreachable!(
1009 "this should never be called for finite fields, since specialized functions are available in this case"
1010 )
1011 }
1012
1013 fn field_to_base_ring<'ring>(
1014 &self,
1015 _ideal: &Self::SuitableIdeal<'ring>,
1016 from: &Self::LocalFieldBase<'ring>,
1017 to: &Self::LocalRingBase<'ring>,
1018 max_ideal_idx: usize,
1019 x: El<Self::LocalField<'ring>>,
1020 ) -> El<Self::LocalRing<'ring>>
1021 where
1022 Self: 'ring,
1023 {
1024 unreachable!(
1025 "this should never be called for finite fields, since specialized functions are available in this case"
1026 )
1027 }
1028
1029 fn reduce_partial<'ring>(
1030 &self,
1031 p: &Self::SuitableIdeal<'ring>,
1032 from: (&Self::LocalRingBase<'ring>, usize),
1033 to: (&Self::LocalRingBase<'ring>, usize),
1034 max_ideal_idx: usize,
1035 x: El<Self::LocalRing<'ring>>,
1036 ) -> El<Self::LocalRing<'ring>>
1037 where
1038 Self: 'ring,
1039 {
1040 unreachable!(
1041 "this should never be called for finite fields, since specialized functions are available in this case"
1042 )
1043 }
1044
1045 fn lift_partial<'ring>(
1046 &self,
1047 p: &Self::SuitableIdeal<'ring>,
1048 from: (&Self::LocalRingBase<'ring>, usize),
1049 to: (&Self::LocalRingBase<'ring>, usize),
1050 max_ideal_idx: usize,
1051 x: El<Self::LocalRing<'ring>>,
1052 ) -> El<Self::LocalRing<'ring>>
1053 where
1054 Self: 'ring,
1055 {
1056 unreachable!(
1057 "this should never be called for finite fields, since specialized functions are available in this case"
1058 )
1059 }
1060
1061 fn reconstruct_ring_el<'local, 'element, 'ring, V1, V2>(
1062 &self,
1063 p: &Self::SuitableIdeal<'ring>,
1064 from: V1,
1065 e: usize,
1066 x: V2,
1067 ) -> Self::Element
1068 where
1069 Self: 'ring,
1070 V1: VectorFn<&'local Self::LocalRing<'ring>>,
1071 V2: VectorFn<&'element El<Self::LocalRing<'ring>>>,
1072 'ring: 'local + 'element,
1073 Self::LocalRing<'ring>: 'local,
1074 El<Self::LocalRing<'ring>>: 'element,
1075 {
1076 unreachable!(
1077 "this should never be called for finite fields, since specialized functions are available in this case"
1078 )
1079 }
1080
1081 fn dbg_ideal<'ring>(&self, p: &Self::SuitableIdeal<'ring>, out: &mut std::fmt::Formatter) -> std::fmt::Result
1082 where
1083 Self: 'ring,
1084 {
1085 unreachable!(
1086 "this should never be called for finite fields, since specialized functions are available in this case"
1087 )
1088 }
1089}
1090
1091#[stability::unstable(feature = "enable")]
1092pub struct IntegersWithLocalZnQuotient<'a, R>
1093where
1094 R: Sized + SelfIso + ZnRing + FromModulusCreateableZnRing + LinSolveRing + Clone,
1095{
1096 integers: &'a R::IntegerRing,
1097 prime: El<R::IntegerRing>,
1098}
1099
1100impl<'a, R> IntegersWithLocalZnQuotient<'a, R>
1101where
1102 R: Sized + SelfIso + ZnRing + FromModulusCreateableZnRing + LinSolveRing + Clone,
1103{
1104 #[stability::unstable(feature = "enable")]
1105 pub fn new(integers: &'a R::IntegerRing, prime: El<R::IntegerRing>) -> Self {
1106 assert!(is_prime(integers, &prime, 10));
1107 return Self { integers, prime };
1108 }
1109
1110 #[stability::unstable(feature = "enable")]
1111 pub fn reduction_context<'b>(&'b self, from_e: usize) -> ReductionContext<'b, 'b, Self> {
1112 ReductionContext {
1113 ring: RingRef::new(self),
1114 ideal: &self.prime,
1115 from_e,
1116 from: vec![self.local_ring_at(&self.prime, from_e, 0)],
1117 to: vec![self.local_ring_at(&self.prime, 1, 0)],
1118 to_fields: vec![self.local_field_at(&self.prime, 0)],
1119 }
1120 }
1121}
1122
1123impl<'a, R> Debug for IntegersWithLocalZnQuotient<'a, R>
1124where
1125 R: ?Sized + SelfIso + ZnRing + FromModulusCreateableZnRing + LinSolveRing + Clone,
1126 R::IntegerRingBase: Debug,
1127{
1128 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1129 f.debug_struct("IntegersWithLocalZnQuotient")
1130 .field("integers", &self.integers.get_ring())
1131 .finish()
1132 }
1133}
1134
1135impl<'a, R> PartialEq for IntegersWithLocalZnQuotient<'a, R>
1136where
1137 R: ?Sized + SelfIso + ZnRing + FromModulusCreateableZnRing + LinSolveRing + Clone,
1138{
1139 fn eq(&self, other: &Self) -> bool { self.integers.get_ring() == other.integers.get_ring() }
1140}
1141
1142impl<'a, R> DelegateRing for IntegersWithLocalZnQuotient<'a, R>
1143where
1144 R: Sized + SelfIso + ZnRing + FromModulusCreateableZnRing + LinSolveRing + Clone,
1145{
1146 type Base = <R as ZnRing>::IntegerRingBase;
1147 type Element = El<<R as ZnRing>::IntegerRing>;
1148
1149 fn get_delegate(&self) -> &Self::Base { self.integers.get_ring() }
1150
1151 fn delegate(&self, el: Self::Element) -> <Self::Base as RingBase>::Element { el }
1152 fn delegate_mut<'b>(&self, el: &'b mut Self::Element) -> &'b mut <Self::Base as RingBase>::Element { el }
1153 fn delegate_ref<'b>(&self, el: &'b Self::Element) -> &'b <Self::Base as RingBase>::Element { el }
1154 fn rev_delegate(&self, el: <Self::Base as RingBase>::Element) -> Self::Element { el }
1155}
1156
1157impl<'a, R> OrderedRing for IntegersWithLocalZnQuotient<'a, R>
1158where
1159 R: Sized + SelfIso + ZnRing + FromModulusCreateableZnRing + Clone,
1160{
1161 fn cmp(&self, lhs: &Self::Element, rhs: &Self::Element) -> std::cmp::Ordering {
1162 self.get_delegate().cmp(self.delegate_ref(lhs), self.delegate_ref(rhs))
1163 }
1164 fn abs_cmp(&self, lhs: &Self::Element, rhs: &Self::Element) -> std::cmp::Ordering {
1165 self.get_delegate()
1166 .abs_cmp(self.delegate_ref(lhs), self.delegate_ref(rhs))
1167 }
1168}
1169
1170impl<'a, R> Domain for IntegersWithLocalZnQuotient<'a, R> where
1171 R: Sized + SelfIso + ZnRing + FromModulusCreateableZnRing + Clone
1172{
1173}
1174
1175impl<'a, R> DelegateRingImplFiniteRing for IntegersWithLocalZnQuotient<'a, R> where
1176 R: Sized + SelfIso + ZnRing + FromModulusCreateableZnRing + Clone
1177{
1178}
1179
1180impl<'a, R> DelegateRingImplEuclideanRing for IntegersWithLocalZnQuotient<'a, R> where
1181 R: Sized + SelfIso + ZnRing + FromModulusCreateableZnRing + Clone
1182{
1183}
1184
1185impl<'a, R> crate::reduce_lift::poly_eval::EvalPolyLocallyRing for IntegersWithLocalZnQuotient<'a, R>
1186where
1187 R: Sized + SelfIso + ZnRing + FromModulusCreateableZnRing + Clone,
1188{
1189 type LocalRingBase<'ring>
1190 = <<Self as DelegateRing>::Base as crate::reduce_lift::poly_eval::EvalPolyLocallyRing>::LocalRingBase<'ring>
1191 where
1192 Self: 'ring;
1193 type LocalRing<'ring>
1194 = <<Self as DelegateRing>::Base as crate::reduce_lift::poly_eval::EvalPolyLocallyRing>::LocalRing<'ring>
1195 where
1196 Self: 'ring;
1197 type LocalComputationData<'ring>
1198 = <<Self as DelegateRing>::Base as crate::reduce_lift::poly_eval::EvalPolyLocallyRing>::LocalComputationData<
1199 'ring,
1200 >
1201 where
1202 Self: 'ring;
1203
1204 fn ln_pseudo_norm(&self, el: &Self::Element) -> f64 { self.get_delegate().ln_pseudo_norm(self.delegate_ref(el)) }
1205
1206 fn reduce<'ring>(
1207 &self,
1208 computation: &Self::LocalComputationData<'ring>,
1209 el: &Self::Element,
1210 ) -> Vec<<Self::LocalRingBase<'ring> as RingBase>::Element>
1211 where
1212 Self: 'ring,
1213 {
1214 self.get_delegate().reduce(computation, self.delegate_ref(el))
1215 }
1216
1217 fn local_ring_count<'ring>(&self, computation: &Self::LocalComputationData<'ring>) -> usize
1218 where
1219 Self: 'ring,
1220 {
1221 self.get_delegate().local_ring_count(computation)
1222 }
1223
1224 fn local_ring_at<'ring>(&self, computation: &Self::LocalComputationData<'ring>, i: usize) -> Self::LocalRing<'ring>
1225 where
1226 Self: 'ring,
1227 {
1228 crate::reduce_lift::poly_eval::EvalPolyLocallyRing::local_ring_at(self.get_delegate(), computation, i)
1229 }
1230
1231 fn local_computation<'ring>(&'ring self, ln_pseudo_norm_bound: f64) -> Self::LocalComputationData<'ring> {
1232 self.get_delegate().local_computation(ln_pseudo_norm_bound)
1233 }
1234
1235 fn lift_combine<'ring>(
1236 &self,
1237 computation: &Self::LocalComputationData<'ring>,
1238 el: &[<Self::LocalRingBase<'ring> as RingBase>::Element],
1239 ) -> Self::Element
1240 where
1241 Self: 'ring,
1242 {
1243 self.rev_delegate(self.get_delegate().lift_combine(computation, el))
1244 }
1245}
1246
1247impl<'a, R> IntegerRing for IntegersWithLocalZnQuotient<'a, R>
1248where
1249 R: Sized + SelfIso + ZnRing + FromModulusCreateableZnRing + Clone,
1250{
1251 fn to_float_approx(&self, value: &Self::Element) -> f64 {
1252 self.get_delegate()
1253 .to_float_approx(self.delegate_ref(self.rev_element_cast_ref(value)))
1254 }
1255 fn from_float_approx(&self, value: f64) -> Option<Self::Element> {
1256 self.get_delegate()
1257 .from_float_approx(value)
1258 .map(|x| self.element_cast(self.rev_delegate(x)))
1259 }
1260 fn abs_is_bit_set(&self, value: &Self::Element, i: usize) -> bool {
1261 self.get_delegate()
1262 .abs_is_bit_set(self.delegate_ref(self.rev_element_cast_ref(value)), i)
1263 }
1264 fn abs_highest_set_bit(&self, value: &Self::Element) -> Option<usize> {
1265 self.get_delegate()
1266 .abs_highest_set_bit(self.delegate_ref(self.rev_element_cast_ref(value)))
1267 }
1268 fn abs_lowest_set_bit(&self, value: &Self::Element) -> Option<usize> {
1269 self.get_delegate()
1270 .abs_lowest_set_bit(self.delegate_ref(self.rev_element_cast_ref(value)))
1271 }
1272 fn get_uniformly_random_bits<G: FnMut() -> u64>(&self, log2_bound_exclusive: usize, rng: G) -> Self::Element {
1273 self.element_cast(self.rev_delegate(self.get_delegate().get_uniformly_random_bits(log2_bound_exclusive, rng)))
1274 }
1275 fn rounded_div(&self, lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
1276 self.element_cast(self.rev_delegate(self.get_delegate().rounded_div(
1277 self.delegate(self.rev_element_cast(lhs)),
1278 self.delegate_ref(self.rev_element_cast_ref(rhs)),
1279 )))
1280 }
1281 fn ceil_div(&self, lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
1282 self.element_cast(self.rev_delegate(self.get_delegate().ceil_div(
1283 self.delegate(self.rev_element_cast(lhs)),
1284 self.delegate_ref(self.rev_element_cast_ref(rhs)),
1285 )))
1286 }
1287 fn floor_div(&self, lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
1288 self.element_cast(self.rev_delegate(self.get_delegate().floor_div(
1289 self.delegate(self.rev_element_cast(lhs)),
1290 self.delegate_ref(self.rev_element_cast_ref(rhs)),
1291 )))
1292 }
1293 fn power_of_two(&self, power: usize) -> Self::Element {
1294 self.element_cast(self.rev_delegate(self.get_delegate().power_of_two(power)))
1295 }
1296 fn representable_bits(&self) -> Option<usize> { self.get_delegate().representable_bits() }
1297 fn parse(&self, string: &str, base: u32) -> Result<Self::Element, ()> {
1298 self.get_delegate()
1299 .parse(string, base)
1300 .map(|x| self.element_cast(self.rev_delegate(x)))
1301 }
1302
1303 fn euclidean_div_pow_2(&self, value: &mut Self::Element, power: usize) {
1304 self.get_delegate()
1305 .euclidean_div_pow_2(self.delegate_mut(self.rev_element_cast_mut(value)), power);
1306 self.postprocess_delegate_mut(self.rev_element_cast_mut(value));
1307 }
1308
1309 fn mul_pow_2(&self, value: &mut Self::Element, power: usize) {
1310 self.get_delegate()
1311 .mul_pow_2(self.delegate_mut(self.rev_element_cast_mut(value)), power);
1312 self.postprocess_delegate_mut(self.rev_element_cast_mut(value));
1313 }
1314}
1315
1316impl<'a, R> PolyGCDLocallyDomain for IntegersWithLocalZnQuotient<'a, R>
1317where
1318 R: Sized + SelfIso + ZnRing + FromModulusCreateableZnRing + LinSolveRing + Clone,
1319{
1320 type LocalRingBase<'ring>
1321 = R
1322 where
1323 Self: 'ring;
1324
1325 type LocalRing<'ring>
1326 = RingValue<R>
1327 where
1328 Self: 'ring;
1329
1330 type LocalFieldBase<'ring>
1331 = AsFieldBase<RingValue<R>>
1332 where
1333 Self: 'ring;
1334
1335 type LocalField<'ring>
1336 = AsField<RingValue<R>>
1337 where
1338 Self: 'ring;
1339
1340 type SuitableIdeal<'ring>
1341 = Self::Element
1342 where
1343 Self: 'ring;
1344
1345 fn heuristic_exponent<'ring, 'el, I>(
1346 &self,
1347 ideal: &Self::SuitableIdeal<'ring>,
1348 poly_deg: usize,
1349 coefficients: I,
1350 ) -> usize
1351 where
1352 I: Iterator<Item = &'el Self::Element>,
1353 Self: 'el + 'ring,
1354 {
1355 let log2_max_coeff = coefficients
1356 .map(|c| self.integers.abs_log2_ceil(c).unwrap_or(0))
1357 .max()
1358 .unwrap_or(0);
1359 return ((log2_max_coeff as f64 + poly_deg as f64) / self.integers.abs_log2_floor(ideal).unwrap_or(1) as f64
1362 * crate::reduce_lift::poly_factor_gcd::INTRING_HEURISTIC_FACTOR_SIZE_OVER_POLY_SIZE_FACTOR)
1363 .ceil() as usize
1364 + 1;
1365 }
1366
1367 fn random_suitable_ideal<'ring, F>(&'ring self, _rng: F) -> Self::SuitableIdeal<'ring>
1368 where
1369 F: FnMut() -> u64,
1370 {
1371 self.integers.clone_el(&self.prime)
1372 }
1373
1374 fn maximal_ideal_factor_count<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>) -> usize
1375 where
1376 Self: 'ring,
1377 {
1378 debug_assert!(self.integers.eq_el(ideal, &self.prime));
1379 1
1380 }
1381
1382 fn local_field_at<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, max_ideal_idx: usize) -> Self::LocalField<'ring>
1383 where
1384 Self: 'ring,
1385 {
1386 assert_eq!(0, max_ideal_idx);
1387 self.local_ring_at(ideal, 1, 0).as_field().ok().unwrap()
1388 }
1389
1390 fn local_ring_at<'ring>(
1391 &self,
1392 ideal: &Self::SuitableIdeal<'ring>,
1393 e: usize,
1394 max_ideal_idx: usize,
1395 ) -> Self::LocalRing<'ring>
1396 where
1397 Self: 'ring,
1398 {
1399 assert_eq!(0, max_ideal_idx);
1400 assert!(self.integers.eq_el(ideal, &self.prime));
1401 RingValue::from(
1402 R::from_modulus(|ZZ| {
1403 Ok(RingRef::new(ZZ).pow(
1404 int_cast(self.integers.clone_el(&self.prime), RingRef::new(ZZ), &self.integers),
1405 e,
1406 ))
1407 })
1408 .unwrap_or_else(no_error),
1409 )
1410 }
1411
1412 fn reduce_ring_el<'ring>(
1413 &self,
1414 ideal: &Self::SuitableIdeal<'ring>,
1415 to: (&Self::LocalRingBase<'ring>, usize),
1416 max_ideal_idx: usize,
1417 x: Self::Element,
1418 ) -> El<Self::LocalRing<'ring>>
1419 where
1420 Self: 'ring,
1421 {
1422 debug_assert_eq!(0, max_ideal_idx);
1423 debug_assert!(self.integers.eq_el(ideal, &self.prime));
1424 debug_assert!(self.integers.eq_el(
1425 &self.integers.pow(self.integers.clone_el(&self.prime), to.1),
1426 to.0.modulus()
1427 ));
1428 RingRef::new(to.0).coerce(&self.integers, x)
1429 }
1430
1431 fn reduce_partial<'ring>(
1432 &self,
1433 ideal: &Self::SuitableIdeal<'ring>,
1434 from: (&Self::LocalRingBase<'ring>, usize),
1435 to: (&Self::LocalRingBase<'ring>, usize),
1436 max_ideal_idx: usize,
1437 x: El<Self::LocalRing<'ring>>,
1438 ) -> El<Self::LocalRing<'ring>>
1439 where
1440 Self: 'ring,
1441 {
1442 debug_assert_eq!(0, max_ideal_idx);
1443 debug_assert!(self.integers.eq_el(ideal, &self.prime));
1444 debug_assert!(self.integers.eq_el(
1445 &self.integers.pow(self.integers.clone_el(&self.prime), to.1),
1446 to.0.modulus()
1447 ));
1448 debug_assert!(self.integers.eq_el(
1449 &self.integers.pow(self.integers.clone_el(&self.prime), from.1),
1450 from.0.modulus()
1451 ));
1452 RingRef::new(to.0).coerce(&self.integers, from.0.smallest_positive_lift(x))
1453 }
1454
1455 fn lift_partial<'ring>(
1456 &self,
1457 ideal: &Self::SuitableIdeal<'ring>,
1458 from: (&Self::LocalRingBase<'ring>, usize),
1459 to: (&Self::LocalRingBase<'ring>, usize),
1460 max_ideal_idx: usize,
1461 x: El<Self::LocalRing<'ring>>,
1462 ) -> El<Self::LocalRing<'ring>>
1463 where
1464 Self: 'ring,
1465 {
1466 debug_assert_eq!(0, max_ideal_idx);
1467 debug_assert!(self.integers.eq_el(ideal, &self.prime));
1468 debug_assert!(self.integers.eq_el(
1469 &self.integers.pow(self.integers.clone_el(&self.prime), to.1),
1470 to.0.modulus()
1471 ));
1472 debug_assert!(self.integers.eq_el(
1473 &self.integers.pow(self.integers.clone_el(&self.prime), from.1),
1474 from.0.modulus()
1475 ));
1476 RingRef::new(to.0).coerce(&self.integers, from.0.smallest_positive_lift(x))
1477 }
1478
1479 fn base_ring_to_field<'ring>(
1480 &self,
1481 _ideal: &Self::SuitableIdeal<'ring>,
1482 from: &Self::LocalRingBase<'ring>,
1483 to: &Self::LocalFieldBase<'ring>,
1484 max_ideal_idx: usize,
1485 x: El<Self::LocalRing<'ring>>,
1486 ) -> El<Self::LocalField<'ring>>
1487 where
1488 Self: 'ring,
1489 {
1490 debug_assert_eq!(0, max_ideal_idx);
1491 assert!(from == to.get_delegate());
1492 to.element_cast(to.rev_delegate(x))
1493 }
1494
1495 fn field_to_base_ring<'ring>(
1496 &self,
1497 _ideal: &Self::SuitableIdeal<'ring>,
1498 from: &Self::LocalFieldBase<'ring>,
1499 to: &Self::LocalRingBase<'ring>,
1500 max_ideal_idx: usize,
1501 x: El<Self::LocalField<'ring>>,
1502 ) -> El<Self::LocalRing<'ring>>
1503 where
1504 Self: 'ring,
1505 {
1506 debug_assert_eq!(0, max_ideal_idx);
1507 assert!(to == from.get_delegate());
1508 from.delegate(from.rev_element_cast(x))
1509 }
1510
1511 fn reconstruct_ring_el<'local, 'element, 'ring, V1, V2>(
1512 &self,
1513 ideal: &Self::SuitableIdeal<'ring>,
1514 from: V1,
1515 e: usize,
1516 x: V2,
1517 ) -> Self::Element
1518 where
1519 Self: 'ring,
1520 V1: VectorFn<&'local Self::LocalRing<'ring>>,
1521 V2: VectorFn<&'element El<Self::LocalRing<'ring>>>,
1522 Self::LocalRing<'ring>: 'local,
1523 El<Self::LocalRing<'ring>>: 'element,
1524 'ring: 'local + 'element,
1525 {
1526 assert_eq!(1, x.len());
1527 assert_eq!(1, from.len());
1528 debug_assert!(self.integers.eq_el(ideal, &self.prime));
1529 debug_assert!(self.integers.eq_el(
1530 &self.integers.pow(self.integers.clone_el(&self.prime), e),
1531 from.at(0).modulus()
1532 ));
1533 from.at(0).smallest_lift(from.at(0).clone_el(x.at(0)))
1534 }
1535
1536 fn dbg_ideal<'ring>(&self, ideal: &Self::SuitableIdeal<'ring>, out: &mut std::fmt::Formatter) -> std::fmt::Result
1537 where
1538 Self: 'ring,
1539 {
1540 self.dbg(ideal, out)
1541 }
1542}
1543
1544impl<'a, R> IntegerPolyGCDRing for IntegersWithLocalZnQuotient<'a, R>
1545where
1546 R: Sized + SelfIso + ZnRing + FromModulusCreateableZnRing + LinSolveRing + Clone,
1547{
1548 type LocalRingAsZn<'ring>
1549 = Self::LocalRing<'ring>
1550 where
1551 Self: 'ring;
1552 type LocalRingAsZnBase<'ring>
1553 = Self::LocalRingBase<'ring>
1554 where
1555 Self: 'ring;
1556
1557 fn local_ring_as_zn<'b, 'ring>(&self, local_field: &'b Self::LocalRing<'ring>) -> &'b Self::LocalRingAsZn<'ring>
1558 where
1559 Self: 'ring,
1560 {
1561 local_field
1562 }
1563
1564 fn local_ring_into_zn<'ring>(&self, local_field: Self::LocalRing<'ring>) -> Self::LocalRingAsZn<'ring>
1565 where
1566 Self: 'ring,
1567 {
1568 local_field
1569 }
1570}