feanor_math/rings/
field.rs

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
18///
19/// A wrapper around a ring that marks this ring to be a perfect field. In particular,
20/// the functions provided by [`DivisibilityRing`] will be used to provide
21/// field-like division for the wrapped ring.
22/// 
23/// # Example
24/// 
25/// A common case where you might encounter [`AsFieldBase`] is when working with rings
26/// which might or might not be a field depending on data only known at runtime. One
27/// example are implementations of [`ZnRing`] with modulus chosen at runtime.
28/// ```
29/// # use feanor_math::assert_el_eq;
30/// # use feanor_math::homomorphism::*;
31/// # use feanor_math::ring::*;
32/// # use feanor_math::rings::field::*;
33/// # use feanor_math::rings::zn::*;
34/// # use feanor_math::rings::zn::zn_64::*;
35/// // 7 is a prime, so this is a field - but must be checked at runtime
36/// let Fp_as_ring = Zn::new(7);
37/// // we use `ZnRing::as_field()` to make this a field
38/// let Fp_as_field: AsField<Zn> = Fp_as_ring.as_field().ok().unwrap();
39/// // in many cases (like here) we can use canonical isomorphisms to map elements
40/// let iso = Fp_as_field.can_iso(&Fp_as_ring).unwrap();
41/// assert_el_eq!(&Fp_as_ring, Fp_as_ring.one(), iso.map(Fp_as_field.one()));
42/// ```
43/// Since the canonical isomorphisms are not given by blanket implementations
44/// (unfortunately there are some conflicts...), they are often not available in
45/// generic contexts. In this case, the currently best solution is to directly
46/// use the functions given by [`DelegateRing`], e.g.
47/// ```
48/// # use feanor_math::assert_el_eq;
49/// # use feanor_math::homomorphism::*;
50/// # use feanor_math::ring::*;
51/// # use feanor_math::rings::field::*;
52/// # use feanor_math::rings::zn::*;
53/// # use feanor_math::rings::zn::zn_64::*;
54/// fn work_in_Fp<R>(ring: R)
55///     where R: RingStore,
56///         R::Type: ZnRing
57/// {
58///     use crate::feanor_math::delegate::DelegateRing;
59/// 
60///     let R_as_field = (&ring).as_field().ok().unwrap();
61///     let x = ring.one();
62///     // since `DelegateRing` does not have a corresponding `RingStore`, the access
63///     // through `get_ring()` is necessary
64///     let x_mapped = R_as_field.get_ring().rev_delegate(x);
65///     let x_mapped_back = R_as_field.get_ring().delegate(x_mapped);
66/// }
67/// ```
68/// 
69pub 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///
106/// [`RingStore`] for [`AsFieldBase`].
107/// 
108#[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    ///
132    /// Assumes that the given ring is a perfect field, and wraps it in [`AsFieldBase`].
133    /// 
134    /// This function is not really unsafe, but users should be careful to only use
135    /// it with rings that are perfect fields. This cannot be checked in here, so must 
136    /// be checked by the caller.
137    /// 
138    pub fn promise_is_perfect_field(base: R) -> Self {
139        Self { zero: FieldEl(base.zero()), base }
140    }
141
142    ///
143    /// Assumes that the given ring is a field and checks whether it is perfect. If this is the case,
144    /// the function wraps it in [`AsFieldBase`]. 
145    ///
146    /// This function is not really unsafe, but users should be careful to only use
147    /// it with rings that are fields. This cannot be checked in here, so must be checked
148    /// by the caller.
149    /// 
150    /// Note that this function does check that the passed field is perfect. However,
151    /// that check is too conservative, and might fail on some perfect fields.
152    /// If you are sure that the field is also perfect, consider using [`AsFieldBase::promise_is_perfect_field()`]
153    /// instead.
154    /// 
155    #[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    ///
174    /// Removes the wrapper, returning the underlying base field.
175    /// 
176    pub fn unwrap_self(self) -> R {
177        self.base
178    }
179}
180
181impl<R: RingStore> AsFieldBase<R> 
182    where R::Type: PerfectField
183{
184    ///
185    /// Creates a new [`AsFieldBase`] from a ring that is already known to be a
186    /// perfect field.
187    /// 
188    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
254///
255/// Necessary to potentially implement [`crate::rings::zn::ZnRing`].
256/// 
257impl<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///
455/// Implements the isomorphisms `S: CanHomFrom<AsFieldBase<RingStore<Type = R>>>` and 
456/// `AsFieldBase<RingStore<Type = S>>: CanHomFrom<R>`.
457/// 
458/// This has to be a macro, as a blanket implementation would unfortunately cause conflicting impls.
459/// Usually, whenever a ring naturally might be a ring (e.g. like [`crate::rings::zn::zn_64::Zn`] or
460/// [`crate::rings::extension::extension_impl::FreeAlgebraImpl`], which even provide a function like 
461/// [`crate::rings::zn::ZnRingStore::as_field()`]), you might use this macro to implement [`CanHomFrom`]
462/// that simplify conversion from and to the field wrapper.
463/// 
464/// # Example
465/// ```
466/// # use feanor_math::ring::*;
467/// # use feanor_math::rings::zn::zn_64::*;
468/// # use feanor_math::rings::field::*;
469/// # use feanor_math::delegate::*;
470/// # use feanor_math::homomorphism::*;
471/// # use feanor_math::{impl_eq_based_self_iso, impl_field_wrap_unwrap_homs, impl_field_wrap_unwrap_isos};
472/// // A no-op wrapper around Zn
473/// #[derive(Copy, Clone)]
474/// struct MyPossibleField {
475///     base_zn: Zn
476/// }
477/// 
478/// impl PartialEq for MyPossibleField {
479/// 
480///     fn eq(&self, other: &Self) -> bool {
481///         self.base_zn.get_ring() == other.base_zn.get_ring()
482///     }
483/// }
484/// 
485/// // impl_wrap_unwrap_homs! relies on the homs/isos of the wrapped ring, so provide those
486/// impl_eq_based_self_iso!{ MyPossibleField }
487/// 
488/// impl DelegateRing for MyPossibleField {
489///     
490///     type Base = ZnBase;
491///     type Element = ZnEl;
492///
493///     fn get_delegate(&self) -> &Self::Base { self.base_zn.get_ring() }
494///     fn delegate_ref<'a>(&self, el: &'a Self::Element) -> &'a <Self::Base as RingBase>::Element { el }
495///     fn delegate_mut<'a>(&self, el: &'a mut Self::Element) -> &'a mut <Self::Base as RingBase>::Element { el }
496///     fn delegate(&self, el: Self::Element) -> <Self::Base as RingBase>::Element { el }
497///     fn rev_delegate(&self, el: <Self::Base as RingBase>::Element) -> Self::Element { el }
498/// }
499/// 
500/// impl_field_wrap_unwrap_homs!{ MyPossibleField, MyPossibleField }
501/// 
502/// // there is also a generic verision, which looks like
503/// impl_field_wrap_unwrap_isos!{ <{ /* type params here */ }> MyPossibleField, MyPossibleField where /* constraints here */ }
504/// 
505/// let R = RingValue::from(MyPossibleField { base_zn: Zn::new(5) });
506/// let R_field = RingValue::from(AsFieldBase::promise_is_perfect_field(R));
507/// let _ = R.can_hom(&R_field).unwrap();
508/// let _ = R_field.can_hom(&R).unwrap();
509/// let _ = R.can_iso(&R_field).unwrap();
510/// let _ = R_field.can_iso(&R).unwrap();
511/// ```
512/// 
513#[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///
551/// Implements the isomorphisms `S: CanIsoFromTo<AsFieldBase<RingStore<Type = R>>>` and `AsFieldBase<RingStore<Type = S>>: CanIsoFromTo<R>`.
552/// 
553/// This has to be a macro, as a blanket implementation would unfortunately cause conflicting impls.
554/// For an example and more detailed explanation, see [`impl_field_wrap_unwrap_homs!`]; 
555/// 
556#[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}