feanor_math/rings/
local.rs

1use crate::algorithms::convolution::KaratsubaHint;
2use crate::algorithms::int_factor::is_prime_power;
3use crate::algorithms::matmul::*;
4use crate::reduce_lift::poly_eval::InterpolationBaseRing;
5use crate::delegate::*;
6use crate::divisibility::{DivisibilityRing, DivisibilityRingStore, Domain};
7use crate::field::Field;
8use crate::local::{PrincipalLocalRing, PrincipalLocalRingStore};
9use crate::pid::*;
10use crate::integer::IntegerRing;
11use crate::ring::*;
12use crate::homomorphism::*;
13use super::field::{AsField, AsFieldBase};
14use crate::rings::zn::*;
15
16///
17/// A wrapper around a ring that marks this ring to be a local principal ideal ring. 
18/// 
19/// The design is analogous to [`crate::rings::field::AsFieldBase`].
20/// 
21#[stability::unstable(feature = "enable")]
22pub struct AsLocalPIRBase<R: DivisibilityRingStore> 
23    where R::Type: DivisibilityRing
24{
25    base: R,
26    max_ideal_gen: LocalPIREl<R>,
27    nilpotent_power: Option<usize>
28}
29
30impl<R> Clone for AsLocalPIRBase<R>
31    where R: DivisibilityRingStore + Clone,
32        R::Type: DivisibilityRing
33{
34    fn clone(&self) -> Self {
35        Self {
36            base: self.base.clone(),
37            max_ideal_gen: self.clone_el(&self.max_ideal_gen),
38            nilpotent_power: self.nilpotent_power
39        }
40    }
41}
42
43impl<R> Copy for AsLocalPIRBase<R>
44    where R: DivisibilityRingStore + Copy,
45        R::Type: DivisibilityRing,
46        El<R>: Copy
47{}
48
49impl<R> PartialEq for AsLocalPIRBase<R>
50    where R: DivisibilityRingStore,
51        R::Type: DivisibilityRing
52{
53    fn eq(&self, other: &Self) -> bool {
54        self.base.get_ring() == other.base.get_ring()
55    }
56}
57
58///
59/// [`RingStore`] for [`AsLocalPIRBase`].
60/// 
61#[stability::unstable(feature = "enable")]
62pub type AsLocalPIR<R> = RingValue<AsLocalPIRBase<R>>;
63
64#[stability::unstable(feature = "enable")]
65pub struct LocalPIREl<R: DivisibilityRingStore>(El<R>)
66    where R::Type: DivisibilityRing;
67
68impl<R: DivisibilityRingStore> Clone for LocalPIREl<R> 
69    where El<R>: Clone,
70        R::Type: DivisibilityRing
71{
72    fn clone(&self) -> Self {
73        LocalPIREl(self.0.clone())
74    }
75}
76
77impl<R: DivisibilityRingStore> Copy for LocalPIREl<R> 
78    where El<R>: Copy,
79        R::Type: DivisibilityRing
80{}
81
82impl<R> AsLocalPIR<R> 
83    where R: RingStore, 
84        R::Type: ZnRing
85{
86    #[stability::unstable(feature = "enable")]
87    pub fn from_zn(ring: R) -> Option<Self> {
88        let (p, e) = is_prime_power(ring.integer_ring(), ring.modulus())?;
89        let g = ring.can_hom(ring.integer_ring()).unwrap().map(p);
90        Some(Self::from(AsLocalPIRBase::promise_is_local_pir(ring, g, Some(e))))
91    }
92}
93
94impl<R> AsLocalPIR<R> 
95    where R: RingStore, 
96        R::Type: Field
97{
98    #[stability::unstable(feature = "enable")]
99    pub fn from_field(ring: R) -> Self {
100        let zero = ring.zero();
101        Self::from(AsLocalPIRBase::promise_is_local_pir(ring, zero, Some(1)))
102    }
103}
104
105impl<R> AsLocalPIR<R> 
106    where R: RingStore, 
107        R::Type: PrincipalLocalRing
108{
109    #[stability::unstable(feature = "enable")]
110    pub fn from_localpir(ring: R) -> Self {
111        let max_ideal_gen = ring.clone_el(ring.max_ideal_gen());
112        let nilpotent_power = ring.nilpotent_power();
113        Self::from(AsLocalPIRBase::promise_is_local_pir(ring, max_ideal_gen, nilpotent_power))
114    }
115}
116
117impl<R> AsLocalPIR<R> 
118    where R: RingStore, 
119        R::Type: DivisibilityRing
120{
121    #[stability::unstable(feature = "enable")]
122    pub fn from_as_field(ring: AsField<R>) -> Self {
123        let ring = ring.into().unwrap_self();
124        let zero = ring.zero();
125        Self::from(AsLocalPIRBase::promise_is_local_pir(ring, zero, Some(1)))
126    }
127}
128
129impl<R: DivisibilityRingStore> AsLocalPIRBase<R> 
130    where R::Type: DivisibilityRing
131{
132    #[stability::unstable(feature = "enable")]
133    pub fn promise_is_local_pir(base: R, max_ideal_gen: El<R>, nilpotent_power: Option<usize>) -> Self {
134        assert!(base.is_commutative());
135        let max_ideal_gen = LocalPIREl(max_ideal_gen);
136        Self { base, max_ideal_gen, nilpotent_power }
137    }
138
139    #[stability::unstable(feature = "enable")]
140    pub fn unwrap_element(&self, el: <Self as RingBase>::Element) -> El<R> {
141        el.0
142    }
143
144    #[stability::unstable(feature = "enable")]
145    pub fn unwrap_self(self) -> R {
146        self.base
147    }
148}
149
150impl<R: DivisibilityRingStore> DelegateRing for AsLocalPIRBase<R> 
151    where R::Type: DivisibilityRing
152{
153    type Element = LocalPIREl<R>;
154    type Base = R::Type;
155
156    fn get_delegate(&self) -> &Self::Base {
157        self.base.get_ring()
158    }
159
160    fn delegate(&self, el: Self::Element) -> <Self::Base as RingBase>::Element {
161        el.0
162    }
163
164    fn delegate_mut<'a>(&self, el: &'a mut Self::Element) -> &'a mut <Self::Base as RingBase>::Element {
165        &mut el.0
166    }
167
168    fn delegate_ref<'a>(&self, el: &'a Self::Element) -> &'a <Self::Base as RingBase>::Element {
169        &el.0
170    }
171
172    fn rev_delegate(&self, el: <Self::Base as RingBase>::Element) -> Self::Element {
173        LocalPIREl(el)
174    }
175}
176
177impl<R: DivisibilityRingStore> DelegateRingImplFiniteRing for AsLocalPIRBase<R> 
178    where R::Type: DivisibilityRing
179{}
180
181impl<R: DivisibilityRingStore, S: DivisibilityRingStore> CanHomFrom<AsLocalPIRBase<S>> for AsLocalPIRBase<R> 
182    where R::Type: DivisibilityRing + CanHomFrom<S::Type>,
183        S::Type: DivisibilityRing
184{
185    type Homomorphism = <R::Type as CanHomFrom<S::Type>>::Homomorphism;
186
187    fn has_canonical_hom(&self, from: &AsLocalPIRBase<S>) -> Option<Self::Homomorphism> {
188        <R::Type as CanHomFrom<S::Type>>::has_canonical_hom(self.get_delegate(), from.get_delegate())
189    }
190
191    fn map_in(&self, from: &AsLocalPIRBase<S>, el: LocalPIREl<S>, hom: &Self::Homomorphism) -> Self::Element {
192        LocalPIREl(<R::Type as CanHomFrom<S::Type>>::map_in(self.get_delegate(), from.get_delegate(), el.0, hom))
193    }
194}
195
196impl<R: DivisibilityRingStore, S: DivisibilityRingStore> CanIsoFromTo<AsLocalPIRBase<S>> for AsLocalPIRBase<R> 
197    where R::Type: DivisibilityRing + CanIsoFromTo<S::Type>,
198        S::Type: DivisibilityRing
199{
200    type Isomorphism = <R::Type as CanIsoFromTo<S::Type>>::Isomorphism;
201
202    fn has_canonical_iso(&self, from: &AsLocalPIRBase<S>) -> Option<Self::Isomorphism> {
203        <R::Type as CanIsoFromTo<S::Type>>::has_canonical_iso(self.get_delegate(), from.get_delegate())
204    }
205
206    fn map_out(&self, from: &AsLocalPIRBase<S>, el: Self::Element, iso: &Self::Isomorphism) -> LocalPIREl<S> {
207        LocalPIREl(<R::Type as CanIsoFromTo<S::Type>>::map_out(self.get_delegate(), from.get_delegate(), el.0, iso))
208    }
209}
210
211///
212/// Necessary to potentially implement [`crate::rings::zn::ZnRing`].
213/// 
214impl<R: DivisibilityRingStore, S: IntegerRing + ?Sized> CanHomFrom<S> for AsLocalPIRBase<R> 
215    where R::Type: DivisibilityRing + CanHomFrom<S>
216{
217    type Homomorphism = <R::Type as CanHomFrom<S>>::Homomorphism;
218
219    fn has_canonical_hom(&self, from: &S) -> Option<Self::Homomorphism> {
220        self.get_delegate().has_canonical_hom(from)
221    }
222
223    fn map_in(&self, from: &S, el: S::Element, hom: &Self::Homomorphism) -> Self::Element {
224        LocalPIREl(<R::Type as CanHomFrom<S>>::map_in(self.get_delegate(), from, el, hom))
225    }
226}
227
228impl<R: DivisibilityRingStore> DivisibilityRing for AsLocalPIRBase<R> 
229    where R::Type: DivisibilityRing
230{
231    fn checked_left_div(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
232        self.get_delegate().checked_left_div(&lhs.0, &rhs.0).map(LocalPIREl)
233    }
234}
235
236impl<R: DivisibilityRingStore> PrincipalIdealRing for AsLocalPIRBase<R> 
237    where R::Type: DivisibilityRing
238{
239    fn checked_div_min(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
240        if let Some(e) = self.nilpotent_power {
241            if self.is_zero(lhs) && self.is_zero(rhs) {
242                return Some(self.one());
243            } else if self.is_zero(lhs) {
244                return Some(RingRef::new(self).pow(self.clone_el(self.max_ideal_gen()), e - self.valuation(rhs).unwrap()));
245            } else {
246                // the constraint `rhs * result = lhs` already fixes the evaluation of `result` uniquely
247                return self.checked_left_div(lhs, rhs);
248            }
249        } else {
250            // we are in a domain
251            self.checked_left_div(lhs, rhs)
252        }
253    }
254
255    fn extended_ideal_gen(&self, lhs: &Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element, Self::Element) {
256        if self.checked_left_div(lhs, rhs).is_some() {
257            (self.zero(), self.one(), self.clone_el(rhs))
258        } else {
259            (self.one(), self.zero(), self.clone_el(lhs))
260        }
261    }
262
263    fn create_elimination_matrix(&self, a: &Self::Element, b: &Self::Element) -> ([Self::Element; 4], Self::Element) {
264        if let Some(quo) = self.checked_left_div(b, a) {
265            (
266                [self.one(), self.zero(), self.negate(quo), self.one()],
267                self.clone_el(a)
268            )
269        } else {
270            let quo = self.checked_left_div(a, b).unwrap();
271            (
272                [self.zero(), self.one(), self.one(), self.negate(quo)],
273                self.clone_el(b)
274            )
275        }
276    }
277}
278
279impl<R: DivisibilityRingStore> KaratsubaHint for AsLocalPIRBase<R>
280    where R::Type: DivisibilityRing
281{
282    fn karatsuba_threshold(&self) -> usize {
283        self.get_delegate().karatsuba_threshold()
284    }
285}
286
287impl<R: DivisibilityRingStore> StrassenHint for AsLocalPIRBase<R>
288    where R::Type: DivisibilityRing
289{
290    fn strassen_threshold(&self) -> usize {
291        self.get_delegate().strassen_threshold()
292    }
293}
294
295impl<R: DivisibilityRingStore> ComputeInnerProduct for AsLocalPIRBase<R>
296    where R::Type: DivisibilityRing
297{
298    fn inner_product<I: Iterator<Item = (Self::Element, Self::Element)>>(&self, els: I) -> Self::Element {
299        self.rev_delegate(self.get_delegate().inner_product(els.map(|(a, b)| (self.delegate(a), self.delegate(b)))))
300    }
301
302    fn inner_product_ref<'a, I: Iterator<Item = (&'a Self::Element, &'a Self::Element)>>(&self, els: I) -> Self::Element
303        where Self::Element: 'a,
304            Self: 'a
305    {
306        self.rev_delegate(self.get_delegate().inner_product_ref(els.map(|(a, b)| (self.delegate_ref(a), self.delegate_ref(b)))))
307    }
308
309    fn inner_product_ref_fst<'a, I: Iterator<Item = (&'a Self::Element, Self::Element)>>(&self, els: I) -> Self::Element
310        where Self::Element: 'a,
311            Self: 'a
312    {
313        self.rev_delegate(self.get_delegate().inner_product_ref_fst(els.map(|(a, b)| (self.delegate_ref(a), self.delegate(b)))))
314    }
315}
316
317impl<R: DivisibilityRingStore> EuclideanRing for AsLocalPIRBase<R> 
318    where R::Type: DivisibilityRing
319{
320    fn euclidean_div_rem(&self, lhs: Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element) {
321        if let Some(quo) = self.checked_left_div(&lhs, rhs) {
322            (quo, self.zero())
323        } else {
324            (self.zero(), lhs)
325        }
326    }
327
328    fn euclidean_deg(&self, val: &Self::Element) -> Option<usize> {
329        self.valuation(val)
330    }
331}
332
333impl<R: DivisibilityRingStore> PrincipalLocalRing for AsLocalPIRBase<R> 
334    where R::Type: DivisibilityRing
335{
336    fn max_ideal_gen(&self) ->  &Self::Element {
337        &self.max_ideal_gen
338    }
339
340    fn nilpotent_power(&self) -> Option<usize> {
341        self.nilpotent_power
342    }
343}
344
345impl<R: DivisibilityRingStore> Domain for AsLocalPIRBase<R> 
346    where R::Type: DivisibilityRing + Domain
347{}
348
349impl<R> FromModulusCreateableZnRing for AsLocalPIRBase<RingValue<R>> 
350    where R: DivisibilityRing + ZnRing + FromModulusCreateableZnRing
351{
352    fn from_modulus<F, E>(create_modulus: F) -> Result<Self, E>
353        where F:FnOnce(&Self::IntegerRingBase) -> Result<El<Self::IntegerRing>, E> 
354    {
355        <R as FromModulusCreateableZnRing>::from_modulus(create_modulus).map(|ring| AsLocalPIR::from_zn(RingValue::from(ring)).unwrap().into())
356    }
357}
358
359impl<R: DivisibilityRingStore> Field for AsLocalPIRBase<R> 
360    where R::Type: DivisibilityRing + Field
361{}
362
363impl<R> InterpolationBaseRing for AsLocalPIRBase<R>
364    where R: RingStore,
365        R::Type: InterpolationBaseRing
366{
367    type ExtendedRingBase<'a> = <R::Type as InterpolationBaseRing>::ExtendedRingBase<'a>
368        where Self: 'a;
369
370    type ExtendedRing<'a> = <R::Type as InterpolationBaseRing>::ExtendedRing<'a>
371        where Self: 'a;
372
373    fn in_base<'a, S>(&self, ext_ring: S, el: El<S>) -> Option<Self::Element>
374        where Self: 'a, S: RingStore<Type = Self::ExtendedRingBase<'a>>
375    {
376        self.get_delegate().in_base(ext_ring, el).map(|x| self.rev_delegate(x))
377    }
378
379    fn in_extension<'a, S>(&self, ext_ring: S, el: Self::Element) -> El<S>
380        where Self: 'a, S: RingStore<Type = Self::ExtendedRingBase<'a>>
381    {
382        self.get_delegate().in_extension(ext_ring, self.delegate(el))
383    }
384
385    fn interpolation_points<'a>(&'a self, count: usize) -> (Self::ExtendedRing<'a>, Vec<El<Self::ExtendedRing<'a>>>) {
386        self.get_delegate().interpolation_points(count)
387    }
388}
389
390impl<R1, R2> CanHomFrom<AsFieldBase<R1>> for AsLocalPIRBase<R2>
391    where R1: RingStore, R2: RingStore,
392        R2::Type: CanHomFrom<R1::Type>,
393        R1::Type: DivisibilityRing,
394        R2::Type: DivisibilityRing
395{
396    type Homomorphism = <R2::Type as CanHomFrom<R1::Type>>::Homomorphism;
397
398    fn has_canonical_hom(&self, from: &AsFieldBase<R1>) -> Option<Self::Homomorphism> {
399        self.get_delegate().has_canonical_hom(from.get_delegate())
400    }
401
402    fn map_in(&self, from: &AsFieldBase<R1>, el: <AsFieldBase<R1> as RingBase>::Element, hom: &Self::Homomorphism) -> Self::Element {
403        self.rev_delegate(self.get_delegate().map_in(from.get_delegate(), from.delegate(el), hom))
404    }
405}
406
407impl<R1, R2> CanIsoFromTo<AsFieldBase<R1>> for AsLocalPIRBase<R2>
408    where R1: RingStore, R2: RingStore,
409        R2::Type: CanIsoFromTo<R1::Type>,
410        R1::Type: DivisibilityRing,
411        R2::Type: DivisibilityRing
412{
413    type Isomorphism = <R2::Type as CanIsoFromTo<R1::Type>>::Isomorphism;
414
415    fn has_canonical_iso(&self, from: &AsFieldBase<R1>) -> Option<Self::Isomorphism> {
416        self.get_delegate().has_canonical_iso(from.get_delegate())
417    }
418
419    fn map_out(&self, from: &AsFieldBase<R1>, el: Self::Element, iso: &Self::Isomorphism) -> <AsFieldBase<R1> as RingBase>::Element {
420        from.rev_delegate(self.get_delegate().map_out(from.get_delegate(), self.delegate(el), iso))
421    }
422}
423
424///
425/// Implements the isomorphisms `S: CanHomFrom<AsFieldBase<RingStore<Type = R>>>` and 
426/// `AsFieldBase<RingStore<Type = S>>: CanHomFrom<R>`.
427/// 
428/// For details, see [`crate::impl_field_wrap_unwrap_homs!`]
429/// 
430#[macro_export]
431macro_rules! impl_localpir_wrap_unwrap_homs {
432    (<{$($gen_args:tt)*}> $self_type_from:ty, $self_type_to:ty where $($constraints:tt)*) => {
433        
434        impl<AsLocalPIRStore, $($gen_args)*> CanHomFrom<$self_type_from> for $crate::rings::local::AsLocalPIRBase<AsLocalPIRStore>
435            where AsLocalPIRStore: RingStore<Type = $self_type_to>, $($constraints)*
436        {
437            type Homomorphism = <$self_type_to as CanHomFrom<$self_type_from>>::Homomorphism;
438
439            fn has_canonical_hom(&self, from: &$self_type_from) -> Option<Self::Homomorphism> {
440                self.get_delegate().has_canonical_hom(from)
441            }
442
443            fn map_in(&self, from: &$self_type_from, el: <$self_type_from as $crate::ring::RingBase>::Element, hom: &Self::Homomorphism) -> <Self as $crate::ring::RingBase>::Element {
444                self.rev_delegate(self.get_delegate().map_in(from, el, hom))
445            }
446        }
447        
448        impl<AsLocalPIRStore, $($gen_args)*> CanHomFrom<$crate::rings::local::AsLocalPIRBase<AsLocalPIRStore>> for $self_type_to
449            where AsLocalPIRStore: RingStore<Type = $self_type_from>, $($constraints)*
450        {
451            type Homomorphism = <$self_type_to as CanHomFrom<$self_type_from>>::Homomorphism;
452
453            fn has_canonical_hom(&self, from: &$crate::rings::local::AsLocalPIRBase<AsLocalPIRStore>) -> Option<Self::Homomorphism> {
454                self.has_canonical_hom(from.get_delegate())
455            }
456
457            fn map_in(&self, from: &$crate::rings::local::AsLocalPIRBase<AsLocalPIRStore>, el: $crate::rings::local::LocalPIREl<AsLocalPIRStore>, hom: &Self::Homomorphism) -> <Self as $crate::ring::RingBase>::Element {
458                self.map_in(from.get_delegate(), from.delegate(el), hom)
459            }
460        }
461    };
462    ($self_type_from:ty, $self_type_to:ty) => {
463        impl_localpir_wrap_unwrap_homs!{ <{}> $self_type_from, $self_type_to where }
464    };
465}
466
467///
468/// Implements the isomorphisms `S: CanIsoFromTo<AsLocalPIRBase<RingStore<Type = R>>>` and `AsLocalPIRBase<RingStore<Type = S>>: CanIsoFromTo<R>`.
469/// 
470/// For details, see [`crate::impl_field_wrap_unwrap_isos!`]
471/// 
472#[macro_export]
473macro_rules! impl_localpir_wrap_unwrap_isos {
474    (<{$($gen_args:tt)*}> $self_type_from:ty, $self_type_to:ty where $($constraints:tt)*) => {
475        
476        impl<AsLocalPIRStore, $($gen_args)*> CanIsoFromTo<$self_type_from> for $crate::rings::local::AsLocalPIRBase<AsLocalPIRStore>
477            where AsLocalPIRStore: RingStore<Type = $self_type_to>, $($constraints)*
478        {
479            type Isomorphism = <$self_type_to as CanIsoFromTo<$self_type_from>>::Isomorphism;
480
481            fn has_canonical_iso(&self, from: &$self_type_from) -> Option<Self::Isomorphism> {
482                self.get_delegate().has_canonical_iso(from)
483            }
484
485            fn map_out(&self, from: &$self_type_from, el: <Self as RingBase>::Element, iso: &Self::Isomorphism) -> <$self_type_from as RingBase>::Element {
486                self.get_delegate().map_out(from, self.delegate(el), iso)
487            }
488        }
489        
490        impl<AsLocalPIRStore, $($gen_args)*> CanIsoFromTo<$crate::rings::local::AsLocalPIRBase<AsLocalPIRStore>> for $self_type_to
491            where AsLocalPIRStore: RingStore<Type = $self_type_from>, $($constraints)*
492        {
493            type Isomorphism = <$self_type_to as CanIsoFromTo<$self_type_from>>::Isomorphism;
494
495            fn has_canonical_iso(&self, from: &$crate::rings::local::AsLocalPIRBase<AsLocalPIRStore>) -> Option<Self::Isomorphism> {
496                self.has_canonical_iso(from.get_delegate())
497            }
498
499            fn map_out(&self, from: &$crate::rings::local::AsLocalPIRBase<AsLocalPIRStore>, el: <Self as RingBase>::Element, hom: &Self::Isomorphism) -> $crate::rings::local::LocalPIREl<AsLocalPIRStore> {
500                from.rev_delegate(self.map_out(from.get_delegate(), el, hom))
501            }
502        }
503    };
504    ($self_type_from:ty, $self_type_to:ty) => {
505        impl_localpir_wrap_unwrap_isos!{ <{}> $self_type_from, $self_type_to where }
506    };
507}
508
509#[cfg(test)]
510use crate::rings::zn::zn_big::Zn;
511#[cfg(test)]
512use crate::primitive_int::*;
513#[cfg(test)]
514use crate::rings::finite::FiniteRingStore;
515#[cfg(test)]
516use std::alloc::Global;
517#[cfg(test)]
518use std::time::Instant;
519#[cfg(test)]
520use crate::algorithms::linsolve::LinSolveRing;
521#[cfg(test)]
522use crate::matrix::{OwnedMatrix, TransposableSubmatrix, TransposableSubmatrixMut};
523#[cfg(test)]
524use crate::assert_matrix_eq;
525#[cfg(test)]
526use super::extension::galois_field::GaloisField;
527
528#[test]
529fn test_canonical_hom_axioms_static_int() {
530    let R = AsLocalPIR::from_zn(Zn::new(StaticRing::<i64>::RING, 8)).unwrap();
531    crate::ring::generic_tests::test_hom_axioms(StaticRing::<i64>::RING, &R, 0..8);
532}
533
534#[test]
535fn test_divisibility_axioms() {
536    let R = AsLocalPIR::from_zn(Zn::new(StaticRing::<i64>::RING, 8)).unwrap();
537    crate::divisibility::generic_tests::test_divisibility_axioms(&R, R.elements());
538}
539
540#[test]
541fn test_principal_ideal_ring_axioms() {
542    let R = AsLocalPIR::from_zn(Zn::new(StaticRing::<i64>::RING, 8)).unwrap();
543    crate::pid::generic_tests::test_principal_ideal_ring_axioms(&R, R.elements());
544    let R = AsLocalPIR::from_zn(Zn::new(StaticRing::<i64>::RING, 9)).unwrap();
545    crate::pid::generic_tests::test_principal_ideal_ring_axioms(&R, R.elements());
546    let R = AsLocalPIR::from_zn(Zn::new(StaticRing::<i64>::RING, 17)).unwrap();
547    crate::pid::generic_tests::test_principal_ideal_ring_axioms(&R, R.elements());
548}
549
550#[test]
551fn test_canonical_hom_axioms_wrap_unwrap() {
552    let R = AsLocalPIR::from_zn(Zn::new(StaticRing::<i64>::RING, 8)).unwrap();
553    crate::ring::generic_tests::test_hom_axioms(RingRef::new(R.get_ring().get_delegate()), &R, RingRef::new(R.get_ring().get_delegate()).elements());
554    crate::ring::generic_tests::test_iso_axioms(RingRef::new(R.get_ring().get_delegate()), &R, RingRef::new(R.get_ring().get_delegate()).elements());
555}
556
557#[test]
558fn test_checked_div_min() {
559    let ring = AsLocalPIR::from_zn(Zn::new(StaticRing::<i64>::RING, 27)).unwrap();
560    assert_el_eq!(&ring, ring.zero(), ring.checked_div_min(&ring.zero(), &ring.one()).unwrap());
561    assert_el_eq!(&ring, ring.int_hom().map(9), ring.checked_div_min(&ring.zero(), &ring.int_hom().map(3)).unwrap());
562    assert_el_eq!(&ring, ring.int_hom().map(3), ring.checked_div_min(&ring.zero(), &ring.int_hom().map(9)).unwrap());
563    assert_el_eq!(&ring, ring.one(), ring.checked_div_min(&ring.zero(), &ring.zero()).unwrap());
564}
565
566#[test]
567#[ignore]
568fn test_solve_large_galois_ring() {
569    let ring: AsLocalPIR<_> = GaloisField::new(17, 2048).get_ring().galois_ring(5);
570    let mut matrix: OwnedMatrix<_> = OwnedMatrix::zero(2, 2, &ring);
571    let mut rng = oorandom::Rand64::new(1);
572
573    *matrix.at_mut(0, 0) = ring.random_element(|| rng.rand_u64());
574    *matrix.at_mut(0, 1) = ring.random_element(|| rng.rand_u64());
575    *matrix.at_mut(1, 1) = ring.random_element(|| rng.rand_u64());
576    assert!(ring.is_unit(&ring.sub_ref(matrix.at(0, 1), matrix.at(1, 1))), "matrix generation failed, pick another seed");
577    *matrix.at_mut(1, 0) = ring.clone_el(matrix.at(0, 0));
578
579    let mut rhs: OwnedMatrix<_> = OwnedMatrix::zero(2, 1, &ring);
580    *rhs.at_mut(0, 0) = ring.random_element(|| rng.rand_u64());
581    *rhs.at_mut(0, 1) = ring.random_element(|| rng.rand_u64());
582
583    let rhs = rhs;
584    let matrix = matrix;
585    let mut result: OwnedMatrix<_> = OwnedMatrix::zero(2, 1, &ring);
586
587    let start = Instant::now();
588    ring.get_ring().solve_right(matrix.clone_matrix(&ring).data_mut(), rhs.clone_matrix(&ring).data_mut(), result.data_mut(), Global).assert_solved();
589    let end = Instant::now();
590    println!("Solved over GR(17, 5, 2048) in {} ms", (end - start).as_millis());
591
592    let mut product: OwnedMatrix<_> = OwnedMatrix::zero(2, 1, &ring);
593    STANDARD_MATMUL.matmul(TransposableSubmatrix::from(matrix.data()), TransposableSubmatrix::from(result.data()), TransposableSubmatrixMut::from(product.data_mut()), &ring);
594
595    assert_matrix_eq!(ring, rhs, product);
596}