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