Skip to main content

feanor_math/
specialization.rs

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