feanor_math/
specialization.rs

1use crate::ring::*;
2use crate::rings::finite::*;
3
4///
5/// Operation on a ring `R` that only makes sense if `R` implements
6/// the trait [`crate::rings::finite::FiniteRing`].
7/// 
8/// Used through the trait [`FiniteRingSpecializable`].
9/// 
10#[stability::unstable(feature = "enable")]
11pub trait FiniteRingOperation<R>
12    where R: ?Sized
13{    
14    type Output;
15
16    ///
17    /// Runs the operations, with the additional assumption that `R: FiniteRing`.
18    /// 
19    fn execute(self) -> Self::Output
20        where R: FiniteRing;
21
22    ///
23    /// Runs the operation in case that `R` is not a [`FiniteRing`].
24    /// 
25    fn fallback(self) -> Self::Output;
26}
27
28///
29/// Trait for ring types that can check (at compile time) whether they implement
30/// [`crate::rings::finite::FiniteRing`].
31/// 
32/// This serves as a workaround while specialization is not properly supported. 
33/// 
34#[stability::unstable(feature = "enable")]
35pub trait FiniteRingSpecializable: RingBase {
36
37    fn specialize<O: FiniteRingOperation<Self>>(op: O) -> O::Output;
38
39    fn is_finite_ring() -> bool {
40        struct CheckIsFinite;
41        impl<R: ?Sized + RingBase> FiniteRingOperation<R> for CheckIsFinite {
42            type Output = bool;
43            fn execute(self) -> Self::Output
44                where R: FiniteRing { true }
45            fn fallback(self) -> Self::Output { false }
46        }
47        return Self::specialize(CheckIsFinite);
48    }
49}
50
51#[cfg(test)]
52use crate::homomorphism::*;
53#[cfg(test)]
54use crate::rings::field::*;
55#[cfg(test)]
56use crate::rings::extension::galois_field::*;
57#[cfg(test)]
58use crate::rings::rational::*;
59#[cfg(test)]
60use crate::rings::zn::*;
61#[cfg(test)]
62use crate::integer::*;
63#[cfg(test)]
64use crate::rings::extension::extension_impl::*;
65#[cfg(test)]
66use crate::rings::extension::*;
67
68#[test]
69fn test_specialize_finite_field() {
70
71    struct Verify<'a, R>(&'a R, i32)
72        where R: ?Sized + RingBase;
73
74    impl<'a, R: ?Sized> FiniteRingOperation<R> for Verify<'a, R>
75        where R: RingBase
76    {
77        type Output = bool;
78
79        fn execute(self) -> bool
80            where R: FiniteRing
81        {
82            assert_el_eq!(BigIntRing::RING, BigIntRing::RING.int_hom().map(self.1), self.0.size(&BigIntRing::RING).unwrap());
83            return true;
84        }
85
86        fn fallback(self) -> Self::Output {
87            return false;
88        }
89    }
90
91    let ring = zn_64::Zn::new(7).as_field().ok().unwrap();
92    assert!(<AsFieldBase<zn_64::Zn>>::specialize(Verify(ring.get_ring(), 7)));
93    
94    let ring = GaloisField::new(3, 2);
95    assert!(GaloisFieldBase::specialize(Verify(ring.get_ring(), 9)));
96
97    let ring = GaloisField::new(3, 2).into().unwrap_self();
98    assert!(<AsFieldBase<FreeAlgebraImpl<_, _, _, _>>>::specialize(Verify(ring.get_ring(), 9)));
99    
100    let ring = RationalField::new(BigIntRing::RING);
101    assert!(!<RationalFieldBase<_>>::specialize(Verify(ring.get_ring(), 0)));
102    
103    let QQ = RationalField::new(BigIntRing::RING);
104    let ring = FreeAlgebraImpl::new(&QQ, 2, [QQ.neg_one()]).as_field().ok().unwrap();
105    assert!(!<AsFieldBase<FreeAlgebraImpl<_, _, _, _>>>::specialize(Verify(ring.get_ring(), 0)));
106
107    let base_ring = GaloisField::new(3, 2).into().unwrap_self();
108    let ring = FreeAlgebraImpl::new(&base_ring, 3, [base_ring.neg_one(), base_ring.one()]).as_field().ok().unwrap();
109    assert!(<AsFieldBase<FreeAlgebraImpl<_, _, _, _>>>::specialize(Verify(ring.get_ring(), 729)));
110}