feanor_math/rings/zn/
zn_rns.rs

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
21///
22/// A ring representing `Z/nZ` for composite n by storing the
23/// values modulo `m1, ..., mr` for `n = m1 * ... * mr`.
24/// Generally, the advantage is improved performance in cases
25/// where `m1`, ..., `mr` are sufficiently small, and can e.g.
26/// by implemented without large integers.
27/// 
28/// Note that the component rings `Z/miZ` of this ring can be
29/// accessed via the [`crate::seq::VectorView`]-functions.
30/// 
31/// # Example
32/// ```
33/// # use feanor_math::ring::*;
34/// # use feanor_math::homomorphism::*;
35/// # use feanor_math::rings::zn::*;
36/// # use feanor_math::rings::zn::zn_rns::*;
37/// # use feanor_math::primitive_int::*;
38/// # use feanor_math::integer::*;
39/// # use feanor_math::seq::*;
40/// 
41/// let R = Zn::create_from_primes(vec![17, 19], StaticRing::<i64>::RING);
42/// let x = R.get_ring().from_congruence([R.get_ring().at(0).int_hom().map(1), R.get_ring().at(1).int_hom().map(16)].into_iter());
43/// assert_eq!(35, R.smallest_lift(R.clone_el(&x)));
44/// let y = R.mul_ref(&x, &x);
45/// let z = R.get_ring().from_congruence([R.get_ring().at(0).int_hom().map(1 * 1), R.get_ring().at(1).int_hom().map(16 * 16)].into_iter());
46/// assert!(R.eq_el(&z, &y));
47/// ```
48/// 
49/// # Canonical mappings
50/// This ring has a canonical isomorphism to Barett-reduction based Zn
51/// ```
52/// # use feanor_math::ring::*;
53/// # use feanor_math::homomorphism::*;
54/// # use feanor_math::rings::zn::*;
55/// # use feanor_math::rings::zn::zn_rns::*;
56/// # use feanor_math::integer::*;
57/// # use feanor_math::primitive_int::*;
58/// let R = Zn::create_from_primes(vec![17, 19], BigIntRing::RING);
59/// let S = zn_big::Zn::new(StaticRing::<i64>::RING, 17 * 19);
60/// assert!(R.eq_el(&R.int_hom().map(12), &R.coerce(&S, S.int_hom().map(12))));
61/// assert!(S.eq_el(&S.int_hom().map(12), &R.can_iso(&S).unwrap().map(R.int_hom().map(12))));
62/// ```
63/// and a canonical homomorphism from any integer ring
64/// ```
65/// # use feanor_math::ring::*;
66/// # use feanor_math::homomorphism::*;
67/// # use feanor_math::rings::zn::*;
68/// # use feanor_math::rings::zn::zn_rns::*;
69/// # use feanor_math::integer::*;
70/// # use feanor_math::primitive_int::*;
71/// let R = Zn::create_from_primes(vec![3, 5, 7], BigIntRing::RING);
72/// let S = BigIntRing::RING;
73/// assert!(R.eq_el(&R.int_hom().map(120493), &R.coerce(&S, S.int_hom().map(120493))));
74/// ```
75/// 
76pub 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
87///
88/// The ring `Z/nZ` for composite `n` implemented using the residue number system (RNS), 
89/// i.e. storing values by storing their value modulo every factor of `n`.
90/// For details, see [`ZnBase`].
91/// 
92pub 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    ///
100    /// Creates a new ring for `Z/nZ` with `n = m1 ... mr` where the `mi` are the moduli
101    /// of the given component rings. Furthermore, the corresponding large integer ring must be
102    /// provided, which has to be able to store values of size at least `n^3`.
103    /// 
104    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    ///
124    /// Creates a new ring for `Z/nZ` with `n = m1 ... mr` where the `mi` are the moduli
125    /// of the given component rings. Furthermore, the corresponding large integer ring must be
126    /// provided, which has to be able to store values of size at least `n^3`.
127    /// 
128    #[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            // makes things much easier, e.g. during CanIsoFromTo implementation
143            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    ///
165    /// Given values `ai` for each component ring `Z/miZ`, computes the unique element in this
166    /// ring `Z/nZ` that is congruent to `ai` modulo `mi`. The "opposite" function is [`Zn::get_congruence()`].
167    /// 
168    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    ///
175    /// Given `a` in `Z/nZ`, returns the vector whose `i`-th entry is `a mod mi`, where the `mi` are the
176    /// moduli of the component rings of this ring.
177    /// 
178    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    ///
189    /// Given values `ai` for each component ring `Z/miZ`, computes the unique element in this
190    /// ring `Z/nZ` that is congruent to `ai` modulo `mi`. The "opposite" function is [`ZnBase::get_congruence()`].
191    /// 
192    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    ///
202    /// Given `a` in `Z/nZ`, returns the vector whose `i`-th entry is `a mod mi`, where the `mi` are the
203    /// moduli of the component rings of this ring.
204    /// 
205    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    // we first map each `lift(x[i]) into `self.total_ring.integer_ring(): J`, then reduce it to 
471    // `self.total_ring: Zn<J>`, then compute the value `sum_i lift(x[i]) * unit_vectors[i]` 
472    // in `self.total_ring: Zn<J>` and then map this to `from: Zn<K>`.
473    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}