Skip to main content

feanor_math/rings/
field.rs

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
24/// A wrapper around a ring that marks this ring to be a perfect field. In particular,
25/// the functions provided by [`DivisibilityRing`] will be used to provide
26/// field-like division for the wrapped ring.
27///
28/// # Example
29///
30/// A common case where you might encounter [`AsFieldBase`] is when working with rings
31/// which might or might not be a field depending on data only known at runtime. One
32/// example are implementations of [`ZnRing`] with modulus chosen at runtime.
33/// ```rust
34/// # use feanor_math::assert_el_eq;
35/// # use feanor_math::homomorphism::*;
36/// # use feanor_math::ring::*;
37/// # use feanor_math::rings::field::*;
38/// # use feanor_math::rings::zn::*;
39/// # use feanor_math::rings::zn::zn_64::*;
40/// // 7 is a prime, so this is a field - but must be checked at runtime
41/// let Fp_as_ring = Zn::new(7);
42/// // we use `ZnRing::as_field()` to make this a field
43/// let Fp_as_field: AsField<Zn> = Fp_as_ring.as_field().ok().unwrap();
44/// // in many cases (like here) we can use canonical isomorphisms to map elements
45/// let iso = Fp_as_field.can_iso(&Fp_as_ring).unwrap();
46/// assert_el_eq!(&Fp_as_ring, Fp_as_ring.one(), iso.map(Fp_as_field.one()));
47/// ```
48/// Since the canonical isomorphisms are not given by blanket implementations
49/// (unfortunately there are some conflicts...), they are often not available in
50/// generic contexts. In this case, the currently best solution is to directly
51/// use the functions given by [`DelegateRing`], e.g.
52/// ```rust
53/// # use feanor_math::assert_el_eq;
54/// # use feanor_math::homomorphism::*;
55/// # use feanor_math::ring::*;
56/// # use feanor_math::rings::field::*;
57/// # use feanor_math::rings::zn::*;
58/// # use feanor_math::rings::zn::zn_64::*;
59/// fn work_in_Fp<R>(ring: R)
60/// where
61///     R: RingStore,
62///     R::Type: ZnRing,
63/// {
64///     use crate::feanor_math::delegate::DelegateRing;
65///
66///     let R_as_field = (&ring).as_field().ok().unwrap();
67///     let x = ring.one();
68///     // since `DelegateRing` does not have a corresponding `RingStore`, the access
69///     // through `get_ring()` is necessary
70///     let x_mapped = R_as_field.get_ring().rev_delegate(x);
71///     let x_mapped_back = R_as_field.get_ring().delegate(x_mapped);
72/// }
73/// ```
74/// The alternative is to explicitly use [`WrapHom`] and [`UnwrapHom`].
75pub 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/// [`RingStore`] for [`AsFieldBase`].
130#[allow(type_alias_bounds)]
131pub type AsField<R: RingStore> = RingValue<AsFieldBase<R>>;
132
133/// An element of [`AsField`].
134pub 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    /// Assumes that the given ring is a perfect field, and wraps it in [`AsFieldBase`].
168    ///
169    /// This function is not really unsafe, but users should be careful to only use
170    /// it with rings that are perfect fields. This cannot be checked in here, so must
171    /// be checked by the caller.
172    pub fn promise_is_perfect_field(base: R) -> Self {
173        Self {
174            zero: FieldEl(base.zero()),
175            base,
176        }
177    }
178
179    /// Assumes that the given ring is a field and checks whether it is perfect. If this is the
180    /// case, the function wraps it in [`AsFieldBase`].
181    ///
182    /// This function is not really unsafe, but users should be careful to only use
183    /// it with rings that are fields. This cannot be checked in here, so must be checked
184    /// by the caller.
185    ///
186    /// Note that this function does check that the passed field is perfect. However,
187    /// that check is too conservative, and might fail on some perfect fields.
188    /// If you are sure that the field is also perfect, consider using
189    /// [`AsFieldBase::promise_is_perfect_field()`] instead.
190    #[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    /// Removes the wrapper, returning the underlying base field.
208    pub fn unwrap_self(self) -> R { self.base }
209}
210
211impl<R: RingStore> AsFieldBase<R>
212where
213    R::Type: PerfectField,
214{
215    /// Creates a new [`AsFieldBase`] from a ring that is already known to be a
216    /// perfect field.
217    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
282/// Necessary to potentially implement [`crate::rings::zn::ZnRing`].
283impl<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/// Implements the isomorphisms `S: CanHomFrom<AsFieldBase<RingStore<Type = R>>>` and
543/// `AsFieldBase<RingStore<Type = S>>: CanHomFrom<R>`.
544///
545/// This has to be a macro, as a blanket implementation would unfortunately cause conflicting impls.
546/// Usually, whenever a ring naturally might be a ring (e.g. like [`crate::rings::zn::zn_64::Zn`] or
547/// [`crate::rings::extension::extension_impl::FreeAlgebraImpl`], which even provide a function like
548/// [`crate::rings::zn::ZnRingStore::as_field()`]), you might use this macro to implement
549/// [`CanHomFrom`] that simplify conversion from and to the field wrapper.
550///
551/// # Example
552/// ```rust
553/// # use feanor_math::ring::*;
554/// # use feanor_math::rings::zn::zn_64::*;
555/// # use feanor_math::rings::field::*;
556/// # use feanor_math::delegate::*;
557/// # use feanor_math::homomorphism::*;
558/// # use feanor_math::{impl_eq_based_self_iso, impl_field_wrap_unwrap_homs, impl_field_wrap_unwrap_isos};
559/// // A no-op wrapper around Zn
560/// #[derive(Copy, Clone)]
561/// struct MyPossibleField {
562///     base_zn: Zn
563/// }
564///
565/// impl PartialEq for MyPossibleField {
566///
567///     fn eq(&self, other: &Self) -> bool {
568///         self.base_zn.get_ring() == other.base_zn.get_ring()
569///     }
570/// }
571///
572/// // impl_wrap_unwrap_homs! relies on the homs/isos of the wrapped ring, so provide those
573/// impl_eq_based_self_iso!{ MyPossibleField }
574///
575/// impl DelegateRing for MyPossibleField {
576///     
577///     type Base = ZnBase;
578///     type Element = ZnEl;
579///
580///     fn get_delegate(&self) -> &Self::Base { self.base_zn.get_ring() }
581///     fn delegate_ref<'a>(&self, el: &'a Self::Element) -> &'a <Self::Base as RingBase>::Element { el }
582///     fn delegate_mut<'a>(&self, el: &'a mut Self::Element) -> &'a mut <Self::Base as RingBase>::Element { el }
583///     fn delegate(&self, el: Self::Element) -> <Self::Base as RingBase>::Element { el }
584///     fn rev_delegate(&self, el: <Self::Base as RingBase>::Element) -> Self::Element { el }
585/// }
586///
587/// impl_field_wrap_unwrap_homs!{ MyPossibleField, MyPossibleField }
588///
589/// // there is also a generic verision, which looks like
590/// impl_field_wrap_unwrap_isos!{ <{ /* type params here */ }> MyPossibleField, MyPossibleField where /* constraints here */ }
591///
592/// let R = RingValue::from(MyPossibleField { base_zn: Zn::new(5) });
593/// let R_field = RingValue::from(AsFieldBase::promise_is_perfect_field(R));
594/// let _ = R.can_hom(&R_field).unwrap();
595/// let _ = R_field.can_hom(&R).unwrap();
596/// let _ = R.can_iso(&R_field).unwrap();
597/// let _ = R_field.can_iso(&R).unwrap();
598/// ```
599#[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/// Implements the isomorphisms `S: CanIsoFromTo<AsFieldBase<RingStore<Type = R>>>` and
637/// `AsFieldBase<RingStore<Type = S>>: CanIsoFromTo<R>`.
638///
639/// This has to be a macro, as a blanket implementation would unfortunately cause conflicting impls.
640/// For an example and more detailed explanation, see [`impl_field_wrap_unwrap_homs!`];
641#[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}