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