feanor_math/rings/
field.rs

1use crate::algorithms::convolution::KaratsubaHint;
2use crate::algorithms::matmul::{ComputeInnerProduct, StrassenHint};
3use crate::reduce_lift::poly_eval::{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
18use std::marker::PhantomData;
19use std::fmt::Debug;
20
21use feanor_serde::newtype_struct::{DeserializeSeedNewtypeStruct, SerializableNewtypeStruct};
22use serde::{Deserialize, Serialize, Deserializer, Serializer};
23use serde::de::DeserializeSeed;
24
25///
26/// A wrapper around a ring that marks this ring to be a perfect field. In particular,
27/// the functions provided by [`DivisibilityRing`] will be used to provide
28/// field-like division for the wrapped ring.
29/// 
30/// # Example
31/// 
32/// A common case where you might encounter [`AsFieldBase`] is when working with rings
33/// which might or might not be a field depending on data only known at runtime. One
34/// example are implementations of [`ZnRing`] with modulus chosen at runtime.
35/// ```rust
36/// # use feanor_math::assert_el_eq;
37/// # use feanor_math::homomorphism::*;
38/// # use feanor_math::ring::*;
39/// # use feanor_math::rings::field::*;
40/// # use feanor_math::rings::zn::*;
41/// # use feanor_math::rings::zn::zn_64::*;
42/// // 7 is a prime, so this is a field - but must be checked at runtime
43/// let Fp_as_ring = Zn::new(7);
44/// // we use `ZnRing::as_field()` to make this a field
45/// let Fp_as_field: AsField<Zn> = Fp_as_ring.as_field().ok().unwrap();
46/// // in many cases (like here) we can use canonical isomorphisms to map elements
47/// let iso = Fp_as_field.can_iso(&Fp_as_ring).unwrap();
48/// assert_el_eq!(&Fp_as_ring, Fp_as_ring.one(), iso.map(Fp_as_field.one()));
49/// ```
50/// Since the canonical isomorphisms are not given by blanket implementations
51/// (unfortunately there are some conflicts...), they are often not available in
52/// generic contexts. In this case, the currently best solution is to directly
53/// use the functions given by [`DelegateRing`], e.g.
54/// ```rust
55/// # use feanor_math::assert_el_eq;
56/// # use feanor_math::homomorphism::*;
57/// # use feanor_math::ring::*;
58/// # use feanor_math::rings::field::*;
59/// # use feanor_math::rings::zn::*;
60/// # use feanor_math::rings::zn::zn_64::*;
61/// fn work_in_Fp<R>(ring: R)
62///     where R: RingStore,
63///         R::Type: ZnRing
64/// {
65///     use crate::feanor_math::delegate::DelegateRing;
66/// 
67///     let R_as_field = (&ring).as_field().ok().unwrap();
68///     let x = ring.one();
69///     // since `DelegateRing` does not have a corresponding `RingStore`, the access
70///     // through `get_ring()` is necessary
71///     let x_mapped = R_as_field.get_ring().rev_delegate(x);
72///     let x_mapped_back = R_as_field.get_ring().delegate(x_mapped);
73/// }
74/// ```
75/// The alternative is to explicitly use [`WrapHom`] and [`UnwrapHom`].
76/// 
77pub struct AsFieldBase<R: RingStore> 
78    where R::Type: DivisibilityRing
79{
80    base: R,
81    zero: FieldEl<R>
82}
83
84impl<R> PerfectField for AsFieldBase<R>
85    where R: RingStore,
86        R::Type: DivisibilityRing
87{}
88
89impl<R> Clone for AsFieldBase<R>
90    where R: RingStore + Clone,
91        R::Type: DivisibilityRing
92{
93    fn clone(&self) -> Self {
94        Self { zero: FieldEl(self.base.zero()), base: self.base.clone() }
95    }
96}
97
98impl<R> Copy for AsFieldBase<R>
99    where R: RingStore + Copy,
100        R::Type: DivisibilityRing,
101        El<R>: Copy
102{}
103
104impl<R> Debug for AsFieldBase<R>
105    where R: RingStore,
106        R::Type: DivisibilityRing + Debug
107{
108    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109        f.debug_tuple("AsField")
110            .field(&self.base.get_ring())
111            .finish()
112    }
113}
114
115impl<R> PartialEq for AsFieldBase<R>
116    where R: RingStore,
117        R::Type: DivisibilityRing
118{
119    fn eq(&self, other: &Self) -> bool {
120        self.base.get_ring() == other.base.get_ring()
121    }
122}
123
124///
125/// [`RingStore`] for [`AsFieldBase`].
126/// 
127#[allow(type_alias_bounds)]
128pub type AsField<R: RingStore> = RingValue<AsFieldBase<R>>;
129
130///
131/// An element of [`AsField`].
132/// 
133pub struct FieldEl<R: RingStore>(El<R>)
134    where R::Type: DivisibilityRing;
135
136impl<R: RingStore> Debug for FieldEl<R> 
137    where El<R>: Debug,
138        R::Type: DivisibilityRing
139{
140    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141        f.debug_tuple("FieldEl")
142            .field(&self.0)
143            .finish()
144    }
145}
146
147impl<R: RingStore> Clone for FieldEl<R> 
148    where El<R>: Clone,
149        R::Type: DivisibilityRing
150{
151    fn clone(&self) -> Self {
152        FieldEl(self.0.clone())
153    }
154}
155
156impl<R: RingStore> Copy for FieldEl<R> 
157    where El<R>: Copy,
158        R::Type: DivisibilityRing
159{}
160
161impl<R: RingStore> AsFieldBase<R> 
162    where R::Type: DivisibilityRing
163{
164    ///
165    /// Assumes that the given ring is a perfect field, and wraps it in [`AsFieldBase`].
166    /// 
167    /// This function is not really unsafe, but users should be careful to only use
168    /// it with rings that are perfect fields. This cannot be checked in here, so must 
169    /// be checked by the caller.
170    /// 
171    pub fn promise_is_perfect_field(base: R) -> Self {
172        Self { zero: FieldEl(base.zero()), base }
173    }
174
175    ///
176    /// Assumes that the given ring is a field and checks whether it is perfect. If this is the case,
177    /// the function wraps it in [`AsFieldBase`]. 
178    ///
179    /// This function is not really unsafe, but users should be careful to only use
180    /// it with rings that are fields. This cannot be checked in here, so must be checked
181    /// by the caller.
182    /// 
183    /// Note that this function does check that the passed field is perfect. However,
184    /// that check is too conservative, and might fail on some perfect fields.
185    /// If you are sure that the field is also perfect, consider using [`AsFieldBase::promise_is_perfect_field()`]
186    /// instead.
187    /// 
188    #[stability::unstable(feature = "enable")]
189    pub fn promise_is_field(base: R) -> Result<Self, R>
190        where R::Type: FiniteRingSpecializable
191    {
192        let characteristic = base.characteristic(&StaticRing::<i64>::RING);
193        if characteristic.is_some() && characteristic.unwrap() == 0 {
194            return Ok(Self::promise_is_perfect_field(base));
195        } else if <R::Type as FiniteRingSpecializable>::is_finite_ring() {
196            return Ok(Self::promise_is_perfect_field(base));
197        } else {
198            return Err(base);
199        }
200    }
201
202    pub fn unwrap_element(&self, el: <Self as RingBase>::Element) -> El<R> {
203        el.0
204    }
205
206    ///
207    /// Removes the wrapper, returning the underlying base field.
208    /// 
209    pub fn unwrap_self(self) -> R {
210        self.base
211    }
212}
213
214impl<R: RingStore> AsFieldBase<R> 
215    where R::Type: PerfectField
216{
217    ///
218    /// Creates a new [`AsFieldBase`] from a ring that is already known to be a
219    /// perfect field.
220    /// 
221    pub fn from_field(base: R) -> Self {
222        Self::promise_is_perfect_field(base)
223    }
224}
225
226impl<R: RingStore> DelegateRing for AsFieldBase<R> 
227    where R::Type: DivisibilityRing
228{
229    type Element = FieldEl<R>;
230    type Base = R::Type;
231
232    fn get_delegate(&self) -> &Self::Base {
233        self.base.get_ring()
234    }
235
236    fn delegate(&self, el: Self::Element) -> <Self::Base as RingBase>::Element {
237        el.0
238    }
239
240    fn delegate_mut<'a>(&self, el: &'a mut Self::Element) -> &'a mut <Self::Base as RingBase>::Element {
241        &mut el.0
242    }
243
244    fn delegate_ref<'a>(&self, el: &'a Self::Element) -> &'a <Self::Base as RingBase>::Element {
245        &el.0
246    }
247
248    fn rev_delegate(&self, el: <Self::Base as RingBase>::Element) -> Self::Element {
249        FieldEl(el)
250    }
251}
252
253impl<R: RingStore> DelegateRingImplFiniteRing for AsFieldBase<R> 
254    where R::Type: DivisibilityRing
255{}
256
257impl<R: RingStore, S: RingStore> CanHomFrom<AsFieldBase<S>> for AsFieldBase<R> 
258    where R::Type: DivisibilityRing + CanHomFrom<S::Type>,
259        S::Type: DivisibilityRing
260{
261    type Homomorphism = <R::Type as CanHomFrom<S::Type>>::Homomorphism;
262
263    fn has_canonical_hom(&self, from: &AsFieldBase<S>) -> Option<Self::Homomorphism> {
264        <R::Type as CanHomFrom<S::Type>>::has_canonical_hom(self.get_delegate(), from.get_delegate())
265    }
266
267    fn map_in(&self, from: &AsFieldBase<S>, el: FieldEl<S>, hom: &Self::Homomorphism) -> Self::Element {
268        FieldEl(<R::Type as CanHomFrom<S::Type>>::map_in(self.get_delegate(), from.get_delegate(), el.0, hom))
269    }
270}
271
272impl<R: RingStore, S: RingStore> CanIsoFromTo<AsFieldBase<S>> for AsFieldBase<R> 
273    where R::Type: DivisibilityRing + CanIsoFromTo<S::Type>,
274        S::Type: DivisibilityRing
275{
276    type Isomorphism = <R::Type as CanIsoFromTo<S::Type>>::Isomorphism;
277
278    fn has_canonical_iso(&self, from: &AsFieldBase<S>) -> Option<Self::Isomorphism> {
279        <R::Type as CanIsoFromTo<S::Type>>::has_canonical_iso(self.get_delegate(), from.get_delegate())
280    }
281
282    fn map_out(&self, from: &AsFieldBase<S>, el: Self::Element, iso: &Self::Isomorphism) -> FieldEl<S> {
283        FieldEl(<R::Type as CanIsoFromTo<S::Type>>::map_out(self.get_delegate(), from.get_delegate(), el.0, iso))
284    }
285}
286
287///
288/// Necessary to potentially implement [`crate::rings::zn::ZnRing`].
289/// 
290impl<R: RingStore, S: IntegerRing + ?Sized> CanHomFrom<S> for AsFieldBase<R> 
291    where R::Type: DivisibilityRing + CanHomFrom<S>
292{
293    type Homomorphism = <R::Type as CanHomFrom<S>>::Homomorphism;
294
295    fn has_canonical_hom(&self, from: &S) -> Option<Self::Homomorphism> {
296        self.get_delegate().has_canonical_hom(from)
297    }
298
299    fn map_in(&self, from: &S, el: S::Element, hom: &Self::Homomorphism) -> Self::Element {
300        FieldEl(<R::Type as CanHomFrom<S>>::map_in(self.get_delegate(), from, el, hom))
301    }
302}
303
304impl<R1, R2> CanHomFrom<AsLocalPIRBase<R1>> for AsFieldBase<R2>
305    where R1: RingStore, R2: RingStore,
306        R2::Type: CanHomFrom<R1::Type>,
307        R1::Type: DivisibilityRing,
308        R2::Type: DivisibilityRing
309{
310    type Homomorphism = <R2::Type as CanHomFrom<R1::Type>>::Homomorphism;
311
312    fn has_canonical_hom(&self, from: &AsLocalPIRBase<R1>) -> Option<Self::Homomorphism> {
313        self.get_delegate().has_canonical_hom(from.get_delegate())
314    }
315
316    fn map_in(&self, from: &AsLocalPIRBase<R1>, el: <AsLocalPIRBase<R1> as RingBase>::Element, hom: &Self::Homomorphism) -> Self::Element {
317        self.rev_delegate(self.get_delegate().map_in(from.get_delegate(), from.delegate(el), hom))
318    }
319}
320
321impl<R1, R2> CanIsoFromTo<AsLocalPIRBase<R1>> for AsFieldBase<R2>
322    where R1: RingStore, R2: RingStore,
323        R2::Type: CanIsoFromTo<R1::Type>,
324        R1::Type: DivisibilityRing,
325        R2::Type: DivisibilityRing
326{
327    type Isomorphism = <R2::Type as CanIsoFromTo<R1::Type>>::Isomorphism;
328
329    fn has_canonical_iso(&self, from: &AsLocalPIRBase<R1>) -> Option<Self::Isomorphism> {
330        self.get_delegate().has_canonical_iso(from.get_delegate())
331    }
332
333    fn map_out(&self, from: &AsLocalPIRBase<R1>, el: Self::Element, iso: &Self::Isomorphism) -> <AsLocalPIRBase<R1> as RingBase>::Element {
334        from.rev_delegate(self.get_delegate().map_out(from.get_delegate(), self.delegate(el), iso))
335    }
336}
337
338impl<R: RingStore> PrincipalIdealRing for AsFieldBase<R> 
339    where R::Type: DivisibilityRing
340{
341    fn checked_div_min(&self, lhs: &Self::Element, rhs: &Self::Element) -> Option<Self::Element> {
342        if self.is_zero(lhs) && self.is_zero(rhs) {
343            Some(self.one())
344        } else {
345            self.checked_left_div(lhs, rhs)
346        }
347    }
348    
349    fn extended_ideal_gen(&self, lhs: &Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element, Self::Element) {
350        if self.is_zero(lhs) {
351            (self.zero(), self.one(), self.clone_el(rhs))
352        } else {
353            (self.one(), self.zero(), self.clone_el(lhs))
354        }
355    }
356}
357
358impl<R: RingStore> PrincipalLocalRing for AsFieldBase<R> 
359    where R::Type: DivisibilityRing
360{
361    fn max_ideal_gen(&self) ->  &Self::Element {
362        &self.zero
363    }
364
365    fn nilpotent_power(&self) -> Option<usize> {
366        Some(1)
367    }
368
369    fn valuation(&self, x: &Self::Element) -> Option<usize> {
370        if self.is_zero(x) {
371            return None;
372        } else {
373            return Some(0);
374        }
375    }
376}
377
378impl<R> InterpolationBaseRing for AsFieldBase<R>
379    where R: InterpolationBaseRingStore,
380        R::Type: InterpolationBaseRing
381{
382    type ExtendedRingBase<'a> = <R::Type as InterpolationBaseRing>::ExtendedRingBase<'a>
383        where Self: 'a;
384
385    type ExtendedRing<'a> = <R::Type as InterpolationBaseRing>::ExtendedRing<'a>
386        where Self: 'a;
387
388    fn in_base<'a, S>(&self, ext_ring: S, el: El<S>) -> Option<Self::Element>
389        where Self: 'a, S: RingStore<Type = Self::ExtendedRingBase<'a>>
390    {
391        self.get_delegate().in_base(ext_ring, el).map(|x| self.rev_delegate(x))
392    }
393
394    fn in_extension<'a, S>(&self, ext_ring: S, el: Self::Element) -> El<S>
395        where Self: 'a, S: RingStore<Type = Self::ExtendedRingBase<'a>>
396    {
397        self.get_delegate().in_extension(ext_ring, self.delegate(el))
398    }
399
400    fn interpolation_points<'a>(&'a self, count: usize) -> (Self::ExtendedRing<'a>, Vec<El<Self::ExtendedRing<'a>>>) {
401        self.get_delegate().interpolation_points(count)
402    }
403}
404
405impl<R: RingStore> EuclideanRing for AsFieldBase<R> 
406    where R::Type: DivisibilityRing
407{
408    fn euclidean_div_rem(&self, lhs: Self::Element, rhs: &Self::Element) -> (Self::Element, Self::Element) {
409        assert!(!self.is_zero(rhs));
410        (self.checked_left_div(&lhs, rhs).unwrap(), self.zero())
411    }
412
413    fn euclidean_deg(&self, val: &Self::Element) -> Option<usize> {
414        if self.is_zero(val) {
415            Some(0)
416        } else {
417            Some(1)
418        }
419    }
420
421    fn euclidean_rem(&self, _: Self::Element, rhs: &Self::Element) -> Self::Element {
422        assert!(!self.is_zero(rhs));
423        self.zero()
424    }
425}
426
427impl<R: RingStore> Domain for AsFieldBase<R> 
428    where R::Type: DivisibilityRing
429{}
430
431impl<R: RingStore> Field for AsFieldBase<R>
432    where R::Type: DivisibilityRing
433{
434    fn div(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
435        FieldEl(self.get_delegate().checked_left_div(&lhs.0, &rhs.0).unwrap())
436    }
437}
438
439impl<R: RingStore> KaratsubaHint for AsFieldBase<R>
440    where R::Type: DivisibilityRing
441{
442    fn karatsuba_threshold(&self) -> usize {
443        self.get_delegate().karatsuba_threshold()
444    }
445}
446
447impl<R: RingStore> ComputeInnerProduct for AsFieldBase<R>
448    where R::Type: DivisibilityRing
449{
450    fn inner_product<I: Iterator<Item = (Self::Element, Self::Element)>>(&self, els: I) -> Self::Element {
451        self.rev_delegate(self.get_delegate().inner_product(els.map(|(a, b)| (self.delegate(a), self.delegate(b)))))
452    }
453
454    fn inner_product_ref<'a, I: Iterator<Item = (&'a Self::Element, &'a Self::Element)>>(&self, els: I) -> Self::Element
455        where Self::Element: 'a,
456            Self: 'a
457    {
458        self.rev_delegate(self.get_delegate().inner_product_ref(els.map(|(a, b)| (self.delegate_ref(a), self.delegate_ref(b)))))
459    }
460
461    fn inner_product_ref_fst<'a, I: Iterator<Item = (&'a Self::Element, Self::Element)>>(&self, els: I) -> Self::Element
462        where Self::Element: 'a,
463            Self: 'a
464    {
465        self.rev_delegate(self.get_delegate().inner_product_ref_fst(els.map(|(a, b)| (self.delegate_ref(a), self.delegate(b)))))
466    }
467}
468
469impl<R: RingStore> StrassenHint for AsFieldBase<R>
470    where R::Type: DivisibilityRing
471{
472    fn strassen_threshold(&self) -> usize {
473        self.get_delegate().strassen_threshold()
474    }
475}
476
477impl<R> FromModulusCreateableZnRing for AsFieldBase<RingValue<R>> 
478    where R: DivisibilityRing + ZnRing + FromModulusCreateableZnRing
479{
480    fn from_modulus<F, E>(create_modulus: F) -> Result<Self, E>
481        where F:FnOnce(&Self::IntegerRingBase) -> Result<El<Self::IntegerRing>, E> 
482    {
483        <R as FromModulusCreateableZnRing>::from_modulus(create_modulus).map(|ring| RingValue::from(ring).as_field().ok().unwrap().into())
484    }
485}
486
487impl<R> Serialize for AsFieldBase<R>
488    where R: RingStore + Serialize,
489        R::Type: DivisibilityRing
490{
491    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
492        where S: Serializer
493    {
494        SerializableNewtypeStruct::new("AsField", &self.base).serialize(serializer)
495    }
496}
497
498impl<'de, R> Deserialize<'de> for AsFieldBase<R>
499    where R: RingStore + Deserialize<'de>,
500        R::Type: DivisibilityRing
501{
502    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
503        where D: Deserializer<'de>
504    {
505        DeserializeSeedNewtypeStruct::new("AsField", PhantomData::<R>).deserialize(deserializer).map(|base_ring| AsFieldBase { zero: FieldEl(base_ring.zero()), base: base_ring })
506    }
507}
508
509///
510/// Implements the isomorphisms `S: CanHomFrom<AsFieldBase<RingStore<Type = R>>>` and 
511/// `AsFieldBase<RingStore<Type = S>>: CanHomFrom<R>`.
512/// 
513/// This has to be a macro, as a blanket implementation would unfortunately cause conflicting impls.
514/// Usually, whenever a ring naturally might be a ring (e.g. like [`crate::rings::zn::zn_64::Zn`] or
515/// [`crate::rings::extension::extension_impl::FreeAlgebraImpl`], which even provide a function like 
516/// [`crate::rings::zn::ZnRingStore::as_field()`]), you might use this macro to implement [`CanHomFrom`]
517/// that simplify conversion from and to the field wrapper.
518/// 
519/// # Example
520/// ```rust
521/// # use feanor_math::ring::*;
522/// # use feanor_math::rings::zn::zn_64::*;
523/// # use feanor_math::rings::field::*;
524/// # use feanor_math::delegate::*;
525/// # use feanor_math::homomorphism::*;
526/// # use feanor_math::{impl_eq_based_self_iso, impl_field_wrap_unwrap_homs, impl_field_wrap_unwrap_isos};
527/// // A no-op wrapper around Zn
528/// #[derive(Copy, Clone)]
529/// struct MyPossibleField {
530///     base_zn: Zn
531/// }
532/// 
533/// impl PartialEq for MyPossibleField {
534/// 
535///     fn eq(&self, other: &Self) -> bool {
536///         self.base_zn.get_ring() == other.base_zn.get_ring()
537///     }
538/// }
539/// 
540/// // impl_wrap_unwrap_homs! relies on the homs/isos of the wrapped ring, so provide those
541/// impl_eq_based_self_iso!{ MyPossibleField }
542/// 
543/// impl DelegateRing for MyPossibleField {
544///     
545///     type Base = ZnBase;
546///     type Element = ZnEl;
547///
548///     fn get_delegate(&self) -> &Self::Base { self.base_zn.get_ring() }
549///     fn delegate_ref<'a>(&self, el: &'a Self::Element) -> &'a <Self::Base as RingBase>::Element { el }
550///     fn delegate_mut<'a>(&self, el: &'a mut Self::Element) -> &'a mut <Self::Base as RingBase>::Element { el }
551///     fn delegate(&self, el: Self::Element) -> <Self::Base as RingBase>::Element { el }
552///     fn rev_delegate(&self, el: <Self::Base as RingBase>::Element) -> Self::Element { el }
553/// }
554/// 
555/// impl_field_wrap_unwrap_homs!{ MyPossibleField, MyPossibleField }
556/// 
557/// // there is also a generic verision, which looks like
558/// impl_field_wrap_unwrap_isos!{ <{ /* type params here */ }> MyPossibleField, MyPossibleField where /* constraints here */ }
559/// 
560/// let R = RingValue::from(MyPossibleField { base_zn: Zn::new(5) });
561/// let R_field = RingValue::from(AsFieldBase::promise_is_perfect_field(R));
562/// let _ = R.can_hom(&R_field).unwrap();
563/// let _ = R_field.can_hom(&R).unwrap();
564/// let _ = R.can_iso(&R_field).unwrap();
565/// let _ = R_field.can_iso(&R).unwrap();
566/// ```
567/// 
568#[macro_export]
569macro_rules! impl_field_wrap_unwrap_homs {
570    (<{$($gen_args:tt)*}> $self_type_from:ty, $self_type_to:ty where $($constraints:tt)*) => {
571        
572        impl<AsFieldRingStore, $($gen_args)*> CanHomFrom<$self_type_from> for $crate::rings::field::AsFieldBase<AsFieldRingStore>
573            where AsFieldRingStore: RingStore<Type = $self_type_to>, $($constraints)*
574        {
575            type Homomorphism = <$self_type_to as CanHomFrom<$self_type_from>>::Homomorphism;
576
577            fn has_canonical_hom(&self, from: &$self_type_from) -> Option<Self::Homomorphism> {
578                self.get_delegate().has_canonical_hom(from)
579            }
580
581            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 {
582                self.rev_delegate(self.get_delegate().map_in(from, el, hom))
583            }
584        }
585        
586        impl<AsFieldRingStore, $($gen_args)*> CanHomFrom<$crate::rings::field::AsFieldBase<AsFieldRingStore>> for $self_type_to
587            where AsFieldRingStore: RingStore<Type = $self_type_from>, $($constraints)*
588        {
589            type Homomorphism = <$self_type_to as CanHomFrom<$self_type_from>>::Homomorphism;
590
591            fn has_canonical_hom(&self, from: &$crate::rings::field::AsFieldBase<AsFieldRingStore>) -> Option<Self::Homomorphism> {
592                self.has_canonical_hom(from.get_delegate())
593            }
594
595            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 {
596                self.map_in(from.get_delegate(), from.delegate(el), hom)
597            }
598        }
599    };
600    ($self_type_from:ty, $self_type_to:ty) => {
601        impl_field_wrap_unwrap_homs!{ <{}> $self_type_from, $self_type_to where }
602    };
603}
604
605///
606/// Implements the isomorphisms `S: CanIsoFromTo<AsFieldBase<RingStore<Type = R>>>` and `AsFieldBase<RingStore<Type = S>>: CanIsoFromTo<R>`.
607/// 
608/// This has to be a macro, as a blanket implementation would unfortunately cause conflicting impls.
609/// For an example and more detailed explanation, see [`impl_field_wrap_unwrap_homs!`]; 
610/// 
611#[macro_export]
612macro_rules! impl_field_wrap_unwrap_isos {
613    (<{$($gen_args:tt)*}> $self_type_from:ty, $self_type_to:ty where $($constraints:tt)*) => {
614        
615        impl<AsFieldRingStore, $($gen_args)*> CanIsoFromTo<$self_type_from> for $crate::rings::field::AsFieldBase<AsFieldRingStore>
616            where AsFieldRingStore: RingStore<Type = $self_type_to>, $($constraints)*
617        {
618            type Isomorphism = <$self_type_to as CanIsoFromTo<$self_type_from>>::Isomorphism;
619
620            fn has_canonical_iso(&self, from: &$self_type_from) -> Option<Self::Isomorphism> {
621                self.get_delegate().has_canonical_iso(from)
622            }
623
624            fn map_out(&self, from: &$self_type_from, el: <Self as RingBase>::Element, iso: &Self::Isomorphism) -> <$self_type_from as RingBase>::Element {
625                self.get_delegate().map_out(from, self.delegate(el), iso)
626            }
627        }
628        
629        impl<AsFieldRingStore, $($gen_args)*> CanIsoFromTo<$crate::rings::field::AsFieldBase<AsFieldRingStore>> for $self_type_to
630            where AsFieldRingStore: RingStore<Type = $self_type_from>, $($constraints)*
631        {
632            type Isomorphism = <$self_type_to as CanIsoFromTo<$self_type_from>>::Isomorphism;
633
634            fn has_canonical_iso(&self, from: &$crate::rings::field::AsFieldBase<AsFieldRingStore>) -> Option<Self::Isomorphism> {
635                self.has_canonical_iso(from.get_delegate())
636            }
637
638            fn map_out(&self, from: &$crate::rings::field::AsFieldBase<AsFieldRingStore>, el: <Self as RingBase>::Element, hom: &Self::Isomorphism) -> $crate::rings::field::FieldEl<AsFieldRingStore> {
639                from.rev_delegate(self.map_out(from.get_delegate(), el, hom))
640            }
641        }
642    };
643    ($self_type_from:ty, $self_type_to:ty) => {
644        impl_field_wrap_unwrap_isos!{ <{}> $self_type_from, $self_type_to where }
645    };
646}
647
648#[cfg(test)]
649use crate::rings::zn::zn_big::Zn;
650#[cfg(test)]
651use crate::rings::finite::FiniteRingStore;
652
653#[test]
654fn test_canonical_hom_axioms_static_int() {
655    let R = Zn::new(StaticRing::<i64>::RING, 17).as_field().ok().unwrap();
656    crate::ring::generic_tests::test_hom_axioms(StaticRing::<i64>::RING, &R, 0..17);
657}
658
659#[test]
660fn test_divisibility_axioms() {
661    let R = Zn::new(StaticRing::<i64>::RING, 17).as_field().ok().unwrap();
662    crate::divisibility::generic_tests::test_divisibility_axioms(&R, R.elements());
663}
664
665#[test]
666fn test_canonical_hom_axioms_wrap_unwrap() {
667    let R = Zn::new(StaticRing::<i64>::RING, 17).as_field().ok().unwrap();
668    crate::ring::generic_tests::test_hom_axioms(RingRef::new(R.get_ring().get_delegate()), &R, RingRef::new(R.get_ring().get_delegate()).elements());
669    crate::ring::generic_tests::test_iso_axioms(RingRef::new(R.get_ring().get_delegate()), &R, RingRef::new(R.get_ring().get_delegate()).elements());
670}
671
672#[test]
673fn test_principal_ideal_ring_axioms() {
674    let R = Zn::new(StaticRing::<i64>::RING, 17).as_field().ok().unwrap();
675    crate::pid::generic_tests::test_principal_ideal_ring_axioms(&R, R.elements());
676    crate::pid::generic_tests::test_euclidean_ring_axioms(&R, R.elements());
677}
678
679#[test]
680fn test_field_axioms() {
681    let R = Zn::new(StaticRing::<i64>::RING, 17).as_field().ok().unwrap();
682    crate::field::generic_tests::test_field_axioms(&R, R.elements());
683}