feanor_math/rings/
finite.rs1use std::marker::PhantomData;
2
3use crate::algorithms::int_factor::is_prime_power;
4use crate::field::*;
5use crate::homomorphism::Homomorphism;
6use crate::ring::*;
7use crate::integer::{BigIntRing, IntegerRing, IntegerRingStore};
8use crate::specialization::FiniteRingSpecializable;
9use crate::unsafe_any::UnsafeAny;
10
11pub trait FiniteRing: RingBase + FiniteRingSpecializable {
19
20 type ElementsIter<'a>: Sized + Clone + Iterator<Item = <Self as RingBase>::Element>
25 where Self: 'a;
26
27 fn elements<'a>(&'a self) -> Self::ElementsIter<'a>;
32
33 fn random_element<G: FnMut() -> u64>(&self, rng: G) -> <Self as RingBase>::Element;
38
39 fn size<I: IntegerRingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
44 where I::Type: IntegerRing;
45}
46
47pub trait FiniteRingStore: RingStore
51 where Self::Type: FiniteRing
52{
53 fn elements<'a>(&'a self) -> <Self::Type as FiniteRing>::ElementsIter<'a> {
57 self.get_ring().elements()
58 }
59
60 fn random_element<G: FnMut() -> u64>(&self, rng: G) -> El<Self> {
64 self.get_ring().random_element(rng)
65 }
66
67 fn size<I: IntegerRingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
71 where I::Type: IntegerRing
72 {
73 self.get_ring().size(ZZ)
74 }
75}
76
77impl<R: RingStore> FiniteRingStore for R
78 where R::Type: FiniteRing
79{}
80
81#[stability::unstable(feature = "enable")]
82pub struct UnsafeAnyFrobeniusDataGuarded<GuardType: ?Sized> {
83 content: UnsafeAny,
84 guard: PhantomData<GuardType>
85}
86
87impl<GuardType: ?Sized> UnsafeAnyFrobeniusDataGuarded<GuardType> {
88
89 #[stability::unstable(feature = "enable")]
90 pub fn uninit() -> UnsafeAnyFrobeniusDataGuarded<GuardType> {
91 Self {
92 content: UnsafeAny::uninit(),
93 guard: PhantomData
94 }
95 }
96
97 #[stability::unstable(feature = "enable")]
98 pub unsafe fn from<T>(value: T) -> UnsafeAnyFrobeniusDataGuarded<GuardType> {
99 Self {
100 content: unsafe { UnsafeAny::from(value) },
101 guard: PhantomData
102 }
103 }
104
105 #[stability::unstable(feature = "enable")]
106 pub unsafe fn get<'a, T>(&'a self) -> &'a T {
107 unsafe { self.content.get() }
108 }
109}
110
111#[stability::unstable(feature = "enable")]
112pub trait ComputeFrobeniusRing: Field + FiniteRing {
113
114 type FrobeniusData;
115
116 fn create_frobenius(&self, exponent_of_p: usize) -> (Self::FrobeniusData, usize);
117
118 fn apply_frobenius(&self, _frobenius_data: &Self::FrobeniusData, exponent_of_p: usize, x: Self::Element) -> Self::Element;
119}
120
121impl<R> ComputeFrobeniusRing for R
122 where R: ?Sized + Field + FiniteRing
123{
124 type FrobeniusData = UnsafeAnyFrobeniusDataGuarded<R>;
125
126 default fn create_frobenius(&self, exponent_of_p: usize) -> (Self::FrobeniusData, usize) {
127 (UnsafeAnyFrobeniusDataGuarded::uninit(), exponent_of_p)
128 }
129
130 default fn apply_frobenius(&self, _frobenius_data: &Self::FrobeniusData, exponent_of_p: usize, x: Self::Element) -> Self::Element {
131 if exponent_of_p == 0 {
132 return x
133 } else {
134 let (p, e) = is_prime_power(BigIntRing::RING, &self.size(&BigIntRing::RING).unwrap()).unwrap();
135 return RingRef::new(self).pow_gen(x, &BigIntRing::RING.pow(p, exponent_of_p % e), BigIntRing::RING);
136 }
137 }
138}
139
140#[stability::unstable(feature = "enable")]
141pub struct Frobenius<R>
142 where R: RingStore,
143 R::Type: FiniteRing + Field
144{
145 field: R,
146 data: <R::Type as ComputeFrobeniusRing>::FrobeniusData,
147 exponent_of_p: usize
148}
149
150impl<R> Frobenius<R>
151 where R: RingStore,
152 R::Type: FiniteRing + Field
153{
154 #[stability::unstable(feature = "enable")]
155 pub fn new(field: R, exponent_of_p: usize) -> Self {
156 let (_p, field_dimension) = is_prime_power(BigIntRing::RING, &field.size(BigIntRing::RING).unwrap()).unwrap();
157 let exponent_of_p = exponent_of_p % field_dimension;
158 let (data, exponent_of_p2) = field.get_ring().create_frobenius(exponent_of_p);
159 assert_eq!(exponent_of_p, exponent_of_p2);
160 return Self { field: field, data: data, exponent_of_p: exponent_of_p };
161 }
162}
163
164impl<R> Homomorphism<R::Type, R::Type> for Frobenius<R>
165 where R: RingStore,
166 R::Type: FiniteRing + Field
167{
168 type CodomainStore = R;
169 type DomainStore = R;
170
171 fn codomain<'a>(&'a self) -> &'a Self::CodomainStore {
172 &self.field
173 }
174
175 fn domain<'a>(&'a self) -> &'a Self::DomainStore {
176 &self.field
177 }
178
179 fn map(&self, x: <R::Type as RingBase>::Element) -> <R::Type as RingBase>::Element {
180 self.field.get_ring().apply_frobenius(&self.data, self.exponent_of_p, x)
181 }
182}
183
184#[cfg(any(test, feature = "generic_tests"))]
185pub mod generic_tests {
186
187 use crate::divisibility::DivisibilityRingStore;
188 use crate::integer::{int_cast, BigIntRing, IntegerRingStore};
189 use crate::ordered::OrderedRingStore;
190 use crate::primitive_int::StaticRing;
191
192 use super::{FiniteRing, FiniteRingStore, RingStore};
193
194 pub fn test_finite_ring_axioms<R>(ring: &R)
195 where R: RingStore,
196 R::Type: FiniteRing
197 {
198 let ZZ = BigIntRing::RING;
199 let size = ring.size(&ZZ).unwrap();
200 let char = ring.characteristic(&ZZ).unwrap();
201 assert!(ZZ.divides(&size, &char));
202
203 if ZZ.is_geq(&size, &ZZ.power_of_two(7)) {
204 assert_eq!(None, ring.size(&StaticRing::<i8>::RING));
205 }
206
207 if ZZ.is_leq(&size, &ZZ.power_of_two(30)) {
208 assert_eq!(int_cast(size, &StaticRing::<i64>::RING, &ZZ) as usize, ring.elements().count());
209 }
210 }
211}