1use std::alloc::{Allocator, Global};
2use std::fmt::Debug;
3
4use serde::Serialize;
5use serde::de::DeserializeSeed;
6use feanor_serde::newtype_struct::*;
7use feanor_serde::seq::*;
8
9use crate::algorithms::matmul::ComputeInnerProduct;
10use crate::iters::multi_cartesian_product;
11use crate::iters::MultiProduct;
12use crate::seq::VectorView;
13use crate::integer::*;
14use crate::divisibility::DivisibilityRingStore;
15use crate::rings::zn::*;
16use crate::serialization::{DeserializeWithRing, SerializableElementRing, SerializeWithRing};
17use crate::specialization::*;
18use crate::primitive_int::*;
19
20pub struct ZnBase<C: RingStore, J: RingStore, A: Allocator + Clone = Global>
76 where C::Type: ZnRing + CanHomFrom<J::Type>,
77 J::Type: IntegerRing,
78 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
79{
80 components: Vec<C>,
81 total_ring: zn_big::Zn<J>,
82 unit_vectors: Vec<El<zn_big::Zn<J>>>,
83 element_allocator: A
84}
85
86pub type Zn<C, J, A = Global> = RingValue<ZnBase<C, J, A>>;
92
93impl<C: RingStore, J: RingStore> Zn<C, J, Global>
94 where C::Type: ZnRing + CanHomFrom<J::Type>,
95 J::Type: IntegerRing,
96 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
97{
98 pub fn new(summands: Vec<C>, large_integers: J) -> Self {
104 Self::new_with_alloc(summands, large_integers, Global)
105 }
106}
107
108impl<J: RingStore> Zn<zn_64::Zn, J, Global>
109 where zn_64::ZnBase: CanHomFrom<J::Type>,
110 J::Type: IntegerRing
111{
112 pub fn create_from_primes(primes: Vec<i64>, large_integers: J) -> Self {
113 Self::new_with_alloc(primes.into_iter().map(|p| zn_64::Zn::new(p as u64)).collect(), large_integers, Global)
114 }
115}
116
117impl<C: RingStore, J: RingStore, A: Allocator + Clone> Zn<C, J, A>
118 where C::Type: ZnRing + CanHomFrom<J::Type>,
119 J::Type: IntegerRing,
120 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
121{
122 #[stability::unstable(feature = "enable")]
128 pub fn new_with_alloc(summands: Vec<C>, large_integers: J, element_allocator: A) -> Self {
129 assert!(summands.len() > 0);
130 let total_modulus = large_integers.prod(
131 summands.iter().map(|R| R.integer_ring().can_iso(&large_integers).unwrap().map_ref(R.modulus()))
132 );
133 let total_ring = zn_big::Zn::new(large_integers, total_modulus);
134 let ZZ = total_ring.integer_ring();
135 for R in &summands {
136 let R_modulus = R.integer_ring().can_iso(ZZ).unwrap().map_ref(R.modulus());
137 assert!(
138 ZZ.is_one(&algorithms::eea::signed_gcd(ZZ.checked_div(total_ring.modulus(), &R_modulus).unwrap(), R_modulus, ZZ)),
139 "all moduli must be coprime"
140 );
141 assert!(R.integer_ring().get_ring() == summands[0].integer_ring().get_ring());
143 }
144 let unit_vectors = summands.iter()
145 .map(|R: &C| (R, ZZ.checked_div(total_ring.modulus(), &R.integer_ring().can_iso(ZZ).unwrap().map_ref(R.modulus())).unwrap()))
146 .map(|(R, n)| (int_cast(R.any_lift(R.invert(&R.coerce(&ZZ, ZZ.clone_el(&n))).unwrap()), ZZ, R.integer_ring()), n))
147 .map(|(n_mod_inv, n)| total_ring.mul(total_ring.coerce(&ZZ, n_mod_inv), total_ring.coerce(&ZZ, n)))
148 .collect();
149 RingValue::from(ZnBase {
150 components: summands,
151 total_ring: total_ring,
152 unit_vectors: unit_vectors,
153 element_allocator: element_allocator
154 })
155 }
156}
157
158impl<C: RingStore, J: RingStore, A: Allocator + Clone> Zn<C, J, A>
159 where C::Type: ZnRing + CanHomFrom<J::Type>,
160 J::Type: IntegerRing,
161 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
162{
163 pub fn from_congruence<I>(&self, el: I) -> ZnEl<C, A>
168 where I: IntoIterator<Item = El<C>>
169 {
170 self.get_ring().from_congruence(el)
171 }
172
173 pub fn get_congruence<'a>(&self, el: &'a ZnEl<C, A>) -> impl 'a + VectorView<El<C>> {
178 self.get_ring().get_congruence(el)
179 }
180}
181
182impl<C: RingStore, J: RingStore, A: Allocator + Clone> ZnBase<C, J, A>
183 where C::Type: ZnRing + CanHomFrom<J::Type>,
184 J::Type: IntegerRing,
185 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
186{
187 pub fn from_congruence<I>(&self, el: I) -> ZnEl<C, A>
192 where I: IntoIterator<Item = El<C>>
193 {
194 let mut data = Vec::with_capacity_in(self.len(), self.element_allocator.clone());
195 data.extend(el);
196 assert_eq!(self.len(), data.len());
197 ZnEl { data }
198 }
199
200 pub fn get_congruence<'a>(&self, el: &'a ZnEl<C, A>) -> impl 'a + VectorView<El<C>> {
205 &el.data as &[El<C>]
206 }
207}
208
209impl<C: RingStore, J: RingStore, A: Allocator + Clone> Debug for ZnBase<C, J, A>
210 where C::Type: ZnRing + CanHomFrom<J::Type>,
211 J::Type: IntegerRing,
212 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
213{
214 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
215 write!(f, "Z/{}Z", self.integer_ring().format(self.modulus()))
216 }
217}
218
219impl<C: RingStore, J: RingStore, A: Allocator + Clone> VectorView<C> for Zn<C, J, A>
220 where C::Type: ZnRing + CanHomFrom<J::Type>,
221 J::Type: IntegerRing,
222 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
223{
224 fn len(&self) -> usize {
225 self.get_ring().len()
226 }
227
228 fn at(&self, index: usize) -> &C {
229 &self.get_ring().at(index)
230 }
231}
232
233impl<C: RingStore, J: RingStore, A: Allocator + Clone> VectorView<C> for ZnBase<C, J, A>
234 where C::Type: ZnRing + CanHomFrom<J::Type>,
235 J::Type: IntegerRing,
236 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
237{
238 fn len(&self) -> usize {
239 self.components.len()
240 }
241
242 fn at(&self, index: usize) -> &C {
243 &self.components[index]
244 }
245}
246
247pub struct ZnEl<C: RingStore, A: Allocator + Clone>
248 where C::Type: ZnRing
249{
250 data: Vec<El<C>, A>
251}
252
253impl<C, A> Debug for ZnEl<C, A>
254 where C: RingStore,
255 C::Type: ZnRing,
256 A: Allocator + Clone,
257 El<C>: Debug
258{
259 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
260 f.debug_struct("ZnEl")
261 .field("congruences", &self.data)
262 .finish()
263 }
264}
265
266impl<C: RingStore, J: RingStore, A: Allocator + Clone> RingBase for ZnBase<C, J, A>
267 where C::Type: ZnRing + CanHomFrom<J::Type>,
268 J::Type: IntegerRing,
269 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
270{
271 type Element = ZnEl<C, A>;
272
273 fn clone_el(&self, val: &Self::Element) -> Self::Element {
274 let mut data = Vec::with_capacity_in(self.len(), self.element_allocator.clone());
275 data.extend((0..self.len()).map(|i| self.at(i).clone_el(val.data.at(i))));
276 ZnEl { data }
277 }
278
279 fn add_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
280 for i in 0..self.components.len() {
281 self.components[i].add_assign_ref(&mut lhs.data[i], &rhs.data[i])
282 }
283 }
284
285 fn add_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
286 for (i, el) in (0..self.components.len()).zip(rhs.data.into_iter()) {
287 self.components[i].add_assign_ref(&mut lhs.data[i], &el)
288 }
289 }
290
291 fn sub_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
292 for i in 0..self.components.len() {
293 self.components[i].sub_assign_ref(&mut lhs.data[i], &rhs.data[i])
294 }
295 }
296
297 fn negate_inplace(&self, lhs: &mut Self::Element) {
298 for i in 0..self.components.len() {
299 self.components[i].negate_inplace(&mut lhs.data[i])
300 }
301 }
302
303 fn mul_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
304 for (i, el) in (0..self.components.len()).zip(rhs.data.into_iter()) {
305 self.components[i].mul_assign_ref(&mut lhs.data[i], &el)
306 }
307 }
308
309 fn mul_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
310 for i in 0..self.components.len() {
311 self.components[i].mul_assign_ref(&mut lhs.data[i], &rhs.data[i])
312 }
313 }
314
315 fn from_int(&self, value: i32) -> Self::Element {
316 self.from_congruence((0..self.len()).map(|i| self.components[i].get_ring().from_int(value)))
317 }
318
319 fn mul_assign_int(&self, lhs: &mut Self::Element, rhs: i32) {
320 for i in 0..self.components.len() {
321 self.components[i].int_hom().mul_assign_map(&mut lhs.data[i], rhs)
322 }
323
324 }
325
326 fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool {
327 (0..self.components.len()).zip(lhs.data.iter()).zip(rhs.data.iter()).all(|((i, l), r)| self.components[i].eq_el(l, r))
328 }
329
330 fn is_zero(&self, value: &Self::Element) -> bool {
331 (0..self.components.len()).zip(value.data.iter()).all(|(i, x)| self.components[i].is_zero(x))
332 }
333
334 fn is_one(&self, value: &Self::Element) -> bool {
335 (0..self.components.len()).zip(value.data.iter()).all(|(i, x)| self.components[i].is_one(x))
336 }
337
338 fn is_neg_one(&self, value: &Self::Element) -> bool {
339 (0..self.components.len()).zip(value.data.iter()).all(|(i, x)| self.components[i].is_neg_one(x))
340 }
341
342 fn is_commutative(&self) -> bool { true }
343 fn is_noetherian(&self) -> bool { true }
344
345 fn dbg_within<'a>(&self, value: &Self::Element, out: &mut std::fmt::Formatter<'a>, _: EnvBindingStrength) -> std::fmt::Result {
346 self.total_ring.get_ring().dbg(&RingRef::new(self).can_iso(&self.total_ring).unwrap().map_ref(value), out)
347 }
348
349 fn characteristic<I: RingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
350 where I::Type: IntegerRing
351 {
352 self.size(ZZ)
353 }
354
355 fn is_approximate(&self) -> bool { false }
356}
357
358impl<C: RingStore, J: RingStore, A: Allocator + Clone> Clone for ZnBase<C, J, A>
359 where C::Type: ZnRing + CanHomFrom<J::Type>,
360 J::Type: IntegerRing,
361 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>,
362 C: Clone,
363 J: Clone
364{
365 fn clone(&self) -> Self {
366 ZnBase {
367 components: self.components.clone(),
368 total_ring: self.total_ring.clone(),
369 unit_vectors: self.unit_vectors.iter().map(|e| self.total_ring.clone_el(e)).collect(),
370 element_allocator: self.element_allocator.clone()
371 }
372 }
373}
374
375impl<C1: RingStore, J1: RingStore, C2: RingStore, J2: RingStore, A1: Allocator + Clone, A2: Allocator + Clone> CanHomFrom<ZnBase<C2, J2, A2>> for ZnBase<C1, J1, A1>
376 where C1::Type: ZnRing + CanHomFrom<C2::Type> + CanHomFrom<J1::Type>,
377 <C1::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J1::Type>,
378 C2::Type: ZnRing + CanHomFrom<J2::Type>,
379 <C2::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J2::Type>,
380 J1::Type: IntegerRing,
381 J2::Type: IntegerRing
382{
383 type Homomorphism = Vec<<C1::Type as CanHomFrom<C2::Type>>::Homomorphism>;
384
385 fn has_canonical_hom(&self, from: &ZnBase<C2, J2, A2>) -> Option<Self::Homomorphism> {
386 if self.components.len() == from.components.len() {
387 self.components.iter()
388 .zip(from.components.iter())
389 .map(|(s, f): (&C1, &C2)| s.get_ring().has_canonical_hom(f.get_ring()).ok_or(()))
390 .collect::<Result<Self::Homomorphism, ()>>()
391 .ok()
392 } else {
393 None
394 }
395 }
396
397 fn map_in_ref(&self, from: &ZnBase<C2, J2, A2>, el: &ZnEl<C2, A2>, hom: &Self::Homomorphism) -> Self::Element {
398 assert_eq!(from.len(), el.data.len());
399 self.from_congruence((0..self.len()).map(|i|
400 self.at(i).get_ring().map_in_ref(from.at(i).get_ring(), el.data.at(i), &hom[i])
401 ))
402 }
403
404 fn map_in(&self, from: &ZnBase<C2, J2, A2>, el: ZnEl<C2, A2>, hom: &Self::Homomorphism) -> Self::Element {
405 self.map_in_ref(from, &el, hom)
406 }
407}
408
409impl<C: RingStore, J: RingStore, A: Allocator + Clone> PartialEq for ZnBase<C, J, A>
410 where C::Type: ZnRing + CanHomFrom<J::Type>,
411 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>,
412 J::Type: IntegerRing
413{
414 fn eq(&self, other: &Self) -> bool {
415 self.components.len() == other.components.len() && self.components.iter().zip(other.components.iter()).all(|(R1, R2)| R1.get_ring() == R2.get_ring())
416 }
417}
418
419impl<C1: RingStore, J1: RingStore, C2: RingStore, J2: RingStore, A1: Allocator + Clone, A2: Allocator + Clone> CanIsoFromTo<ZnBase<C2, J2, A2>> for ZnBase<C1, J1, A1>
420 where C1::Type: ZnRing + CanIsoFromTo<C2::Type> + CanHomFrom<J1::Type>,
421 <C1::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J1::Type>,
422 C2::Type: ZnRing + CanHomFrom<J2::Type>,
423 <C2::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J2::Type>,
424 J1::Type: IntegerRing,
425 J2::Type: IntegerRing
426{
427 type Isomorphism = Vec<<C1::Type as CanIsoFromTo<C2::Type>>::Isomorphism>;
428
429 fn has_canonical_iso(&self, from: &ZnBase<C2, J2, A2>) -> Option<Self::Isomorphism> {
430 if self.components.len() == from.components.len() {
431 self.components.iter()
432 .zip(from.components.iter())
433 .map(|(s, f): (&C1, &C2)| s.get_ring().has_canonical_iso(f.get_ring()).ok_or(()))
434 .collect::<Result<Self::Isomorphism, ()>>()
435 .ok()
436 } else {
437 None
438 }
439 }
440
441 fn map_out(&self, from: &ZnBase<C2, J2, A2>, el: ZnEl<C1, A1>, iso: &Self::Isomorphism) -> ZnEl<C2, A2> {
442 assert_eq!(self.len(), el.data.len());
443 from.from_congruence((0..from.len()).map(|i|
444 self.at(i).get_ring().map_out(from.at(i).get_ring(), self.at(i).clone_el(el.data.at(i)), &iso[i])
445 ))
446 }
447}
448
449impl<C: RingStore, J: RingStore, K: RingStore, A: Allocator + Clone> CanHomFrom<zn_big::ZnBase<K>> for ZnBase<C, J, A>
450 where C::Type: ZnRing + CanHomFrom<J::Type>,
451 J::Type: IntegerRing + CanIsoFromTo<K::Type>,
452 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>,
453 K::Type: IntegerRing
454{
455 type Homomorphism = (<J::Type as CanHomFrom<K::Type>>::Homomorphism, Vec<<C::Type as CanHomFrom<J::Type>>::Homomorphism>);
456
457 fn has_canonical_hom(&self, from: &zn_big::ZnBase<K>) -> Option<Self::Homomorphism> {
458 if self.total_ring.get_ring().has_canonical_hom(from).is_some() {
459 Some((
460 self.total_ring.get_ring().has_canonical_hom(from)?,
461 self.components.iter()
462 .map(|s| s.get_ring())
463 .map(|s| s.has_canonical_hom(self.integer_ring().get_ring()).ok_or(()))
464 .collect::<Result<Vec<_>, ()>>()
465 .ok()?
466 ))
467 } else {
468 None
469 }
470 }
471
472 fn map_in(&self, from: &zn_big::ZnBase<K>, el: zn_big::ZnEl<K>, hom: &Self::Homomorphism) -> ZnEl<C, A> {
473 let lift = from.smallest_positive_lift(el);
474 let mapped_lift = <J::Type as CanHomFrom<K::Type>>::map_in(
475 self.integer_ring().get_ring(),
476 from.integer_ring().get_ring(),
477 lift,
478 &hom.0
479 );
480 self.from_congruence((0..self.len()).map(|i|
481 self.at(i).get_ring().map_in_ref(self.integer_ring().get_ring(), &mapped_lift, &hom.1[i])
482 ))
483 }
484}
485
486impl<C: RingStore, J: RingStore, K: RingStore, A: Allocator + Clone> CanIsoFromTo<zn_big::ZnBase<K>> for ZnBase<C, J, A>
487 where C::Type: ZnRing + CanHomFrom<J::Type>,
488 J::Type: IntegerRing + CanIsoFromTo<K::Type>,
489 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>,
490 K::Type: IntegerRing
491{
492 type Isomorphism = (
496 <zn_big::ZnBase<J> as CanIsoFromTo<zn_big::ZnBase<K>>>::Isomorphism,
497 <zn_big::ZnBase<J> as CanHomFrom<J::Type>>::Homomorphism
498 );
499
500 fn has_canonical_iso(&self, from: &zn_big::ZnBase<K>) -> Option<Self::Isomorphism> {
501 Some((
502 <zn_big::ZnBase<J> as CanIsoFromTo<zn_big::ZnBase<K>>>::has_canonical_iso(self.total_ring.get_ring(), from)?,
503 self.total_ring.get_ring().has_canonical_hom(self.total_ring.integer_ring().get_ring())?,
504 ))
505 }
506
507 fn map_out(&self, from: &zn_big::ZnBase<K>, el: Self::Element, (final_iso, red): &Self::Isomorphism) -> zn_big::ZnEl<K> {
508 assert_eq!(self.len(), el.data.len());
509 let small_integer_ring = self.at(0).integer_ring();
510 let result = <_ as ComputeInnerProduct>::inner_product_ref_fst(self.total_ring.get_ring(),
511 self.components.iter()
512 .zip(el.data.into_iter())
513 .map(|(R, x): (&C, El<C>)| R.smallest_positive_lift(x))
514 .zip(self.unit_vectors.iter())
515 .map(|(x, u)|
516 (
517 u,
518 self.total_ring.get_ring().map_in(
519 self.total_ring.integer_ring().get_ring(),
520 int_cast(x, self.total_ring.integer_ring(), small_integer_ring),
521 red
522 )
523 )
524 )
525 );
526 return <zn_big::ZnBase<J> as CanIsoFromTo<zn_big::ZnBase<K>>>::map_out(self.total_ring.get_ring(), from, result, final_iso);
527 }
528}
529
530impl<C: RingStore, J: RingStore, A: Allocator + Clone> CanHomFrom<zn_64::ZnBase> for ZnBase<C, J, A>
531 where C::Type: ZnRing + CanHomFrom<J::Type>,
532 J::Type: IntegerRing + CanIsoFromTo<StaticRingBase<i64>>,
533 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
534{
535 type Homomorphism = (<Self as CanHomFrom<zn_big::ZnBase<J>>>::Homomorphism, <zn_big::ZnBase<J> as CanHomFrom<zn_64::ZnBase>>::Homomorphism);
536
537 fn has_canonical_hom(&self, from: &zn_64::ZnBase) -> Option<Self::Homomorphism> {
538 Some((self.has_canonical_hom(self.total_ring.get_ring())?, self.total_ring.get_ring().has_canonical_hom(from)?))
539 }
540
541 fn map_in(&self, from: &zn_64::ZnBase, el: zn_64::ZnEl, hom: &Self::Homomorphism) -> ZnEl<C, A> {
542 self.map_in(self.total_ring.get_ring(), self.total_ring.get_ring().map_in(from, el, &hom.1), &hom.0)
543 }
544}
545
546impl<C: RingStore, J: RingStore, K: IntegerRing, A: Allocator + Clone> CanHomFrom<K> for ZnBase<C, J, A>
547 where C::Type: ZnRing + CanHomFrom<J::Type> + CanHomFrom<K>,
548 J::Type: IntegerRing,
549 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>,
550 K: ?Sized
551{
552 type Homomorphism = Vec<<C::Type as CanHomFrom<K>>::Homomorphism>;
553
554 fn has_canonical_hom(&self, from: &K) -> Option<Self::Homomorphism> {
555 Some(self.components.iter()
556 .map(|R| <C::Type as CanHomFrom<K>>::has_canonical_hom(R.get_ring(), from).ok_or(()))
557 .collect::<Result<Vec<<C::Type as CanHomFrom<K>>::Homomorphism>, ()>>()
558 .ok()?
559 )
560 }
561
562 fn map_in(&self, from: &K, el: K::Element, hom: &Self::Homomorphism) -> Self::Element {
563 self.from_congruence((0..self.len()).map(|i|
564 <C::Type as CanHomFrom<K>>::map_in_ref(self.at(i).get_ring(), from, &el, &hom[i])
565 ))
566 }
567}
568
569impl<C: RingStore, J: RingStore, A: Allocator + Clone> DivisibilityRing for ZnBase<C, J, A>
570 where C::Type: ZnRing + CanHomFrom<J::Type>,
571 J::Type: IntegerRing,
572 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
573{
574 fn checked_left_div(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
575 let mut data = Vec::with_capacity_in(self.len(), self.element_allocator.clone());
576 for i in 0..self.len() {
577 data.push(self.at(i).checked_div(lhs.data.at(i), rhs.data.at(i))?);
578 }
579 return Some(ZnEl { data });
580 }
581}
582
583pub struct FromCongruenceElementCreator<'a, C: RingStore, J: RingStore, A: Allocator + Clone>
584 where C::Type: ZnRing + CanHomFrom<J::Type>,
585 J::Type: IntegerRing,
586 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
587{
588 ring: &'a ZnBase<C, J, A>
589}
590
591impl<'a, 'b, C: RingStore, J: RingStore, A: Allocator + Clone> Clone for FromCongruenceElementCreator<'a, C, J, A>
592 where C::Type: ZnRing + CanHomFrom<J::Type>,
593 J::Type: IntegerRing,
594 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
595{
596 fn clone(&self) -> Self {
597 *self
598 }
599}
600
601impl<'a, 'b, C: RingStore, J: RingStore, A: Allocator + Clone> Copy for FromCongruenceElementCreator<'a, C, J, A>
602 where C::Type: ZnRing + CanHomFrom<J::Type>,
603 J::Type: IntegerRing,
604 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
605{}
606
607impl<'a, 'b, C: RingStore, J: RingStore, A: Allocator + Clone> FnOnce<(&'b [El<C>],)> for FromCongruenceElementCreator<'a, C, J, A>
608 where C::Type: ZnRing + CanHomFrom<J::Type>,
609 J::Type: IntegerRing,
610 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
611{
612 type Output = <ZnBase<C, J, A> as RingBase>::Element;
613
614 extern "rust-call" fn call_once(mut self, args: (&'b [El<C>],)) -> Self::Output {
615 self.call_mut(args)
616 }
617}
618
619impl<'a, 'b, C: RingStore, J: RingStore, A: Allocator + Clone> FnMut<(&'b [El<C>],)> for FromCongruenceElementCreator<'a, C, J, A>
620 where C::Type: ZnRing + CanHomFrom<J::Type>,
621 J::Type: IntegerRing,
622 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
623{
624 extern "rust-call" fn call_mut(&mut self, args: (&'b [El<C>],)) -> Self::Output {
625 self.ring.from_congruence(args.0.into_iter().enumerate().map(|(i, x)| self.ring.at(i).clone_el(x)))
626 }
627}
628
629pub struct CloneComponentElement<'a, C: RingStore, J: RingStore, A: Allocator + Clone>
630 where C::Type: ZnRing + CanHomFrom<J::Type>,
631 J::Type: IntegerRing,
632 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
633{
634 ring: &'a ZnBase<C, J, A>
635}
636
637impl<'a, 'b, C: RingStore, J: RingStore, A: Allocator + Clone> Clone for CloneComponentElement<'a, C, J, A>
638 where C::Type: ZnRing + CanHomFrom<J::Type>,
639 J::Type: IntegerRing,
640 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
641{
642 fn clone(&self) -> Self {
643 *self
644 }
645}
646
647impl<'a, 'b, C: RingStore, J: RingStore, A: Allocator + Clone> Copy for CloneComponentElement<'a, C, J, A>
648 where C::Type: ZnRing + CanHomFrom<J::Type>,
649 J::Type: IntegerRing,
650 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
651{}
652
653impl<'a, 'b, C: RingStore, J: RingStore, A: Allocator + Clone> FnOnce<(usize, &'b El<C>)> for CloneComponentElement<'a, C, J, A>
654 where C::Type: ZnRing + CanHomFrom<J::Type>,
655 J::Type: IntegerRing,
656 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
657{
658 type Output = El<C>;
659
660 extern "rust-call" fn call_once(mut self, args: (usize, &'b El<C>)) -> Self::Output {
661 self.call_mut(args)
662 }
663}
664
665impl<'a, 'b, C: RingStore, J: RingStore, A: Allocator + Clone> FnMut<(usize, &'b El<C>)> for CloneComponentElement<'a, C, J, A>
666 where C::Type: ZnRing + CanHomFrom<J::Type>,
667 J::Type: IntegerRing,
668 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
669{
670 extern "rust-call" fn call_mut(&mut self, args: (usize, &'b El<C>)) -> Self::Output {
671 self.call(args)
672 }
673}
674
675impl<'a, 'b, C: RingStore, J: RingStore, A: Allocator + Clone> Fn<(usize, &'b El<C>)> for CloneComponentElement<'a, C, J, A>
676 where C::Type: ZnRing + CanHomFrom<J::Type>,
677 J::Type: IntegerRing,
678 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
679{
680 extern "rust-call" fn call(&self, args: (usize, &'b El<C>)) -> Self::Output {
681 self.ring.at(args.0).clone_el(args.1)
682 }
683}
684
685impl<C: RingStore, J: RingStore, A: Allocator + Clone> HashableElRing for ZnBase<C, J, A>
686 where C::Type: ZnRing + CanHomFrom<J::Type> + HashableElRing,
687 J::Type: IntegerRing,
688 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
689{
690 fn hash<H: std::hash::Hasher>(&self, el: &Self::Element, h: &mut H) {
691 for (i, el) in (0..self.components.len()).zip(el.data.iter()) {
692 self.components[i].hash(el, h);
693 }
694 }
695}
696
697impl<C: RingStore, J: RingStore, A: Allocator + Clone> FiniteRingSpecializable for ZnBase<C, J, A>
698 where C::Type: ZnRing + CanHomFrom<J::Type>,
699 J::Type: IntegerRing,
700 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
701{
702 fn specialize<O: FiniteRingOperation<Self>>(op: O) -> O::Output {
703 op.execute()
704 }
705}
706
707impl<C: RingStore, J: RingStore, A: Allocator + Clone> FiniteRing for ZnBase<C, J, A>
708 where C::Type: ZnRing + CanHomFrom<J::Type>,
709 J::Type: IntegerRing,
710 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
711{
712 type ElementsIter<'a> = MultiProduct<<C::Type as FiniteRing>::ElementsIter<'a>, FromCongruenceElementCreator<'a, C, J, A>, CloneComponentElement<'a, C, J, A>, Self::Element>
713 where Self: 'a;
714
715 fn elements<'a>(&'a self) -> Self::ElementsIter<'a> {
716 multi_cartesian_product((0..self.len()).map(|i| self.at(i).elements()), FromCongruenceElementCreator { ring: self }, CloneComponentElement { ring: self })
717 }
718
719 fn random_element<G: FnMut() -> u64>(&self, mut rng: G) -> ZnEl<C, A> {
720 self.from_congruence((0..self.len()).map(|i| self.at(i).random_element(&mut rng)))
721 }
722
723 fn size<I: RingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
724 where I::Type: IntegerRing
725 {
726 if ZZ.get_ring().representable_bits().is_none() || self.integer_ring().abs_log2_ceil(self.modulus()) < ZZ.get_ring().representable_bits() {
727 Some(int_cast(self.integer_ring().clone_el(self.modulus()), ZZ, self.integer_ring()))
728 } else {
729 None
730 }
731 }
732}
733
734impl<C: RingStore, J: RingStore, A: Allocator + Clone> PrincipalIdealRing for ZnBase<C, J, A>
735 where C::Type: ZnRing + CanHomFrom<J::Type>,
736 J::Type: IntegerRing,
737 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
738{
739 fn checked_div_min(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
740 let mut data = Vec::with_capacity_in(self.len(), self.element_allocator.clone());
741 for i in 0..self.len() {
742 data.push(self.at(i).checked_div_min(lhs.data.at(i), rhs.data.at(i))?);
743 }
744 return Some(ZnEl { data });
745 }
746
747 fn extended_ideal_gen(&self, lhs: &Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element, Self::Element) {
748 let mut result = (self.zero(), self.zero(), self.zero());
749 for (i, Zn) in self.as_iter().enumerate() {
750 (result.0.data[i], result.1.data[i], result.2.data[i]) = Zn.extended_ideal_gen(&lhs.data[i], &rhs.data[i]);
751 }
752 return result;
753 }
754}
755
756impl<C: RingStore, J: RingStore, A: Allocator + Clone> ZnRing for ZnBase<C, J, A>
757 where C::Type: ZnRing + CanHomFrom<J::Type>,
758 J::Type: IntegerRing,
759 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
760{
761 type IntegerRingBase = J::Type;
762 type IntegerRing = J;
763
764 fn integer_ring(&self) -> &Self::IntegerRing {
765 self.total_ring.integer_ring()
766 }
767
768 fn modulus(&self) -> &El<Self::IntegerRing> {
769 self.total_ring.modulus()
770 }
771
772 fn smallest_positive_lift(&self, el: Self::Element) -> El<Self::IntegerRing> {
773 self.total_ring.smallest_positive_lift(
774 <Self as CanIsoFromTo<zn_big::ZnBase<J>>>::map_out(
775 self,
776 self.total_ring.get_ring(),
777 el,
778 &<Self as CanIsoFromTo<zn_big::ZnBase<J>>>::has_canonical_iso(self, self.total_ring.get_ring()).unwrap()
779 )
780 )
781 }
782
783 fn smallest_lift(&self, el: Self::Element) -> El<Self::IntegerRing> {
784 self.total_ring.smallest_lift(
785 <Self as CanIsoFromTo<zn_big::ZnBase<J>>>::map_out(
786 self,
787 self.total_ring.get_ring(),
788 el,
789 &<Self as CanIsoFromTo<zn_big::ZnBase<J>>>::has_canonical_iso(self, self.total_ring.get_ring()).unwrap()
790 )
791 )
792 }
793
794 fn is_field(&self) -> bool {
795 self.components.len() == 1 && self.components[0].is_field()
796 }
797
798 fn from_int_promise_reduced(&self, x: El<Self::IntegerRing>) -> Self::Element {
799 debug_assert!(!self.integer_ring().is_neg(&x));
800 debug_assert!(self.integer_ring().is_lt(&x, self.modulus()));
801 RingRef::new(self).can_hom(self.integer_ring()).unwrap().map(x)
802 }
803}
804
805impl<C: RingStore, J: RingStore, A: Allocator + Clone> SerializableElementRing for ZnBase<C, J, A>
806 where C::Type: ZnRing + CanHomFrom<J::Type> + SerializableElementRing,
807 J::Type: IntegerRing + SerializableElementRing,
808 <C::Type as ZnRing>::IntegerRingBase: IntegerRing + CanIsoFromTo<J::Type>
809{
810 fn serialize<S>(&self, el: &Self::Element, serializer: S) -> Result<S::Ok, S::Error>
811 where S: serde::Serializer
812 {
813 if serializer.is_human_readable() {
814 self.total_ring.get_ring().serialize(
815 &RingRef::new(self).can_iso(&self.total_ring).unwrap().map_ref(el),
816 serializer
817 )
818 } else {
819 let el_congruence = self.get_congruence(el);
820 SerializableNewtypeStruct::new("RNSZnEl", SerializableSeq::new_with_len((0..self.len()).map(|i| SerializeWithRing::new(el_congruence.at(i), self.at(i))), self.len())).serialize(serializer)
821 }
822 }
823
824 fn deserialize<'de, D>(&self, deserializer: D) -> Result<Self::Element, D::Error>
825 where D: serde::Deserializer<'de>
826 {
827 if deserializer.is_human_readable() {
828 Ok(RingRef::new(self).can_hom(&self.total_ring).unwrap().map(
829 self.total_ring.get_ring().deserialize(deserializer)?
830 ))
831 } else {
832 let dummy_ring = self.at(0);
833 DeserializeSeedNewtypeStruct::new("RNSZnEl", DeserializeSeedSeq::new(
834 self.as_iter().map(|ring| DeserializeWithRing::new(ring)).chain([DeserializeWithRing::new(dummy_ring)].into_iter()),
835 Vec::with_capacity_in(self.len(), self.element_allocator.clone()),
836 |mut current, next| { current.push(next); current }
837 )).deserialize(deserializer).map(|result| ZnEl {
838 data: result
839 })
840 }
841 }
842}
843
844#[cfg(test)]
845use crate::primitive_int::StaticRing;
846
847#[cfg(test)]
848const EDGE_CASE_ELEMENTS: [i32; 9] = [0, 1, 7, 9, 62, 8, 10, 11, 12];
849
850#[test]
851fn test_ring_axioms() {
852 let ring = Zn::create_from_primes(vec![7, 11], StaticRing::<i64>::RING);
853 crate::ring::generic_tests::test_ring_axioms(&ring, EDGE_CASE_ELEMENTS.iter().cloned().map(|x| ring.int_hom().map(x)))
854}
855
856#[test]
857fn test_hash_axioms() {
858 let ring = Zn::create_from_primes(vec![7, 11], StaticRing::<i64>::RING);
859 crate::ring::generic_tests::test_hash_axioms(&ring, EDGE_CASE_ELEMENTS.iter().cloned().map(|x| ring.int_hom().map(x)))
860}
861
862#[test]
863fn test_map_in_map_out() {
864 let ring1 = Zn::create_from_primes(vec![7, 11, 17], StaticRing::<i64>::RING);
865 let ring2 = zn_big::Zn::new(StaticRing::<i64>::RING, 7 * 11 * 17);
866 for x in [0, 1, 7, 8, 9, 10, 11, 17, 7 * 17, 11 * 8, 11 * 17, 7 * 11 * 17 - 1] {
867 let value = ring2.int_hom().map(x);
868 assert!(ring2.eq_el(&value, &ring1.can_iso(&ring2).unwrap().map(ring1.coerce(&ring2, value.clone()))));
869 }
870}
871
872#[test]
873fn test_canonical_iso_axioms_zn_big() {
874 let from = zn_big::Zn::new(StaticRing::<i128>::RING, 7 * 11);
875 let to = Zn::create_from_primes(vec![7, 11], StaticRing::<i64>::RING);
876 crate::ring::generic_tests::test_hom_axioms(&from, &to, EDGE_CASE_ELEMENTS.iter().cloned().map(|x| from.int_hom().map(x)));
877 crate::ring::generic_tests::test_iso_axioms(&from, &to, EDGE_CASE_ELEMENTS.iter().cloned().map(|x| from.int_hom().map(x)));
878
879 let from = zn_big::Zn::new(StaticRing::<i128>::RING, 7 * 11 * 65537);
880 let to = Zn::create_from_primes(vec![7, 11, 65537], StaticRing::<i128>::RING);
881 crate::ring::generic_tests::test_hom_axioms(&from, &to, from.elements().step_by(65536));
882 crate::ring::generic_tests::test_iso_axioms(&from, &to, from.elements().step_by(65536));
883}
884
885#[test]
886fn test_canonical_hom_axioms_static_int() {
887 let from = StaticRing::<i32>::RING;
888 let to = Zn::create_from_primes(vec![7, 11], StaticRing::<i64>::RING);
889 crate::ring::generic_tests::test_hom_axioms(&from, to, EDGE_CASE_ELEMENTS.iter().cloned().map(|x| from.int_hom().map(x)));
890}
891
892#[test]
893fn test_zn_ring_axioms() {
894 let ring = Zn::create_from_primes(vec![7, 11], StaticRing::<i64>::RING);
895 super::generic_tests::test_zn_axioms(ring);
896}
897
898#[test]
899fn test_zn_map_in_large_int() {
900 let ring = Zn::create_from_primes(vec![7, 11], BigIntRing::RING);
901 super::generic_tests::test_map_in_large_int(ring);
902
903 let R = Zn::create_from_primes(vec![3, 5, 7], BigIntRing::RING);
904 let S = BigIntRing::RING;
905 assert!(R.eq_el(&R.int_hom().map(120493), &R.coerce(&S, S.int_hom().map(120493))));
906}
907
908#[test]
909fn test_principal_ideal_ring_axioms() {
910 let R = Zn::create_from_primes(vec![5], BigIntRing::RING);
911 crate::pid::generic_tests::test_principal_ideal_ring_axioms(&R, R.elements());
912
913 let R = Zn::create_from_primes(vec![3, 5], BigIntRing::RING);
914 crate::pid::generic_tests::test_principal_ideal_ring_axioms(&R, R.elements());
915
916 let R = Zn::create_from_primes(vec![2, 3, 5], BigIntRing::RING);
917 crate::pid::generic_tests::test_principal_ideal_ring_axioms(&R, R.elements());
918
919 let R = Zn::create_from_primes(vec![3, 5, 2], BigIntRing::RING);
920 let modulo = R.int_hom();
921 crate::pid::generic_tests::test_principal_ideal_ring_axioms(
922 &R,
923 [-1, 0, 1, 3, 2, 4, 5, 9, 18, 15, 30].into_iter().map(|x| modulo.map(x))
924 );
925}
926
927#[test]
928fn test_finite_ring_axioms() {
929 crate::rings::finite::generic_tests::test_finite_ring_axioms(&Zn::create_from_primes(vec![3, 5, 7, 11], StaticRing::<i64>::RING));
930 crate::rings::finite::generic_tests::test_finite_ring_axioms(&Zn::create_from_primes(vec![3, 5], StaticRing::<i64>::RING));
931 crate::rings::finite::generic_tests::test_finite_ring_axioms(&Zn::create_from_primes(vec![3], StaticRing::<i64>::RING));
932 crate::rings::finite::generic_tests::test_finite_ring_axioms(&Zn::create_from_primes(vec![2], StaticRing::<i64>::RING));
933}
934
935#[test]
936fn test_not_prime() {
937 let ring = Zn::new(vec![zn_64::Zn::new(15), zn_64::Zn::new(7)], StaticRing::<i64>::RING);
938 let equivalent_ring = zn_big::Zn::new(StaticRing::<i64>::RING, 15 * 7);
939 crate::ring::generic_tests::test_ring_axioms(&ring, ring.elements());
940 crate::divisibility::generic_tests::test_divisibility_axioms(&ring, ring.elements());
941 crate::homomorphism::generic_tests::test_homomorphism_axioms(ring.can_hom(&equivalent_ring).unwrap(), equivalent_ring.elements());
942 crate::homomorphism::generic_tests::test_homomorphism_axioms(ring.can_iso(&equivalent_ring).unwrap(), ring.elements());
943}
944
945#[test]
946fn test_serialization() {
947 let ring = Zn::create_from_primes(vec![3, 5, 7], StaticRing::<i64>::RING);
948 crate::serialization::generic_tests::test_serialization(&ring, ring.elements());
949}
950
951#[test]
952#[should_panic]
953fn test_not_coprime() {
954 _ = Zn::new(vec![zn_64::Zn::new(15), zn_64::Zn::new(35)], StaticRing::<i64>::RING);
955}
956
957#[test]
958fn test_format() {
959 let ring = Zn::new([72057594035352641, 72057594035418113, 72057594036334721, 72057594036945793, ].iter().map(|p| zn_64::Zn::new(*p)).collect(), BigIntRing::RING);
960 assert_eq!("1", format!("{}", ring.format(&ring.int_hom().map(1))));
961}