1use std::cell::OnceCell;
2use std::fmt::Debug;
3use std::marker::PhantomData;
4
5use feanor_serde::dependent_tuple::DeserializeSeedDependentTuple;
6use feanor_serde::newtype_struct::*;
7use serde::de::{DeserializeSeed, Error};
8use serde::{Deserialize, Deserializer, Serialize, Serializer};
9
10use crate::delegate::DelegateRing;
11use crate::divisibility::DivisibilityRing;
12use crate::homomorphism::*;
13use crate::integer::*;
14use crate::ordered::OrderedRingStore;
15use crate::pid::*;
16use crate::reduce_lift::poly_eval::InterpolationBaseRing;
17use crate::ring::*;
18use crate::rings::extension::FreeAlgebraStore;
19use crate::rings::extension::galois_field::*;
20use crate::rings::zn::*;
21use crate::seq::*;
22use crate::serialization::*;
23use crate::specialization::*;
24use crate::{
25 impl_field_wrap_unwrap_homs, impl_field_wrap_unwrap_isos, impl_localpir_wrap_unwrap_homs,
26 impl_localpir_wrap_unwrap_isos,
27};
28
29pub struct ZnBase<I: RingStore>
78where
79 I::Type: IntegerRing,
80{
81 integer_ring: I,
82 modulus: El<I>,
83 twice_modulus: El<I>,
84 inverse_modulus: El<I>,
85 inverse_modulus_bitshift: usize,
86}
87
88pub type Zn<I> = RingValue<ZnBase<I>>;
91
92impl<I: RingStore> Zn<I>
93where
94 I::Type: IntegerRing,
95{
96 pub fn new(integer_ring: I, modulus: El<I>) -> Self { RingValue::from(ZnBase::new(integer_ring, modulus)) }
97}
98
99impl<I: RingStore> ZnBase<I>
100where
101 I::Type: IntegerRing,
102{
103 pub fn new(integer_ring: I, modulus: El<I>) -> Self {
104 assert!(integer_ring.is_geq(&modulus, &integer_ring.int_hom().map(2)));
105
106 let k = integer_ring
110 .abs_log2_ceil(&integer_ring.mul_ref(&modulus, &modulus))
111 .unwrap()
112 + 2;
113 let mod_square_bound = integer_ring.power_of_two(k);
114 let inverse_modulus = integer_ring.euclidean_div(mod_square_bound, &modulus);
115
116 _ = integer_ring.mul_ref_snd(integer_ring.pow(integer_ring.clone_el(&modulus), 2), &inverse_modulus);
118
119 return ZnBase {
120 twice_modulus: integer_ring.add_ref(&modulus, &modulus),
121 integer_ring,
122 modulus,
123 inverse_modulus,
124 inverse_modulus_bitshift: k,
125 };
126 }
127
128 fn bounded_reduce(&self, n: &mut El<I>) {
129 debug_assert!(
130 self.integer_ring
131 .is_leq(n, &self.integer_ring.mul_ref(&self.twice_modulus, &self.twice_modulus))
132 );
133 debug_assert!(!self.integer_ring.is_neg(n));
134
135 let mut subtract = self.integer_ring.mul_ref(n, &self.inverse_modulus);
136 self.integer_ring
137 .euclidean_div_pow_2(&mut subtract, self.inverse_modulus_bitshift);
138 self.integer_ring.mul_assign_ref(&mut subtract, &self.modulus);
139 self.integer_ring.sub_assign(n, subtract);
140
141 debug_assert!(self.integer_ring.is_lt(n, &self.twice_modulus));
142 }
143}
144
145pub struct ZnEl<I: RingStore>(
146 El<I>,
148)
149where
150 I::Type: IntegerRing;
151
152impl<I> Debug for ZnBase<I>
153where
154 I: RingStore,
155 I::Type: IntegerRing,
156{
157 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
158 write!(f, "Z/{}Z", self.integer_ring().format(self.modulus()))
159 }
160}
161
162impl<I: RingStore> Debug for ZnEl<I>
163where
164 El<I>: Clone + Debug,
165 I::Type: IntegerRing,
166{
167 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("ZnEl").field(&self.0).finish() }
168}
169
170impl<I: RingStore> Clone for ZnEl<I>
171where
172 El<I>: Clone,
173 I::Type: IntegerRing,
174{
175 fn clone(&self) -> Self { ZnEl(self.0.clone()) }
176}
177
178impl<I: RingStore> Copy for ZnEl<I>
179where
180 El<I>: Copy,
181 I::Type: IntegerRing,
182{
183}
184
185impl<I: RingStore> RingBase for ZnBase<I>
186where
187 I::Type: IntegerRing,
188{
189 type Element = ZnEl<I>;
190
191 fn clone_el(&self, val: &Self::Element) -> Self::Element { ZnEl(self.integer_ring().clone_el(&val.0)) }
192
193 fn add_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
194 debug_assert!(self.integer_ring.is_leq(&lhs.0, &self.twice_modulus));
195 debug_assert!(self.integer_ring.is_leq(&rhs.0, &self.twice_modulus));
196
197 self.integer_ring.add_assign_ref(&mut lhs.0, &rhs.0);
198 if self.integer_ring.is_geq(&lhs.0, &self.twice_modulus) {
199 self.integer_ring.sub_assign_ref(&mut lhs.0, &self.twice_modulus);
200 }
201
202 debug_assert!(self.integer_ring.is_leq(&lhs.0, &self.twice_modulus));
203 }
204
205 fn add_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
206 debug_assert!(self.integer_ring.is_leq(&lhs.0, &self.twice_modulus));
207 debug_assert!(self.integer_ring.is_leq(&rhs.0, &self.twice_modulus));
208
209 self.integer_ring.add_assign(&mut lhs.0, rhs.0);
210 if self.integer_ring.is_geq(&lhs.0, &self.twice_modulus) {
211 self.integer_ring.sub_assign_ref(&mut lhs.0, &self.twice_modulus);
212 }
213
214 debug_assert!(self.integer_ring.is_leq(&lhs.0, &self.twice_modulus));
215 }
216
217 fn sub_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
218 debug_assert!(self.integer_ring.is_leq(&lhs.0, &self.twice_modulus));
219 debug_assert!(self.integer_ring.is_leq(&rhs.0, &self.twice_modulus));
220
221 self.integer_ring.sub_assign_ref(&mut lhs.0, &rhs.0);
222 if self.integer_ring.is_neg(&lhs.0) {
223 self.integer_ring.add_assign_ref(&mut lhs.0, &self.twice_modulus);
224 }
225
226 debug_assert!(self.integer_ring.is_leq(&lhs.0, &self.twice_modulus));
227 debug_assert!(!self.integer_ring.is_neg(&lhs.0));
228 }
229
230 fn negate_inplace(&self, lhs: &mut Self::Element) {
231 debug_assert!(self.integer_ring.is_leq(&lhs.0, &self.twice_modulus));
232
233 self.integer_ring.negate_inplace(&mut lhs.0);
234 self.integer_ring.add_assign_ref(&mut lhs.0, &self.twice_modulus);
235
236 debug_assert!(self.integer_ring.is_leq(&lhs.0, &self.twice_modulus));
237 debug_assert!(!self.integer_ring.is_neg(&lhs.0));
238 }
239
240 fn mul_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
241 debug_assert!(self.integer_ring.is_leq(&lhs.0, &self.twice_modulus));
242 debug_assert!(self.integer_ring.is_leq(&rhs.0, &self.twice_modulus));
243
244 self.integer_ring.mul_assign(&mut lhs.0, rhs.0);
245 self.bounded_reduce(&mut lhs.0);
246 }
247
248 fn mul_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
249 debug_assert!(self.integer_ring.is_leq(&lhs.0, &self.twice_modulus));
250 debug_assert!(self.integer_ring.is_leq(&rhs.0, &self.twice_modulus));
251
252 self.integer_ring.mul_assign_ref(&mut lhs.0, &rhs.0);
253 self.bounded_reduce(&mut lhs.0);
254 }
255
256 fn from_int(&self, value: i32) -> Self::Element { RingRef::new(self).coerce(&StaticRing::<i32>::RING, value) }
257
258 fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool {
259 debug_assert!(self.integer_ring.is_leq(&lhs.0, &self.twice_modulus));
260 debug_assert!(self.integer_ring.is_leq(&rhs.0, &self.twice_modulus));
261
262 if self.integer_ring.eq_el(&lhs.0, &rhs.0) {
263 return true;
264 }
265 let difference = self.integer_ring.abs(self.integer_ring.sub_ref(&lhs.0, &rhs.0));
266 return self.integer_ring.eq_el(&difference, &self.modulus)
267 || self.integer_ring.eq_el(&difference, &self.twice_modulus);
268 }
269
270 fn is_zero(&self, value: &Self::Element) -> bool {
271 debug_assert!(self.integer_ring.is_leq(&value.0, &self.twice_modulus));
272
273 self.integer_ring.is_zero(&value.0)
274 || self.integer_ring.eq_el(&value.0, &self.modulus)
275 || self.integer_ring.eq_el(&value.0, &self.twice_modulus)
276 }
277
278 fn is_one(&self, value: &Self::Element) -> bool {
279 debug_assert!(self.integer_ring.is_leq(&value.0, &self.twice_modulus));
280
281 self.integer_ring.is_one(&value.0)
282 || self.integer_ring.eq_el(
283 &value.0,
284 &self.integer_ring.add_ref_fst(&self.modulus, self.integer_ring.one()),
285 )
286 }
287
288 fn is_commutative(&self) -> bool { true }
289 fn is_noetherian(&self) -> bool { true }
290
291 fn dbg_within<'a>(
292 &self,
293 value: &Self::Element,
294 out: &mut std::fmt::Formatter<'a>,
295 _: EnvBindingStrength,
296 ) -> std::fmt::Result {
297 if self.integer_ring.is_geq(&value.0, &self.modulus) {
298 let reduced_value = self.integer_ring.sub_ref(&value.0, &self.modulus);
299 if self.integer_ring.eq_el(&reduced_value, &self.modulus) {
300 self.integer_ring.get_ring().dbg(&self.integer_ring.zero(), out)
301 } else {
302 self.integer_ring.get_ring().dbg(&reduced_value, out)
303 }
304 } else {
305 self.integer_ring.get_ring().dbg(&value.0, out)
306 }
307 }
308
309 fn characteristic<J: RingStore + Copy>(&self, ZZ: J) -> Option<El<J>>
310 where
311 J::Type: IntegerRing,
312 {
313 self.size(ZZ)
314 }
315
316 fn is_approximate(&self) -> bool { false }
317}
318
319impl<I: RingStore> Clone for ZnBase<I>
320where
321 I: Clone,
322 I::Type: IntegerRing,
323{
324 fn clone(&self) -> Self {
325 ZnBase {
326 integer_ring: self.integer_ring.clone(),
327 modulus: self.integer_ring.clone_el(&self.modulus),
328 inverse_modulus: self.integer_ring.clone_el(&self.inverse_modulus),
329 inverse_modulus_bitshift: self.inverse_modulus_bitshift,
330 twice_modulus: self.integer_ring.clone_el(&self.twice_modulus),
331 }
332 }
333}
334
335impl<I: RingStore> InterpolationBaseRing for AsFieldBase<Zn<I>>
336where
337 I::Type: IntegerRing,
338{
339 type ExtendedRingBase<'a>
340 = GaloisFieldBaseOver<RingRef<'a, Self>>
341 where
342 Self: 'a;
343
344 type ExtendedRing<'a>
345 = GaloisFieldOver<RingRef<'a, Self>>
346 where
347 Self: 'a;
348
349 fn in_base<'a, S>(&self, ext_ring: S, el: El<S>) -> Option<Self::Element>
350 where
351 Self: 'a,
352 S: RingStore<Type = Self::ExtendedRingBase<'a>>,
353 {
354 let wrt_basis = ext_ring.wrt_canonical_basis(&el);
355 if wrt_basis.iter().skip(1).all(|x| self.is_zero(&x)) {
356 return Some(wrt_basis.at(0));
357 } else {
358 return None;
359 }
360 }
361
362 fn in_extension<'a, S>(&self, ext_ring: S, el: Self::Element) -> El<S>
363 where
364 Self: 'a,
365 S: RingStore<Type = Self::ExtendedRingBase<'a>>,
366 {
367 ext_ring.inclusion().map(el)
368 }
369
370 fn interpolation_points<'a>(&'a self, count: usize) -> (Self::ExtendedRing<'a>, Vec<El<Self::ExtendedRing<'a>>>) {
371 let ring = super::generic_impls::interpolation_ring(RingRef::new(self), count);
372 let points = ring.elements().take(count).collect();
373 return (ring, points);
374 }
375}
376impl<I: RingStore> Copy for ZnBase<I>
377where
378 I: Copy,
379 El<I>: Copy,
380 I::Type: IntegerRing,
381{
382}
383
384impl<I: RingStore> HashableElRing for ZnBase<I>
385where
386 I::Type: IntegerRing,
387{
388 fn hash<H: std::hash::Hasher>(&self, el: &Self::Element, h: &mut H) {
389 self.integer_ring()
390 .hash(&self.smallest_positive_lift(self.clone_el(el)), h)
391 }
392}
393
394impl<I: RingStore + Default> FromModulusCreateableZnRing for ZnBase<I>
395where
396 I::Type: IntegerRing,
397{
398 fn from_modulus<F, E>(create_modulus: F) -> Result<Self, E>
399 where
400 F: FnOnce(&Self::IntegerRingBase) -> Result<El<Self::IntegerRing>, E>,
401 {
402 let ZZ = I::default();
403 let modulus = create_modulus(ZZ.get_ring())?;
404 Ok(Self::new(ZZ, modulus))
405 }
406}
407
408impl<I: RingStore> DivisibilityRing for ZnBase<I>
409where
410 I::Type: IntegerRing,
411{
412 fn checked_left_div(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
413 super::generic_impls::checked_left_div(RingRef::new(self), lhs, rhs)
414 }
415}
416
417impl<I: RingStore, J: RingStore> CanHomFrom<ZnBase<J>> for ZnBase<I>
418where
419 I::Type: IntegerRing + CanHomFrom<J::Type>,
420 J::Type: IntegerRing,
421{
422 type Homomorphism = <I::Type as CanHomFrom<J::Type>>::Homomorphism;
423
424 fn has_canonical_hom(&self, from: &ZnBase<J>) -> Option<Self::Homomorphism> {
425 let base_hom = <I::Type as CanHomFrom<J::Type>>::has_canonical_hom(
426 self.integer_ring.get_ring(),
427 from.integer_ring.get_ring(),
428 )?;
429 if self.integer_ring.eq_el(
430 &self.modulus,
431 &<I::Type as CanHomFrom<J::Type>>::map_in(
432 self.integer_ring.get_ring(),
433 from.integer_ring.get_ring(),
434 from.integer_ring().clone_el(&from.modulus),
435 &base_hom,
436 ),
437 ) {
438 Some(base_hom)
439 } else {
440 None
441 }
442 }
443
444 fn map_in(
445 &self,
446 from: &ZnBase<J>,
447 el: <ZnBase<J> as RingBase>::Element,
448 hom: &Self::Homomorphism,
449 ) -> Self::Element {
450 ZnEl(<I::Type as CanHomFrom<J::Type>>::map_in(
451 self.integer_ring.get_ring(),
452 from.integer_ring.get_ring(),
453 el.0,
454 hom,
455 ))
456 }
457}
458
459impl<I: RingStore> CanHomFrom<zn_64::ZnBase> for ZnBase<I>
460where
461 I::Type: IntegerRing,
462{
463 type Homomorphism = <zn_64::ZnBase as CanIsoFromTo<ZnBase<I>>>::Isomorphism;
464
465 fn has_canonical_hom(&self, from: &zn_64::ZnBase) -> Option<Self::Homomorphism> { from.has_canonical_iso(self) }
466
467 fn map_in(
468 &self,
469 from: &zn_64::ZnBase,
470 el: <zn_64::ZnBase as RingBase>::Element,
471 hom: &Self::Homomorphism,
472 ) -> Self::Element {
473 from.map_out(self, el, hom)
474 }
475}
476
477impl<I: RingStore> CanIsoFromTo<zn_64::ZnBase> for ZnBase<I>
478where
479 I::Type: IntegerRing,
480{
481 type Isomorphism = <zn_64::ZnBase as CanHomFrom<ZnBase<I>>>::Homomorphism;
482
483 fn has_canonical_iso(&self, from: &zn_64::ZnBase) -> Option<Self::Isomorphism> { from.has_canonical_hom(self) }
484
485 fn map_out(
486 &self,
487 from: &zn_64::ZnBase,
488 el: Self::Element,
489 iso: &Self::Isomorphism,
490 ) -> <zn_64::ZnBase as RingBase>::Element {
491 from.map_in(self, el, iso)
492 }
493}
494
495impl<I: RingStore> PartialEq for ZnBase<I>
496where
497 I::Type: IntegerRing,
498{
499 fn eq(&self, other: &Self) -> bool {
500 self.integer_ring.get_ring() == other.integer_ring.get_ring()
501 && self.integer_ring.eq_el(&self.modulus, &other.modulus)
502 }
503}
504
505impl<I: RingStore, J: RingStore> CanIsoFromTo<ZnBase<J>> for ZnBase<I>
506where
507 I::Type: IntegerRing + CanIsoFromTo<J::Type>,
508 J::Type: IntegerRing,
509{
510 type Isomorphism = <I::Type as CanIsoFromTo<J::Type>>::Isomorphism;
511
512 fn has_canonical_iso(&self, from: &ZnBase<J>) -> Option<Self::Isomorphism> {
513 let base_iso = <I::Type as CanIsoFromTo<J::Type>>::has_canonical_iso(
514 self.integer_ring.get_ring(),
515 from.integer_ring.get_ring(),
516 )?;
517 if from.integer_ring().eq_el(
518 from.modulus(),
519 &<I::Type as CanIsoFromTo<J::Type>>::map_out(
520 self.integer_ring.get_ring(),
521 from.integer_ring.get_ring(),
522 self.integer_ring().clone_el(self.modulus()),
523 &base_iso,
524 ),
525 ) {
526 Some(base_iso)
527 } else {
528 None
529 }
530 }
531
532 fn map_out(
533 &self,
534 from: &ZnBase<J>,
535 el: Self::Element,
536 iso: &Self::Isomorphism,
537 ) -> <ZnBase<J> as RingBase>::Element {
538 ZnEl(<I::Type as CanIsoFromTo<J::Type>>::map_out(
539 self.integer_ring.get_ring(),
540 from.integer_ring.get_ring(),
541 el.0,
542 iso,
543 ))
544 }
545}
546
547impl<I: RingStore, J: IntegerRing + ?Sized> CanHomFrom<J> for ZnBase<I>
548where
549 I::Type: IntegerRing,
550 J: CanIsoFromTo<I::Type>,
551{
552 type Homomorphism = super::generic_impls::BigIntToZnHom<J, I::Type, ZnBase<I>>;
553
554 fn has_canonical_hom(&self, from: &J) -> Option<Self::Homomorphism> {
555 super::generic_impls::has_canonical_hom_from_bigint(
556 from,
557 self,
558 self.integer_ring.get_ring(),
559 Some(&self.integer_ring.mul_ref(&self.twice_modulus, &self.twice_modulus)),
560 )
561 }
562
563 fn map_in(&self, from: &J, el: J::Element, hom: &Self::Homomorphism) -> Self::Element {
564 super::generic_impls::map_in_from_bigint(
565 from,
566 self,
567 self.integer_ring.get_ring(),
568 el,
569 hom,
570 |n| {
571 debug_assert!(self.integer_ring.is_lt(&n, &self.modulus));
572 ZnEl(n)
573 },
574 |mut n| {
575 debug_assert!(
576 self.integer_ring
577 .is_lt(&n, &self.integer_ring.mul_ref(&self.twice_modulus, &self.twice_modulus))
578 );
579 self.bounded_reduce(&mut n);
580 ZnEl(n)
581 },
582 )
583 }
584}
585
586pub struct ZnBaseElementsIter<'a, I>
587where
588 I: RingStore,
589 I::Type: IntegerRing,
590{
591 ring: &'a ZnBase<I>,
592 current: El<I>,
593}
594
595impl<'a, I> Clone for ZnBaseElementsIter<'a, I>
596where
597 I: RingStore,
598 I::Type: IntegerRing,
599{
600 fn clone(&self) -> Self {
601 Self {
602 ring: self.ring,
603 current: self.ring.integer_ring().clone_el(&self.current),
604 }
605 }
606}
607
608impl<'a, I> Iterator for ZnBaseElementsIter<'a, I>
609where
610 I: RingStore,
611 I::Type: IntegerRing,
612{
613 type Item = ZnEl<I>;
614
615 fn next(&mut self) -> Option<Self::Item> {
616 if self.ring.integer_ring().is_lt(&self.current, self.ring.modulus()) {
617 let result = self.ring.integer_ring().clone_el(&self.current);
618 self.ring
619 .integer_ring()
620 .add_assign(&mut self.current, self.ring.integer_ring().one());
621 return Some(ZnEl(result));
622 } else {
623 return None;
624 }
625 }
626}
627
628impl<I> Serialize for ZnBase<I>
629where
630 I: RingStore + Serialize,
631 I::Type: IntegerRing + SerializableElementRing,
632{
633 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
634 where
635 S: Serializer,
636 {
637 SerializableNewtypeStruct::new(
638 "Zn",
639 (
640 self.integer_ring(),
641 SerializeWithRing::new(self.modulus(), self.integer_ring()),
642 ),
643 )
644 .serialize(serializer)
645 }
646}
647
648impl<'de, I> Deserialize<'de> for ZnBase<I>
649where
650 I: RingStore + Deserialize<'de>,
651 I::Type: IntegerRing + SerializableElementRing,
652{
653 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
654 where
655 D: Deserializer<'de>,
656 {
657 let ring_cell = OnceCell::new();
658 let modulus = <_ as DeserializeSeed<'de>>::deserialize(
659 DeserializeSeedNewtypeStruct::new(
660 "Zn",
661 DeserializeSeedDependentTuple::new(PhantomData::<I>, |ring| {
662 ring_cell.set(ring).ok().unwrap();
663 DeserializeWithRing::new(ring_cell.get().unwrap())
664 }),
665 ),
666 deserializer,
667 )?;
668 let ring = ring_cell.into_inner().unwrap();
669 return Ok(Zn::new(ring, modulus).into());
670 }
671}
672
673impl<I: RingStore> SerializableElementRing for ZnBase<I>
674where
675 I::Type: IntegerRing + SerializableElementRing,
676{
677 fn deserialize<'de, D>(&self, deserializer: D) -> Result<Self::Element, D::Error>
678 where
679 D: Deserializer<'de>,
680 {
681 self.integer_ring()
682 .get_ring()
683 .deserialize(deserializer)
684 .and_then(|x| {
685 if self.integer_ring().is_neg(&x) || self.integer_ring().is_geq(&x, self.modulus()) {
686 Err(Error::custom("ring element value out of bounds for ring Z/nZ"))
687 } else {
688 Ok(x)
689 }
690 })
691 .map(|x| self.from_int_promise_reduced(x))
692 }
693
694 fn serialize<S>(&self, el: &Self::Element, serializer: S) -> Result<S::Ok, S::Error>
695 where
696 S: Serializer,
697 {
698 self.integer_ring()
699 .get_ring()
700 .serialize(&self.smallest_positive_lift(self.clone_el(el)), serializer)
701 }
702}
703
704impl<I: RingStore> FiniteRing for ZnBase<I>
705where
706 I::Type: IntegerRing,
707{
708 type ElementsIter<'a>
709 = ZnBaseElementsIter<'a, I>
710 where
711 Self: 'a;
712
713 fn elements<'a>(&'a self) -> ZnBaseElementsIter<'a, I> {
714 ZnBaseElementsIter {
715 ring: self,
716 current: self.integer_ring().zero(),
717 }
718 }
719
720 fn random_element<G: FnMut() -> u64>(&self, rng: G) -> <Self as RingBase>::Element {
721 super::generic_impls::random_element(self, rng)
722 }
723
724 fn size<J: RingStore + Copy>(&self, ZZ: J) -> Option<El<J>>
725 where
726 J::Type: IntegerRing,
727 {
728 if ZZ.get_ring().representable_bits().is_none()
729 || self.integer_ring().abs_log2_ceil(self.modulus()) < ZZ.get_ring().representable_bits()
730 {
731 Some(int_cast(
732 self.integer_ring().clone_el(self.modulus()),
733 ZZ,
734 self.integer_ring(),
735 ))
736 } else {
737 None
738 }
739 }
740}
741
742impl<I: RingStore> PrincipalIdealRing for ZnBase<I>
743where
744 I::Type: IntegerRing,
745{
746 fn checked_div_min(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
747 super::generic_impls::checked_div_min(RingRef::new(self), lhs, rhs)
748 }
749
750 fn extended_ideal_gen(
751 &self,
752 lhs: &Self::Element,
753 rhs: &Self::Element,
754 ) -> (Self::Element, Self::Element, Self::Element) {
755 let (s, t, d) = self.integer_ring().extended_ideal_gen(&lhs.0, &rhs.0);
756 let quo = RingRef::new(self).into_can_hom(self.integer_ring()).ok().unwrap();
757 (quo.map(s), quo.map(t), quo.map(d))
758 }
759}
760
761impl<I> FiniteRingSpecializable for ZnBase<I>
762where
763 I: RingStore,
764 I::Type: IntegerRing,
765{
766 fn specialize<O: FiniteRingOperation<Self>>(op: O) -> O::Output { op.execute() }
767}
768
769impl<I: RingStore> ZnRing for ZnBase<I>
770where
771 I::Type: IntegerRing,
772{
773 type IntegerRingBase = I::Type;
774 type IntegerRing = I;
775
776 fn integer_ring(&self) -> &Self::IntegerRing { &self.integer_ring }
777
778 fn modulus(&self) -> &El<Self::IntegerRing> { &self.modulus }
779
780 fn smallest_positive_lift(&self, mut el: Self::Element) -> El<Self::IntegerRing> {
781 if self.integer_ring.eq_el(&el.0, &self.twice_modulus) {
782 return self.integer_ring.zero();
783 }
784 if self.integer_ring.is_geq(&el.0, &self.modulus) {
785 self.integer_ring.sub_assign_ref(&mut el.0, &self.modulus);
786 }
787 debug_assert!(self.integer_ring.is_lt(&el.0, &self.modulus));
788 return el.0;
789 }
790
791 fn from_int_promise_reduced(&self, x: El<Self::IntegerRing>) -> Self::Element {
792 debug_assert!(!self.integer_ring().is_neg(&x));
793 debug_assert!(self.integer_ring().is_lt(&x, self.modulus()));
794 ZnEl(x)
795 }
796}
797
798impl_field_wrap_unwrap_homs! { <{I, J}> ZnBase<I>, ZnBase<J> where I: RingStore, I::Type: IntegerRing, J: RingStore, J::Type: IntegerRing }
799impl_field_wrap_unwrap_isos! { <{I, J}> ZnBase<I>, ZnBase<J> where I: RingStore, I::Type: IntegerRing, J: RingStore, J::Type: IntegerRing }
800impl_localpir_wrap_unwrap_homs! { <{I, J}> ZnBase<I>, ZnBase<J> where I: RingStore, I::Type: IntegerRing, J: RingStore, J::Type: IntegerRing }
801impl_localpir_wrap_unwrap_isos! { <{I, J}> ZnBase<I>, ZnBase<J> where I: RingStore, I::Type: IntegerRing, J: RingStore, J::Type: IntegerRing }
802
803#[cfg(test)]
804use crate::integer::BigIntRing;
805#[cfg(test)]
806use crate::rings::rust_bigint::*;
807
808#[test]
809fn test_mul() {
810 const ZZ: BigIntRing = BigIntRing::RING;
811 let Z257 = Zn::new(ZZ, ZZ.int_hom().map(257));
812 let x = Z257.coerce(&ZZ, ZZ.int_hom().map(256));
813 assert_el_eq!(Z257, Z257.one(), Z257.mul_ref(&x, &x));
814}
815
816#[test]
817fn test_project() {
818 const ZZ: StaticRing<i64> = StaticRing::RING;
819 let Z17 = Zn::new(ZZ, 17);
820 for k in 0..289 {
821 assert_el_eq!(Z17, Z17.int_hom().map((289 - k) % 17), Z17.coerce(&ZZ, -k as i64));
822 }
823}
824
825#[test]
826fn test_ring_axioms_znbase() {
827 let ring = Zn::new(StaticRing::<i64>::RING, 63);
828 crate::ring::generic_tests::test_ring_axioms(&ring, ring.elements())
829}
830
831#[test]
832fn test_hash_axioms() {
833 let ring = Zn::new(StaticRing::<i64>::RING, 63);
834 crate::ring::generic_tests::test_hash_axioms(&ring, ring.elements())
835}
836
837#[test]
838fn test_canonical_iso_axioms_zn_big() {
839 let from = Zn::new(StaticRing::<i128>::RING, 7 * 11);
840 let to = Zn::new(BigIntRing::RING, BigIntRing::RING.int_hom().map(7 * 11));
841 crate::ring::generic_tests::test_hom_axioms(&from, &to, from.elements());
842 crate::ring::generic_tests::test_iso_axioms(&from, &to, from.elements());
843 assert!(from.can_hom(&Zn::new(StaticRing::<i64>::RING, 19)).is_none());
844}
845
846#[test]
847fn test_canonical_hom_axioms_static_int() {
848 let from = StaticRing::<i32>::RING;
849 let to = Zn::new(StaticRing::<i128>::RING, 7 * 11);
850 crate::ring::generic_tests::test_hom_axioms(&from, to, 0..=(2 * 7 * 11));
851}
852
853#[test]
854fn test_zn_ring_axioms_znbase() {
855 super::generic_tests::test_zn_axioms(Zn::new(StaticRing::<i64>::RING, 17));
856 super::generic_tests::test_zn_axioms(Zn::new(StaticRing::<i64>::RING, 63));
857}
858
859#[test]
860fn test_zn_map_in_large_int_znbase() {
861 super::generic_tests::test_map_in_large_int(Zn::new(StaticRing::<i64>::RING, 63));
862}
863
864#[test]
865fn test_zn_map_in_small_int() {
866 let ring = Zn::new(StaticRing::<i64>::RING, 257);
867 assert_el_eq!(ring, ring.one(), ring.coerce(&StaticRing::<i8>::RING, 1));
868}
869
870#[test]
871fn test_divisibility_axioms() {
872 let R = Zn::new(StaticRing::<i64>::RING, 17);
873 crate::divisibility::generic_tests::test_divisibility_axioms(&R, R.elements());
874}
875
876#[test]
877fn test_principal_ideal_ring_axioms() {
878 let R = Zn::new(StaticRing::<i64>::RING, 17);
879 crate::pid::generic_tests::test_principal_ideal_ring_axioms(&R, R.elements());
880 let R = Zn::new(StaticRing::<i64>::RING, 63);
881 crate::pid::generic_tests::test_principal_ideal_ring_axioms(&R, R.elements());
882}
883
884#[test]
885fn test_canonical_iso_axioms_as_field() {
886 let R = Zn::new(StaticRing::<i128>::RING, 17);
887 let R2 = R.clone().as_field().ok().unwrap();
888 crate::ring::generic_tests::test_hom_axioms(&R, &R2, R.elements());
889 crate::ring::generic_tests::test_iso_axioms(&R, &R2, R.elements());
890 crate::ring::generic_tests::test_hom_axioms(&R2, &R, R2.elements());
891 crate::ring::generic_tests::test_iso_axioms(&R2, &R, R2.elements());
892}
893
894#[test]
895fn test_canonical_iso_axioms_zn_64() {
896 let R = Zn::new(StaticRing::<i128>::RING, 17);
897 let R2 = zn_64::Zn::new(17);
898 crate::ring::generic_tests::test_hom_axioms(&R, &R2, R.elements());
899 crate::ring::generic_tests::test_iso_axioms(&R, &R2, R.elements());
900 crate::ring::generic_tests::test_hom_axioms(&R2, &R, R2.elements());
901 crate::ring::generic_tests::test_iso_axioms(&R2, &R, R2.elements());
902}
903
904#[test]
905fn test_finite_field_axioms() {
906 crate::rings::finite::generic_tests::test_finite_ring_axioms(&Zn::new(&StaticRing::<i64>::RING, 128));
907 crate::rings::finite::generic_tests::test_finite_ring_axioms(&Zn::new(&StaticRing::<i64>::RING, 15));
908 crate::rings::finite::generic_tests::test_finite_ring_axioms(&Zn::new(&StaticRing::<i128>::RING, 1 << 32));
909}
910
911#[test]
912fn test_serialize() {
913 let ring = Zn::new(&StaticRing::<i64>::RING, 128);
914 crate::serialization::generic_tests::test_serialization(ring, ring.elements())
915}
916#[test]
917fn test_unreduced() {
918 let ZZbig = RustBigintRing::RING;
919 let ring = Zn::new(
920 ZZbig,
921 ZZbig.prod(
922 [
923 72057594035352641,
924 72057594035418113,
925 72057594036334721,
926 72057594036945793,
927 ]
928 .iter()
929 .map(|p| int_cast(*p, ZZbig, StaticRing::<i64>::RING)),
930 ),
931 );
932 let value = ZZbig
933 .get_ring()
934 .parse(
935 "26959946664284515451292772736873168147996033528710027874998326058050",
936 10,
937 )
938 .unwrap();
939
940 let x: ZnEl<RustBigintRing> = ZnEl(value);
941 assert!(ZZbig.is_lt(&x.0, &ring.get_ring().twice_modulus));
943
944 assert!(ring.is_one(&x));
945 assert!(ring.is_one(&ring.mul_ref(&x, &x)));
946 assert!(ring.eq_el(&x, &ring.mul_ref(&x, &x)));
947 assert_eq!("1", format!("{}", ring.format(&x)));
948}
949
950#[test]
951fn test_serialize_deserialize() {
952 crate::serialization::generic_tests::test_serialize_deserialize(Zn::new(StaticRing::<i64>::RING, 128).into());
953 crate::serialization::generic_tests::test_serialize_deserialize(Zn::new(StaticRing::<i64>::RING, 129).into());
954 crate::serialization::generic_tests::test_serialize_deserialize(
955 Zn::new(BigIntRing::RING, BigIntRing::RING.power_of_two(10)).into(),
956 );
957}