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#[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#[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
211impl<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 return self.checked_left_div(lhs, rhs);
248 }
249 } else {
250 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#[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#[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}