feanor_math/
specialization.rs

1use std::alloc::Allocator;
2use std::marker::PhantomData;
3
4use crate::algorithms::convolution::ConvolutionAlgorithm;
5use crate::integer::*;
6use crate::primitive_int::PrimitiveInt;
7use crate::primitive_int::StaticRingBase;
8use crate::ring::*;
9use crate::rings::extension::extension_impl::*;
10use crate::rings::finite::*;
11use crate::rings::rational::*;
12use crate::rings::rust_bigint::RustBigintRingBase;
13use crate::seq::*;
14use crate::rings::zn::*;
15
16///
17/// Operation on a ring `R` that only makes sense if `R` implements
18/// the trait [`crate::rings::finite::FiniteRing`].
19/// 
20/// Used through the trait [`FiniteRingSpecializable`].
21/// 
22#[stability::unstable(feature = "enable")]
23pub trait FiniteRingOperation<R>
24    where R: ?Sized
25{    
26    type Output;
27
28    ///
29    /// Runs the operations, with the additional assumption that `R: FiniteRing`.
30    /// 
31    fn execute(self) -> Self::Output
32        where R: FiniteRing;
33}
34
35///
36/// Trait for ring types that can check (at compile time) whether they implement
37/// [`crate::rings::finite::FiniteRing`].
38/// 
39/// This serves as a workaround while specialization is not properly supported. 
40/// 
41#[stability::unstable(feature = "enable")]
42pub trait FiniteRingSpecializable: RingBase {
43
44    fn specialize<O: FiniteRingOperation<Self>>(op: O) -> Result<O::Output, ()>;
45
46    fn is_finite_ring() -> bool {
47        struct CheckIsFinite;
48        impl<R: ?Sized + RingBase> FiniteRingOperation<R> for CheckIsFinite {
49            type Output = ();
50            fn execute(self) -> Self::Output
51                where R: FiniteRing { () } 
52        }
53        return Self::specialize(CheckIsFinite).is_ok();
54    }
55}
56
57impl<I> FiniteRingSpecializable for RationalFieldBase<I>
58    where I: RingStore,
59        I::Type: IntegerRing
60{
61    fn specialize<O: FiniteRingOperation<Self>>(_op: O) -> Result<O::Output, ()> {
62        Err(())
63    }
64}
65
66impl<A> FiniteRingSpecializable for RustBigintRingBase<A>
67    where A: Allocator + Clone
68{
69    fn specialize<O: FiniteRingOperation<Self>>(_op: O) -> Result<O::Output, ()> {
70        Err(())
71    }
72}
73
74impl<T> FiniteRingSpecializable for StaticRingBase<T>
75    where T: PrimitiveInt
76{
77    fn specialize<O: FiniteRingOperation<Self>>(_op: O) -> Result<O::Output, ()> {
78        Err(())
79    }
80}
81
82impl FiniteRingSpecializable for zn_64::ZnBase {
83    fn specialize<O: FiniteRingOperation<Self>>(op: O) -> Result<O::Output, ()> {
84        Ok(op.execute())
85    }
86}
87
88impl<R, V, A, C> FiniteRingSpecializable for FreeAlgebraImplBase<R, V, A, C>
89    where R: RingStore,
90        R::Type: FiniteRingSpecializable, 
91        V: VectorView<El<R>>,
92        A: Allocator + Clone,
93        C: ConvolutionAlgorithm<R::Type>
94{
95    fn specialize<O: FiniteRingOperation<Self>>(op: O) -> Result<O::Output, ()> {
96        struct OpWrapper<R, V, A, C, O>
97            where R: RingStore,
98                R::Type: FiniteRingSpecializable, 
99                V: VectorView<El<R>>,
100                A: Allocator + Clone,
101                C: ConvolutionAlgorithm<R::Type>,
102                O: FiniteRingOperation<FreeAlgebraImplBase<R, V, A, C>>
103        {
104            operation: O,
105            ring: PhantomData<FreeAlgebraImpl<R, V, A, C>>
106        }
107
108        impl<R, V, A, C, O> FiniteRingOperation<R::Type> for OpWrapper<R, V, A, C, O>
109            where R: RingStore,
110                R::Type: FiniteRingSpecializable, 
111                V: VectorView<El<R>>,
112                A: Allocator + Clone,
113                C: ConvolutionAlgorithm<R::Type>,
114                O: FiniteRingOperation<FreeAlgebraImplBase<R, V, A, C>>
115        {
116            type Output = O::Output;
117            fn execute(self) -> Self::Output where R::Type:FiniteRing {
118                self.operation.execute()
119            }
120        }
121
122        <R::Type as FiniteRingSpecializable>::specialize(OpWrapper { operation: op, ring: PhantomData })
123    }
124}
125
126#[cfg(test)]
127use crate::homomorphism::*;
128#[cfg(test)]
129use crate::rings::field::*;
130#[cfg(test)]
131use crate::rings::extension::galois_field::*;
132#[cfg(test)]
133use crate::rings::extension::*;
134
135#[test]
136fn test_specialize_finite_field() {
137
138    struct Verify<'a, R>(&'a R, i32)
139        where R: ?Sized + RingBase;
140
141    impl<'a, R: ?Sized> FiniteRingOperation<R> for Verify<'a, R>
142        where R: RingBase
143    {
144        type Output = ();
145
146        fn execute(self)
147            where R: FiniteRing
148        {
149            assert_el_eq!(BigIntRing::RING, BigIntRing::RING.int_hom().map(self.1), self.0.size(&BigIntRing::RING).unwrap());
150        }
151    }
152
153    let ring = zn_64::Zn::new(7).as_field().ok().unwrap();
154    assert!(<AsFieldBase<zn_64::Zn>>::specialize(Verify(ring.get_ring(), 7)).is_ok());
155    
156    let ring = GaloisField::new(3, 2);
157    assert!(GaloisFieldBase::specialize(Verify(ring.get_ring(), 9)).is_ok());
158
159    let ring = GaloisField::new(3, 2).into().unwrap_self();
160    assert!(<AsFieldBase<FreeAlgebraImpl<_, _, _, _>>>::specialize(Verify(ring.get_ring(), 9)).is_ok());
161    
162    let ring = RationalField::new(BigIntRing::RING);
163    assert!(<RationalFieldBase<_>>::specialize(Verify(ring.get_ring(), 0)).is_err());
164    
165    let QQ = RationalField::new(BigIntRing::RING);
166    let ring = FreeAlgebraImpl::new(&QQ, 2, [QQ.neg_one()]).as_field().ok().unwrap();
167    assert!(<AsFieldBase<FreeAlgebraImpl<_, _, _, _>>>::specialize(Verify(ring.get_ring(), 0)).is_err());
168
169    let base_ring = GaloisField::new(3, 2).into().unwrap_self();
170    let ring = FreeAlgebraImpl::new(&base_ring, 3, [base_ring.neg_one(), base_ring.one()]).as_field().ok().unwrap();
171    assert!(<AsFieldBase<FreeAlgebraImpl<_, _, _, _>>>::specialize(Verify(ring.get_ring(), 729)).is_ok());
172}