1use crate::algorithms::convolution::KaratsubaHint;
2use crate::algorithms::matmul::{ComputeInnerProduct, StrassenHint};
3use crate::compute_locally::{InterpolationBaseRing, InterpolationBaseRingStore};
4use crate::delegate::*;
5use crate::divisibility::*;
6use crate::local::PrincipalLocalRing;
7use crate::pid::{EuclideanRing, PrincipalIdealRing};
8use crate::field::*;
9use crate::integer::IntegerRing;
10use crate::ring::*;
11use crate::homomorphism::*;
12use crate::rings::zn::FromModulusCreateableZnRing;
13use crate::rings::zn::*;
14use crate::specialization::FiniteRingSpecializable;
15use super::local::AsLocalPIRBase;
16use crate::primitive_int::*;
17
18pub struct AsFieldBase<R: RingStore>
70 where R::Type: DivisibilityRing
71{
72 base: R,
73 zero: FieldEl<R>
74}
75
76impl<R> PerfectField for AsFieldBase<R>
77 where R: RingStore,
78 R::Type: DivisibilityRing
79{}
80
81impl<R> Clone for AsFieldBase<R>
82 where R: RingStore + Clone,
83 R::Type: DivisibilityRing
84{
85 fn clone(&self) -> Self {
86 Self { zero: FieldEl(self.base.zero()), base: self.base.clone() }
87 }
88}
89
90impl<R> Copy for AsFieldBase<R>
91 where R: RingStore + Copy,
92 R::Type: DivisibilityRing,
93 El<R>: Copy
94{}
95
96impl<R> PartialEq for AsFieldBase<R>
97 where R: RingStore,
98 R::Type: DivisibilityRing
99{
100 fn eq(&self, other: &Self) -> bool {
101 self.base.get_ring() == other.base.get_ring()
102 }
103}
104
105#[allow(type_alias_bounds)]
109pub type AsField<R: RingStore> = RingValue<AsFieldBase<R>>;
110
111pub struct FieldEl<R: RingStore>(El<R>)
112 where R::Type: DivisibilityRing;
113
114impl<R: RingStore> Clone for FieldEl<R>
115 where El<R>: Clone,
116 R::Type: DivisibilityRing
117{
118 fn clone(&self) -> Self {
119 FieldEl(self.0.clone())
120 }
121}
122
123impl<R: RingStore> Copy for FieldEl<R>
124 where El<R>: Copy,
125 R::Type: DivisibilityRing
126{}
127
128impl<R: RingStore> AsFieldBase<R>
129 where R::Type: DivisibilityRing
130{
131 pub fn promise_is_perfect_field(base: R) -> Self {
139 Self { zero: FieldEl(base.zero()), base }
140 }
141
142 #[stability::unstable(feature = "enable")]
156 pub fn promise_is_field(base: R) -> Result<Self, R>
157 where R::Type: FiniteRingSpecializable
158 {
159 let characteristic = base.characteristic(&StaticRing::<i64>::RING);
160 if characteristic.is_some() && characteristic.unwrap() == 0 {
161 return Ok(Self::promise_is_perfect_field(base));
162 } else if <R::Type as FiniteRingSpecializable>::is_finite_ring() {
163 return Ok(Self::promise_is_perfect_field(base));
164 } else {
165 return Err(base);
166 }
167 }
168
169 pub fn unwrap_element(&self, el: <Self as RingBase>::Element) -> El<R> {
170 el.0
171 }
172
173 pub fn unwrap_self(self) -> R {
177 self.base
178 }
179}
180
181impl<R: RingStore> AsFieldBase<R>
182 where R::Type: PerfectField
183{
184 pub fn from_field(base: R) -> Self {
189 Self::promise_is_perfect_field(base)
190 }
191}
192
193impl<R: RingStore> DelegateRing for AsFieldBase<R>
194 where R::Type: DivisibilityRing
195{
196 type Element = FieldEl<R>;
197 type Base = R::Type;
198
199 fn get_delegate(&self) -> &Self::Base {
200 self.base.get_ring()
201 }
202
203 fn delegate(&self, el: Self::Element) -> <Self::Base as RingBase>::Element {
204 el.0
205 }
206
207 fn delegate_mut<'a>(&self, el: &'a mut Self::Element) -> &'a mut <Self::Base as RingBase>::Element {
208 &mut el.0
209 }
210
211 fn delegate_ref<'a>(&self, el: &'a Self::Element) -> &'a <Self::Base as RingBase>::Element {
212 &el.0
213 }
214
215 fn rev_delegate(&self, el: <Self::Base as RingBase>::Element) -> Self::Element {
216 FieldEl(el)
217 }
218}
219
220impl<R: RingStore> DelegateRingImplFiniteRing for AsFieldBase<R>
221 where R::Type: DivisibilityRing
222{}
223
224impl<R: RingStore, S: RingStore> CanHomFrom<AsFieldBase<S>> for AsFieldBase<R>
225 where R::Type: DivisibilityRing + CanHomFrom<S::Type>,
226 S::Type: DivisibilityRing
227{
228 type Homomorphism = <R::Type as CanHomFrom<S::Type>>::Homomorphism;
229
230 fn has_canonical_hom(&self, from: &AsFieldBase<S>) -> Option<Self::Homomorphism> {
231 <R::Type as CanHomFrom<S::Type>>::has_canonical_hom(self.get_delegate(), from.get_delegate())
232 }
233
234 fn map_in(&self, from: &AsFieldBase<S>, el: FieldEl<S>, hom: &Self::Homomorphism) -> Self::Element {
235 FieldEl(<R::Type as CanHomFrom<S::Type>>::map_in(self.get_delegate(), from.get_delegate(), el.0, hom))
236 }
237}
238
239impl<R: RingStore, S: RingStore> CanIsoFromTo<AsFieldBase<S>> for AsFieldBase<R>
240 where R::Type: DivisibilityRing + CanIsoFromTo<S::Type>,
241 S::Type: DivisibilityRing
242{
243 type Isomorphism = <R::Type as CanIsoFromTo<S::Type>>::Isomorphism;
244
245 fn has_canonical_iso(&self, from: &AsFieldBase<S>) -> Option<Self::Isomorphism> {
246 <R::Type as CanIsoFromTo<S::Type>>::has_canonical_iso(self.get_delegate(), from.get_delegate())
247 }
248
249 fn map_out(&self, from: &AsFieldBase<S>, el: Self::Element, iso: &Self::Isomorphism) -> FieldEl<S> {
250 FieldEl(<R::Type as CanIsoFromTo<S::Type>>::map_out(self.get_delegate(), from.get_delegate(), el.0, iso))
251 }
252}
253
254impl<R: RingStore, S: IntegerRing + ?Sized> CanHomFrom<S> for AsFieldBase<R>
258 where R::Type: DivisibilityRing + CanHomFrom<S>
259{
260 type Homomorphism = <R::Type as CanHomFrom<S>>::Homomorphism;
261
262 fn has_canonical_hom(&self, from: &S) -> Option<Self::Homomorphism> {
263 self.get_delegate().has_canonical_hom(from)
264 }
265
266 fn map_in(&self, from: &S, el: S::Element, hom: &Self::Homomorphism) -> Self::Element {
267 FieldEl(<R::Type as CanHomFrom<S>>::map_in(self.get_delegate(), from, el, hom))
268 }
269}
270
271impl<R1, R2> CanHomFrom<AsLocalPIRBase<R1>> for AsFieldBase<R2>
272 where R1: RingStore, R2: RingStore,
273 R2::Type: CanHomFrom<R1::Type>,
274 R1::Type: DivisibilityRing,
275 R2::Type: DivisibilityRing
276{
277 type Homomorphism = <R2::Type as CanHomFrom<R1::Type>>::Homomorphism;
278
279 fn has_canonical_hom(&self, from: &AsLocalPIRBase<R1>) -> Option<Self::Homomorphism> {
280 self.get_delegate().has_canonical_hom(from.get_delegate())
281 }
282
283 fn map_in(&self, from: &AsLocalPIRBase<R1>, el: <AsLocalPIRBase<R1> as RingBase>::Element, hom: &Self::Homomorphism) -> Self::Element {
284 self.rev_delegate(self.get_delegate().map_in(from.get_delegate(), from.delegate(el), hom))
285 }
286}
287
288impl<R1, R2> CanIsoFromTo<AsLocalPIRBase<R1>> for AsFieldBase<R2>
289 where R1: RingStore, R2: RingStore,
290 R2::Type: CanIsoFromTo<R1::Type>,
291 R1::Type: DivisibilityRing,
292 R2::Type: DivisibilityRing
293{
294 type Isomorphism = <R2::Type as CanIsoFromTo<R1::Type>>::Isomorphism;
295
296 fn has_canonical_iso(&self, from: &AsLocalPIRBase<R1>) -> Option<Self::Isomorphism> {
297 self.get_delegate().has_canonical_iso(from.get_delegate())
298 }
299
300 fn map_out(&self, from: &AsLocalPIRBase<R1>, el: Self::Element, iso: &Self::Isomorphism) -> <AsLocalPIRBase<R1> as RingBase>::Element {
301 from.rev_delegate(self.get_delegate().map_out(from.get_delegate(), self.delegate(el), iso))
302 }
303}
304
305impl<R: RingStore> PrincipalIdealRing for AsFieldBase<R>
306 where R::Type: DivisibilityRing
307{
308 fn checked_div_min(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
309 if self.is_zero(lhs) && self.is_zero(rhs) {
310 Some(self.one())
311 } else {
312 self.checked_left_div(lhs, rhs)
313 }
314 }
315
316 fn extended_ideal_gen(&self, lhs: &Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element, Self::Element) {
317 if self.is_zero(lhs) {
318 (self.zero(), self.one(), self.clone_el(rhs))
319 } else {
320 (self.one(), self.zero(), self.clone_el(lhs))
321 }
322 }
323}
324
325impl<R: RingStore> PrincipalLocalRing for AsFieldBase<R>
326 where R::Type: DivisibilityRing
327{
328 fn max_ideal_gen(&self) -> &Self::Element {
329 &self.zero
330 }
331
332 fn nilpotent_power(&self) -> Option<usize> {
333 Some(1)
334 }
335
336 fn valuation(&self, x: &Self::Element) -> Option<usize> {
337 if self.is_zero(x) {
338 return None;
339 } else {
340 return Some(0);
341 }
342 }
343}
344
345impl<R> InterpolationBaseRing for AsFieldBase<R>
346 where R: InterpolationBaseRingStore,
347 R::Type: InterpolationBaseRing
348{
349 type ExtendedRingBase<'a> = <R::Type as InterpolationBaseRing>::ExtendedRingBase<'a>
350 where Self: 'a;
351
352 type ExtendedRing<'a> = <R::Type as InterpolationBaseRing>::ExtendedRing<'a>
353 where Self: 'a;
354
355 fn in_base<'a, S>(&self, ext_ring: S, el: El<S>) -> Option<Self::Element>
356 where Self: 'a, S: RingStore<Type = Self::ExtendedRingBase<'a>>
357 {
358 self.get_delegate().in_base(ext_ring, el).map(|x| self.rev_delegate(x))
359 }
360
361 fn in_extension<'a, S>(&self, ext_ring: S, el: Self::Element) -> El<S>
362 where Self: 'a, S: RingStore<Type = Self::ExtendedRingBase<'a>>
363 {
364 self.get_delegate().in_extension(ext_ring, self.delegate(el))
365 }
366
367 fn interpolation_points<'a>(&'a self, count: usize) -> (Self::ExtendedRing<'a>, Vec<El<Self::ExtendedRing<'a>>>) {
368 self.get_delegate().interpolation_points(count)
369 }
370}
371
372impl<R: RingStore> EuclideanRing for AsFieldBase<R>
373 where R::Type: DivisibilityRing
374{
375 fn euclidean_div_rem(&self, lhs: Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element) {
376 assert!(!self.is_zero(rhs));
377 (self.checked_left_div(&lhs, rhs).unwrap(), self.zero())
378 }
379
380 fn euclidean_deg(&self, val: &Self::Element) -> Option<usize> {
381 if self.is_zero(val) {
382 Some(0)
383 } else {
384 Some(1)
385 }
386 }
387
388 fn euclidean_rem(&self, _: Self::Element, rhs: &Self::Element) -> Self::Element {
389 assert!(!self.is_zero(rhs));
390 self.zero()
391 }
392}
393
394impl<R: RingStore> Domain for AsFieldBase<R>
395 where R::Type: DivisibilityRing
396{}
397
398impl<R: RingStore> Field for AsFieldBase<R>
399 where R::Type: DivisibilityRing
400{
401 fn div(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
402 FieldEl(self.get_delegate().checked_left_div(&lhs.0, &rhs.0).unwrap())
403 }
404}
405
406impl<R: RingStore> KaratsubaHint for AsFieldBase<R>
407 where R::Type: DivisibilityRing
408{
409 fn karatsuba_threshold(&self) -> usize {
410 self.get_delegate().karatsuba_threshold()
411 }
412}
413
414impl<R: RingStore> ComputeInnerProduct for AsFieldBase<R>
415 where R::Type: DivisibilityRing
416{
417 fn inner_product<I: Iterator<Item = (Self::Element, Self::Element)>>(&self, els: I) -> Self::Element {
418 self.rev_delegate(self.get_delegate().inner_product(els.map(|(a, b)| (self.delegate(a), self.delegate(b)))))
419 }
420
421 fn inner_product_ref<'a, I: Iterator<Item = (&'a Self::Element, &'a Self::Element)>>(&self, els: I) -> Self::Element
422 where Self::Element: 'a,
423 Self: 'a
424 {
425 self.rev_delegate(self.get_delegate().inner_product_ref(els.map(|(a, b)| (self.delegate_ref(a), self.delegate_ref(b)))))
426 }
427
428 fn inner_product_ref_fst<'a, I: Iterator<Item = (&'a Self::Element, Self::Element)>>(&self, els: I) -> Self::Element
429 where Self::Element: 'a,
430 Self: 'a
431 {
432 self.rev_delegate(self.get_delegate().inner_product_ref_fst(els.map(|(a, b)| (self.delegate_ref(a), self.delegate(b)))))
433 }
434}
435
436impl<R: RingStore> StrassenHint for AsFieldBase<R>
437 where R::Type: DivisibilityRing
438{
439 fn strassen_threshold(&self) -> usize {
440 self.get_delegate().strassen_threshold()
441 }
442}
443
444impl<R> FromModulusCreateableZnRing for AsFieldBase<RingValue<R>>
445 where R: DivisibilityRing + ZnRing + FromModulusCreateableZnRing
446{
447 fn create<F, E>(create_modulus: F) -> Result<Self, E>
448 where F:FnOnce(&Self::IntegerRingBase) -> Result<El<Self::IntegerRing>, E>
449 {
450 <R as FromModulusCreateableZnRing>::create(create_modulus).map(|ring| RingValue::from(ring).as_field().ok().unwrap().into())
451 }
452}
453
454#[macro_export]
514macro_rules! impl_field_wrap_unwrap_homs {
515 (<{$($gen_args:tt)*}> $self_type_from:ty, $self_type_to:ty where $($constraints:tt)*) => {
516
517 impl<AsFieldRingStore, $($gen_args)*> CanHomFrom<$self_type_from> for $crate::rings::field::AsFieldBase<AsFieldRingStore>
518 where AsFieldRingStore: RingStore<Type = $self_type_to>, $($constraints)*
519 {
520 type Homomorphism = <$self_type_to as CanHomFrom<$self_type_from>>::Homomorphism;
521
522 fn has_canonical_hom(&self, from: &$self_type_from) -> Option<Self::Homomorphism> {
523 self.get_delegate().has_canonical_hom(from)
524 }
525
526 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 {
527 self.rev_delegate(self.get_delegate().map_in(from, el, hom))
528 }
529 }
530
531 impl<AsFieldRingStore, $($gen_args)*> CanHomFrom<$crate::rings::field::AsFieldBase<AsFieldRingStore>> for $self_type_to
532 where AsFieldRingStore: RingStore<Type = $self_type_from>, $($constraints)*
533 {
534 type Homomorphism = <$self_type_to as CanHomFrom<$self_type_from>>::Homomorphism;
535
536 fn has_canonical_hom(&self, from: &$crate::rings::field::AsFieldBase<AsFieldRingStore>) -> Option<Self::Homomorphism> {
537 self.has_canonical_hom(from.get_delegate())
538 }
539
540 fn map_in(&self, from: &$crate::rings::field::AsFieldBase<AsFieldRingStore>, el: $crate::rings::field::FieldEl<AsFieldRingStore>, hom: &Self::Homomorphism) -> <Self as $crate::ring::RingBase>::Element {
541 self.map_in(from.get_delegate(), from.delegate(el), hom)
542 }
543 }
544 };
545 ($self_type_from:ty, $self_type_to:ty) => {
546 impl_field_wrap_unwrap_homs!{ <{}> $self_type_from, $self_type_to where }
547 };
548}
549
550#[macro_export]
557macro_rules! impl_field_wrap_unwrap_isos {
558 (<{$($gen_args:tt)*}> $self_type_from:ty, $self_type_to:ty where $($constraints:tt)*) => {
559
560 impl<AsFieldRingStore, $($gen_args)*> CanIsoFromTo<$self_type_from> for $crate::rings::field::AsFieldBase<AsFieldRingStore>
561 where AsFieldRingStore: RingStore<Type = $self_type_to>, $($constraints)*
562 {
563 type Isomorphism = <$self_type_to as CanIsoFromTo<$self_type_from>>::Isomorphism;
564
565 fn has_canonical_iso(&self, from: &$self_type_from) -> Option<Self::Isomorphism> {
566 self.get_delegate().has_canonical_iso(from)
567 }
568
569 fn map_out(&self, from: &$self_type_from, el: <Self as RingBase>::Element, iso: &Self::Isomorphism) -> <$self_type_from as RingBase>::Element {
570 self.get_delegate().map_out(from, self.delegate(el), iso)
571 }
572 }
573
574 impl<AsFieldRingStore, $($gen_args)*> CanIsoFromTo<$crate::rings::field::AsFieldBase<AsFieldRingStore>> for $self_type_to
575 where AsFieldRingStore: RingStore<Type = $self_type_from>, $($constraints)*
576 {
577 type Isomorphism = <$self_type_to as CanIsoFromTo<$self_type_from>>::Isomorphism;
578
579 fn has_canonical_iso(&self, from: &$crate::rings::field::AsFieldBase<AsFieldRingStore>) -> Option<Self::Isomorphism> {
580 self.has_canonical_iso(from.get_delegate())
581 }
582
583 fn map_out(&self, from: &$crate::rings::field::AsFieldBase<AsFieldRingStore>, el: <Self as RingBase>::Element, hom: &Self::Isomorphism) -> $crate::rings::field::FieldEl<AsFieldRingStore> {
584 from.rev_delegate(self.map_out(from.get_delegate(), el, hom))
585 }
586 }
587 };
588 ($self_type_from:ty, $self_type_to:ty) => {
589 impl_field_wrap_unwrap_isos!{ <{}> $self_type_from, $self_type_to where }
590 };
591}
592
593#[cfg(test)]
594use crate::rings::zn::zn_big::Zn;
595#[cfg(test)]
596use crate::rings::finite::FiniteRingStore;
597
598#[test]
599fn test_canonical_hom_axioms_static_int() {
600 let R = Zn::new(StaticRing::<i64>::RING, 17).as_field().ok().unwrap();
601 crate::ring::generic_tests::test_hom_axioms(StaticRing::<i64>::RING, &R, 0..17);
602}
603
604#[test]
605fn test_divisibility_axioms() {
606 let R = Zn::new(StaticRing::<i64>::RING, 17).as_field().ok().unwrap();
607 crate::divisibility::generic_tests::test_divisibility_axioms(&R, R.elements());
608}
609
610#[test]
611fn test_canonical_hom_axioms_wrap_unwrap() {
612 let R = Zn::new(StaticRing::<i64>::RING, 17).as_field().ok().unwrap();
613 crate::ring::generic_tests::test_hom_axioms(RingRef::new(R.get_ring().get_delegate()), &R, RingRef::new(R.get_ring().get_delegate()).elements());
614 crate::ring::generic_tests::test_iso_axioms(RingRef::new(R.get_ring().get_delegate()), &R, RingRef::new(R.get_ring().get_delegate()).elements());
615}
616
617#[test]
618fn test_principal_ideal_ring_axioms() {
619 let R = Zn::new(StaticRing::<i64>::RING, 17).as_field().ok().unwrap();
620 crate::pid::generic_tests::test_principal_ideal_ring_axioms(&R, R.elements());
621 crate::pid::generic_tests::test_euclidean_ring_axioms(&R, R.elements());
622}
623
624#[test]
625fn test_field_axioms() {
626 let R = Zn::new(StaticRing::<i64>::RING, 17).as_field().ok().unwrap();
627 crate::field::generic_tests::test_field_axioms(&R, R.elements());
628}