1use std::fmt::Debug;
2use std::marker::PhantomData;
3
4use feanor_serde::newtype_struct::{DeserializeSeedNewtypeStruct, SerializableNewtypeStruct};
5use serde::de::DeserializeSeed;
6use serde::{Deserialize, Deserializer, Serialize, Serializer};
7
8use super::local::AsLocalPIRBase;
9use crate::algorithms::convolution::KaratsubaHint;
10use crate::algorithms::matmul::{ComputeInnerProduct, StrassenHint};
11use crate::delegate::*;
12use crate::divisibility::*;
13use crate::field::*;
14use crate::homomorphism::*;
15use crate::integer::IntegerRing;
16use crate::local::PrincipalLocalRing;
17use crate::pid::{EuclideanRing, PrincipalIdealRing};
18use crate::primitive_int::*;
19use crate::reduce_lift::poly_eval::{InterpolationBaseRing, InterpolationBaseRingStore};
20use crate::ring::*;
21use crate::rings::zn::{FromModulusCreateableZnRing, *};
22use crate::specialization::FiniteRingSpecializable;
23
24pub struct AsFieldBase<R: RingStore>
76where
77 R::Type: DivisibilityRing,
78{
79 base: R,
80 zero: FieldEl<R>,
81}
82
83impl<R> PerfectField for AsFieldBase<R>
84where
85 R: RingStore,
86 R::Type: DivisibilityRing,
87{
88}
89
90impl<R> Clone for AsFieldBase<R>
91where
92 R: RingStore + Clone,
93 R::Type: DivisibilityRing,
94{
95 fn clone(&self) -> Self {
96 Self {
97 zero: FieldEl(self.base.zero()),
98 base: self.base.clone(),
99 }
100 }
101}
102
103impl<R> Copy for AsFieldBase<R>
104where
105 R: RingStore + Copy,
106 R::Type: DivisibilityRing,
107 El<R>: Copy,
108{
109}
110
111impl<R> Debug for AsFieldBase<R>
112where
113 R: RingStore,
114 R::Type: DivisibilityRing + Debug,
115{
116 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117 f.debug_tuple("AsField").field(&self.base.get_ring()).finish()
118 }
119}
120
121impl<R> PartialEq for AsFieldBase<R>
122where
123 R: RingStore,
124 R::Type: DivisibilityRing,
125{
126 fn eq(&self, other: &Self) -> bool { self.base.get_ring() == other.base.get_ring() }
127}
128
129#[allow(type_alias_bounds)]
131pub type AsField<R: RingStore> = RingValue<AsFieldBase<R>>;
132
133pub struct FieldEl<R: RingStore>(El<R>)
135where
136 R::Type: DivisibilityRing;
137
138impl<R: RingStore> Debug for FieldEl<R>
139where
140 El<R>: Debug,
141 R::Type: DivisibilityRing,
142{
143 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144 f.debug_tuple("FieldEl").field(&self.0).finish()
145 }
146}
147
148impl<R: RingStore> Clone for FieldEl<R>
149where
150 El<R>: Clone,
151 R::Type: DivisibilityRing,
152{
153 fn clone(&self) -> Self { FieldEl(self.0.clone()) }
154}
155
156impl<R: RingStore> Copy for FieldEl<R>
157where
158 El<R>: Copy,
159 R::Type: DivisibilityRing,
160{
161}
162
163impl<R: RingStore> AsFieldBase<R>
164where
165 R::Type: DivisibilityRing,
166{
167 pub fn promise_is_perfect_field(base: R) -> Self {
173 Self {
174 zero: FieldEl(base.zero()),
175 base,
176 }
177 }
178
179 #[stability::unstable(feature = "enable")]
191 pub fn promise_is_field(base: R) -> Result<Self, R>
192 where
193 R::Type: FiniteRingSpecializable,
194 {
195 let characteristic = base.characteristic(&StaticRing::<i64>::RING);
196 if characteristic.is_some() && characteristic.unwrap() == 0 {
197 return Ok(Self::promise_is_perfect_field(base));
198 } else if <R::Type as FiniteRingSpecializable>::is_finite_ring() {
199 return Ok(Self::promise_is_perfect_field(base));
200 } else {
201 return Err(base);
202 }
203 }
204
205 pub fn unwrap_element(&self, el: <Self as RingBase>::Element) -> El<R> { el.0 }
206
207 pub fn unwrap_self(self) -> R { self.base }
209}
210
211impl<R: RingStore> AsFieldBase<R>
212where
213 R::Type: PerfectField,
214{
215 pub fn from_field(base: R) -> Self { Self::promise_is_perfect_field(base) }
218}
219
220impl<R: RingStore> DelegateRing for AsFieldBase<R>
221where
222 R::Type: DivisibilityRing,
223{
224 type Element = FieldEl<R>;
225 type Base = R::Type;
226
227 fn get_delegate(&self) -> &Self::Base { self.base.get_ring() }
228
229 fn delegate(&self, el: Self::Element) -> <Self::Base as RingBase>::Element { el.0 }
230
231 fn delegate_mut<'a>(&self, el: &'a mut Self::Element) -> &'a mut <Self::Base as RingBase>::Element { &mut el.0 }
232
233 fn delegate_ref<'a>(&self, el: &'a Self::Element) -> &'a <Self::Base as RingBase>::Element { &el.0 }
234
235 fn rev_delegate(&self, el: <Self::Base as RingBase>::Element) -> Self::Element { FieldEl(el) }
236}
237
238impl<R: RingStore> DelegateRingImplFiniteRing for AsFieldBase<R> where R::Type: DivisibilityRing {}
239
240impl<R: RingStore, S: RingStore> CanHomFrom<AsFieldBase<S>> for AsFieldBase<R>
241where
242 R::Type: DivisibilityRing + CanHomFrom<S::Type>,
243 S::Type: DivisibilityRing,
244{
245 type Homomorphism = <R::Type as CanHomFrom<S::Type>>::Homomorphism;
246
247 fn has_canonical_hom(&self, from: &AsFieldBase<S>) -> Option<Self::Homomorphism> {
248 <R::Type as CanHomFrom<S::Type>>::has_canonical_hom(self.get_delegate(), from.get_delegate())
249 }
250
251 fn map_in(&self, from: &AsFieldBase<S>, el: FieldEl<S>, hom: &Self::Homomorphism) -> Self::Element {
252 FieldEl(<R::Type as CanHomFrom<S::Type>>::map_in(
253 self.get_delegate(),
254 from.get_delegate(),
255 el.0,
256 hom,
257 ))
258 }
259}
260
261impl<R: RingStore, S: RingStore> CanIsoFromTo<AsFieldBase<S>> for AsFieldBase<R>
262where
263 R::Type: DivisibilityRing + CanIsoFromTo<S::Type>,
264 S::Type: DivisibilityRing,
265{
266 type Isomorphism = <R::Type as CanIsoFromTo<S::Type>>::Isomorphism;
267
268 fn has_canonical_iso(&self, from: &AsFieldBase<S>) -> Option<Self::Isomorphism> {
269 <R::Type as CanIsoFromTo<S::Type>>::has_canonical_iso(self.get_delegate(), from.get_delegate())
270 }
271
272 fn map_out(&self, from: &AsFieldBase<S>, el: Self::Element, iso: &Self::Isomorphism) -> FieldEl<S> {
273 FieldEl(<R::Type as CanIsoFromTo<S::Type>>::map_out(
274 self.get_delegate(),
275 from.get_delegate(),
276 el.0,
277 iso,
278 ))
279 }
280}
281
282impl<R: RingStore, S: IntegerRing + ?Sized> CanHomFrom<S> for AsFieldBase<R>
284where
285 R::Type: DivisibilityRing + CanHomFrom<S>,
286{
287 type Homomorphism = <R::Type as CanHomFrom<S>>::Homomorphism;
288
289 fn has_canonical_hom(&self, from: &S) -> Option<Self::Homomorphism> { self.get_delegate().has_canonical_hom(from) }
290
291 fn map_in(&self, from: &S, el: S::Element, hom: &Self::Homomorphism) -> Self::Element {
292 FieldEl(<R::Type as CanHomFrom<S>>::map_in(self.get_delegate(), from, el, hom))
293 }
294}
295
296impl<R1, R2> CanHomFrom<AsLocalPIRBase<R1>> for AsFieldBase<R2>
297where
298 R1: RingStore,
299 R2: RingStore,
300 R2::Type: CanHomFrom<R1::Type>,
301 R1::Type: DivisibilityRing,
302 R2::Type: DivisibilityRing,
303{
304 type Homomorphism = <R2::Type as CanHomFrom<R1::Type>>::Homomorphism;
305
306 fn has_canonical_hom(&self, from: &AsLocalPIRBase<R1>) -> Option<Self::Homomorphism> {
307 self.get_delegate().has_canonical_hom(from.get_delegate())
308 }
309
310 fn map_in(
311 &self,
312 from: &AsLocalPIRBase<R1>,
313 el: <AsLocalPIRBase<R1> as RingBase>::Element,
314 hom: &Self::Homomorphism,
315 ) -> Self::Element {
316 self.rev_delegate(self.get_delegate().map_in(from.get_delegate(), from.delegate(el), hom))
317 }
318}
319
320impl<R1, R2> CanIsoFromTo<AsLocalPIRBase<R1>> for AsFieldBase<R2>
321where
322 R1: RingStore,
323 R2: RingStore,
324 R2::Type: CanIsoFromTo<R1::Type>,
325 R1::Type: DivisibilityRing,
326 R2::Type: DivisibilityRing,
327{
328 type Isomorphism = <R2::Type as CanIsoFromTo<R1::Type>>::Isomorphism;
329
330 fn has_canonical_iso(&self, from: &AsLocalPIRBase<R1>) -> Option<Self::Isomorphism> {
331 self.get_delegate().has_canonical_iso(from.get_delegate())
332 }
333
334 fn map_out(
335 &self,
336 from: &AsLocalPIRBase<R1>,
337 el: Self::Element,
338 iso: &Self::Isomorphism,
339 ) -> <AsLocalPIRBase<R1> as RingBase>::Element {
340 from.rev_delegate(self.get_delegate().map_out(from.get_delegate(), self.delegate(el), iso))
341 }
342}
343
344impl<R: RingStore> PrincipalIdealRing for AsFieldBase<R>
345where
346 R::Type: DivisibilityRing,
347{
348 fn checked_div_min(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
349 if self.is_zero(lhs) && self.is_zero(rhs) {
350 Some(self.one())
351 } else {
352 self.checked_left_div(lhs, rhs)
353 }
354 }
355
356 fn extended_ideal_gen(
357 &self,
358 lhs: &Self::Element,
359 rhs: &Self::Element,
360 ) -> (Self::Element, Self::Element, Self::Element) {
361 if self.is_zero(lhs) {
362 (self.zero(), self.one(), self.clone_el(rhs))
363 } else {
364 (self.one(), self.zero(), self.clone_el(lhs))
365 }
366 }
367}
368
369impl<R: RingStore> PrincipalLocalRing for AsFieldBase<R>
370where
371 R::Type: DivisibilityRing,
372{
373 fn max_ideal_gen(&self) -> &Self::Element { &self.zero }
374
375 fn nilpotent_power(&self) -> Option<usize> { Some(1) }
376
377 fn valuation(&self, x: &Self::Element) -> Option<usize> {
378 if self.is_zero(x) {
379 return None;
380 } else {
381 return Some(0);
382 }
383 }
384}
385
386impl<R> InterpolationBaseRing for AsFieldBase<R>
387where
388 R: InterpolationBaseRingStore,
389 R::Type: InterpolationBaseRing,
390{
391 type ExtendedRingBase<'a>
392 = <R::Type as InterpolationBaseRing>::ExtendedRingBase<'a>
393 where
394 Self: 'a;
395
396 type ExtendedRing<'a>
397 = <R::Type as InterpolationBaseRing>::ExtendedRing<'a>
398 where
399 Self: 'a;
400
401 fn in_base<'a, S>(&self, ext_ring: S, el: El<S>) -> Option<Self::Element>
402 where
403 Self: 'a,
404 S: RingStore<Type = Self::ExtendedRingBase<'a>>,
405 {
406 self.get_delegate().in_base(ext_ring, el).map(|x| self.rev_delegate(x))
407 }
408
409 fn in_extension<'a, S>(&self, ext_ring: S, el: Self::Element) -> El<S>
410 where
411 Self: 'a,
412 S: RingStore<Type = Self::ExtendedRingBase<'a>>,
413 {
414 self.get_delegate().in_extension(ext_ring, self.delegate(el))
415 }
416
417 fn interpolation_points<'a>(&'a self, count: usize) -> (Self::ExtendedRing<'a>, Vec<El<Self::ExtendedRing<'a>>>) {
418 self.get_delegate().interpolation_points(count)
419 }
420}
421
422impl<R: RingStore> EuclideanRing for AsFieldBase<R>
423where
424 R::Type: DivisibilityRing,
425{
426 fn euclidean_div_rem(&self, lhs: Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element) {
427 assert!(!self.is_zero(rhs));
428 (self.checked_left_div(&lhs, rhs).unwrap(), self.zero())
429 }
430
431 fn euclidean_deg(&self, val: &Self::Element) -> Option<usize> { if self.is_zero(val) { Some(0) } else { Some(1) } }
432
433 fn euclidean_rem(&self, _: Self::Element, rhs: &Self::Element) -> Self::Element {
434 assert!(!self.is_zero(rhs));
435 self.zero()
436 }
437}
438
439impl<R: RingStore> Domain for AsFieldBase<R> where R::Type: DivisibilityRing {}
440
441impl<R: RingStore> Field for AsFieldBase<R>
442where
443 R::Type: DivisibilityRing,
444{
445 fn div(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
446 FieldEl(self.get_delegate().checked_left_div(&lhs.0, &rhs.0).unwrap())
447 }
448}
449
450impl<R: RingStore> KaratsubaHint for AsFieldBase<R>
451where
452 R::Type: DivisibilityRing,
453{
454 fn karatsuba_threshold(&self) -> usize { self.get_delegate().karatsuba_threshold() }
455}
456
457impl<R: RingStore> ComputeInnerProduct for AsFieldBase<R>
458where
459 R::Type: DivisibilityRing,
460{
461 fn inner_product<I: Iterator<Item = (Self::Element, Self::Element)>>(&self, els: I) -> Self::Element {
462 self.rev_delegate(
463 self.get_delegate()
464 .inner_product(els.map(|(a, b)| (self.delegate(a), self.delegate(b)))),
465 )
466 }
467
468 fn inner_product_ref<'a, I: Iterator<Item = (&'a Self::Element, &'a Self::Element)>>(&self, els: I) -> Self::Element
469 where
470 Self::Element: 'a,
471 Self: 'a,
472 {
473 self.rev_delegate(
474 self.get_delegate()
475 .inner_product_ref(els.map(|(a, b)| (self.delegate_ref(a), self.delegate_ref(b)))),
476 )
477 }
478
479 fn inner_product_ref_fst<'a, I: Iterator<Item = (&'a Self::Element, Self::Element)>>(&self, els: I) -> Self::Element
480 where
481 Self::Element: 'a,
482 Self: 'a,
483 {
484 self.rev_delegate(
485 self.get_delegate()
486 .inner_product_ref_fst(els.map(|(a, b)| (self.delegate_ref(a), self.delegate(b)))),
487 )
488 }
489}
490
491impl<R: RingStore> StrassenHint for AsFieldBase<R>
492where
493 R::Type: DivisibilityRing,
494{
495 fn strassen_threshold(&self) -> usize { self.get_delegate().strassen_threshold() }
496}
497
498impl<R> FromModulusCreateableZnRing for AsFieldBase<RingValue<R>>
499where
500 R: DivisibilityRing + ZnRing + FromModulusCreateableZnRing,
501{
502 fn from_modulus<F, E>(create_modulus: F) -> Result<Self, E>
503 where
504 F: FnOnce(&Self::IntegerRingBase) -> Result<El<Self::IntegerRing>, E>,
505 {
506 <R as FromModulusCreateableZnRing>::from_modulus(create_modulus)
507 .map(|ring| RingValue::from(ring).as_field().ok().unwrap().into())
508 }
509}
510
511impl<R> Serialize for AsFieldBase<R>
512where
513 R: RingStore + Serialize,
514 R::Type: DivisibilityRing,
515{
516 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
517 where
518 S: Serializer,
519 {
520 SerializableNewtypeStruct::new("AsField", &self.base).serialize(serializer)
521 }
522}
523
524impl<'de, R> Deserialize<'de> for AsFieldBase<R>
525where
526 R: RingStore + Deserialize<'de>,
527 R::Type: DivisibilityRing,
528{
529 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
530 where
531 D: Deserializer<'de>,
532 {
533 DeserializeSeedNewtypeStruct::new("AsField", PhantomData::<R>)
534 .deserialize(deserializer)
535 .map(|base_ring| AsFieldBase {
536 zero: FieldEl(base_ring.zero()),
537 base: base_ring,
538 })
539 }
540}
541
542#[macro_export]
600macro_rules! impl_field_wrap_unwrap_homs {
601 (<{$($gen_args:tt)*}> $self_type_from:ty, $self_type_to:ty where $($constraints:tt)*) => {
602
603 impl<AsFieldRingStore, $($gen_args)*> CanHomFrom<$self_type_from> for $crate::rings::field::AsFieldBase<AsFieldRingStore>
604 where AsFieldRingStore: RingStore<Type = $self_type_to>, $($constraints)*
605 {
606 type Homomorphism = <$self_type_to as CanHomFrom<$self_type_from>>::Homomorphism;
607
608 fn has_canonical_hom(&self, from: &$self_type_from) -> Option<Self::Homomorphism> {
609 self.get_delegate().has_canonical_hom(from)
610 }
611
612 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 {
613 self.rev_delegate(self.get_delegate().map_in(from, el, hom))
614 }
615 }
616
617 impl<AsFieldRingStore, $($gen_args)*> CanHomFrom<$crate::rings::field::AsFieldBase<AsFieldRingStore>> for $self_type_to
618 where AsFieldRingStore: RingStore<Type = $self_type_from>, $($constraints)*
619 {
620 type Homomorphism = <$self_type_to as CanHomFrom<$self_type_from>>::Homomorphism;
621
622 fn has_canonical_hom(&self, from: &$crate::rings::field::AsFieldBase<AsFieldRingStore>) -> Option<Self::Homomorphism> {
623 self.has_canonical_hom(from.get_delegate())
624 }
625
626 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 {
627 self.map_in(from.get_delegate(), from.delegate(el), hom)
628 }
629 }
630 };
631 ($self_type_from:ty, $self_type_to:ty) => {
632 impl_field_wrap_unwrap_homs!{ <{}> $self_type_from, $self_type_to where }
633 };
634}
635
636#[macro_export]
642macro_rules! impl_field_wrap_unwrap_isos {
643 (<{$($gen_args:tt)*}> $self_type_from:ty, $self_type_to:ty where $($constraints:tt)*) => {
644
645 impl<AsFieldRingStore, $($gen_args)*> CanIsoFromTo<$self_type_from> for $crate::rings::field::AsFieldBase<AsFieldRingStore>
646 where AsFieldRingStore: RingStore<Type = $self_type_to>, $($constraints)*
647 {
648 type Isomorphism = <$self_type_to as CanIsoFromTo<$self_type_from>>::Isomorphism;
649
650 fn has_canonical_iso(&self, from: &$self_type_from) -> Option<Self::Isomorphism> {
651 self.get_delegate().has_canonical_iso(from)
652 }
653
654 fn map_out(&self, from: &$self_type_from, el: <Self as RingBase>::Element, iso: &Self::Isomorphism) -> <$self_type_from as RingBase>::Element {
655 self.get_delegate().map_out(from, self.delegate(el), iso)
656 }
657 }
658
659 impl<AsFieldRingStore, $($gen_args)*> CanIsoFromTo<$crate::rings::field::AsFieldBase<AsFieldRingStore>> for $self_type_to
660 where AsFieldRingStore: RingStore<Type = $self_type_from>, $($constraints)*
661 {
662 type Isomorphism = <$self_type_to as CanIsoFromTo<$self_type_from>>::Isomorphism;
663
664 fn has_canonical_iso(&self, from: &$crate::rings::field::AsFieldBase<AsFieldRingStore>) -> Option<Self::Isomorphism> {
665 self.has_canonical_iso(from.get_delegate())
666 }
667
668 fn map_out(&self, from: &$crate::rings::field::AsFieldBase<AsFieldRingStore>, el: <Self as RingBase>::Element, hom: &Self::Isomorphism) -> $crate::rings::field::FieldEl<AsFieldRingStore> {
669 from.rev_delegate(self.map_out(from.get_delegate(), el, hom))
670 }
671 }
672 };
673 ($self_type_from:ty, $self_type_to:ty) => {
674 impl_field_wrap_unwrap_isos!{ <{}> $self_type_from, $self_type_to where }
675 };
676}
677
678#[cfg(test)]
679use crate::rings::finite::FiniteRingStore;
680#[cfg(test)]
681use crate::rings::zn::zn_big::Zn;
682
683#[test]
684fn test_canonical_hom_axioms_static_int() {
685 let R = Zn::new(StaticRing::<i64>::RING, 17).as_field().ok().unwrap();
686 crate::ring::generic_tests::test_hom_axioms(StaticRing::<i64>::RING, &R, 0..17);
687}
688
689#[test]
690fn test_divisibility_axioms() {
691 let R = Zn::new(StaticRing::<i64>::RING, 17).as_field().ok().unwrap();
692 crate::divisibility::generic_tests::test_divisibility_axioms(&R, R.elements());
693}
694
695#[test]
696fn test_canonical_hom_axioms_wrap_unwrap() {
697 let R = Zn::new(StaticRing::<i64>::RING, 17).as_field().ok().unwrap();
698 crate::ring::generic_tests::test_hom_axioms(
699 RingRef::new(R.get_ring().get_delegate()),
700 &R,
701 RingRef::new(R.get_ring().get_delegate()).elements(),
702 );
703 crate::ring::generic_tests::test_iso_axioms(
704 RingRef::new(R.get_ring().get_delegate()),
705 &R,
706 RingRef::new(R.get_ring().get_delegate()).elements(),
707 );
708}
709
710#[test]
711fn test_principal_ideal_ring_axioms() {
712 let R = Zn::new(StaticRing::<i64>::RING, 17).as_field().ok().unwrap();
713 crate::pid::generic_tests::test_principal_ideal_ring_axioms(&R, R.elements());
714 crate::pid::generic_tests::test_euclidean_ring_axioms(&R, R.elements());
715}
716
717#[test]
718fn test_field_axioms() {
719 let R = Zn::new(StaticRing::<i64>::RING, 17).as_field().ok().unwrap();
720 crate::field::generic_tests::test_field_axioms(&R, R.elements());
721}