use std::marker::PhantomData;
use crate::algorithms::int_factor::is_prime_power;
use crate::field::*;
use crate::homomorphism::Homomorphism;
use crate::integer::{BigIntRing, IntegerRing, IntegerRingStore};
use crate::ring::*;
use crate::specialization::FiniteRingSpecializable;
use crate::unsafe_any::UnsafeAny;
pub trait FiniteRing: RingBase + FiniteRingSpecializable {
type ElementsIter<'a>: Sized + Clone + Iterator<Item = <Self as RingBase>::Element>
where
Self: 'a;
fn elements<'a>(&'a self) -> Self::ElementsIter<'a>;
fn random_element<G: FnMut() -> u64>(&self, rng: G) -> <Self as RingBase>::Element;
fn size<I: IntegerRingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
where
I::Type: IntegerRing;
}
pub trait FiniteRingStore: RingStore
where
Self::Type: FiniteRing,
{
fn elements<'a>(&'a self) -> <Self::Type as FiniteRing>::ElementsIter<'a> { self.get_ring().elements() }
fn random_element<G: FnMut() -> u64>(&self, rng: G) -> El<Self> { self.get_ring().random_element(rng) }
fn size<I: IntegerRingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
where
I::Type: IntegerRing,
{
self.get_ring().size(ZZ)
}
}
impl<R: RingStore> FiniteRingStore for R where R::Type: FiniteRing {}
#[stability::unstable(feature = "enable")]
pub struct UnsafeAnyFrobeniusDataGuarded<GuardType: ?Sized> {
content: UnsafeAny,
guard: PhantomData<GuardType>,
}
impl<GuardType: ?Sized> UnsafeAnyFrobeniusDataGuarded<GuardType> {
#[stability::unstable(feature = "enable")]
pub fn uninit() -> UnsafeAnyFrobeniusDataGuarded<GuardType> {
Self {
content: UnsafeAny::uninit(),
guard: PhantomData,
}
}
#[stability::unstable(feature = "enable")]
pub unsafe fn from<T>(value: T) -> UnsafeAnyFrobeniusDataGuarded<GuardType> {
Self {
content: unsafe { UnsafeAny::from(value) },
guard: PhantomData,
}
}
#[stability::unstable(feature = "enable")]
pub unsafe fn get<'a, T>(&'a self) -> &'a T { unsafe { self.content.get() } }
}
#[stability::unstable(feature = "enable")]
pub trait ComputeFrobeniusRing: Field + FiniteRing {
type FrobeniusData;
fn create_frobenius(&self, exponent_of_p: usize) -> (Self::FrobeniusData, usize);
fn apply_frobenius(
&self,
_frobenius_data: &Self::FrobeniusData,
exponent_of_p: usize,
x: Self::Element,
) -> Self::Element;
}
impl<R> ComputeFrobeniusRing for R
where
R: ?Sized + Field + FiniteRing,
{
type FrobeniusData = UnsafeAnyFrobeniusDataGuarded<R>;
default fn create_frobenius(&self, exponent_of_p: usize) -> (Self::FrobeniusData, usize) {
(UnsafeAnyFrobeniusDataGuarded::uninit(), exponent_of_p)
}
default fn apply_frobenius(
&self,
_frobenius_data: &Self::FrobeniusData,
exponent_of_p: usize,
x: Self::Element,
) -> Self::Element {
if exponent_of_p == 0 {
return x;
} else {
let (p, e) = is_prime_power(BigIntRing::RING, &self.size(&BigIntRing::RING).unwrap()).unwrap();
return RingRef::new(self).pow_gen(x, &BigIntRing::RING.pow(p, exponent_of_p % e), BigIntRing::RING);
}
}
}
#[stability::unstable(feature = "enable")]
pub struct Frobenius<R>
where
R: RingStore,
R::Type: FiniteRing + Field,
{
field: R,
data: <R::Type as ComputeFrobeniusRing>::FrobeniusData,
exponent_of_p: usize,
}
impl<R> Frobenius<R>
where
R: RingStore,
R::Type: FiniteRing + Field,
{
#[stability::unstable(feature = "enable")]
pub fn new(field: R, exponent_of_p: usize) -> Self {
let (_p, field_dimension) = is_prime_power(BigIntRing::RING, &field.size(BigIntRing::RING).unwrap()).unwrap();
let exponent_of_p = exponent_of_p % field_dimension;
let (data, exponent_of_p2) = field.get_ring().create_frobenius(exponent_of_p);
assert_eq!(exponent_of_p, exponent_of_p2);
return Self {
field,
data,
exponent_of_p,
};
}
}
impl<R> Homomorphism<R::Type, R::Type> for Frobenius<R>
where
R: RingStore,
R::Type: FiniteRing + Field,
{
type CodomainStore = R;
type DomainStore = R;
fn codomain(&self) -> &Self::CodomainStore { &self.field }
fn domain(&self) -> &Self::DomainStore { &self.field }
fn map(&self, x: <R::Type as RingBase>::Element) -> <R::Type as RingBase>::Element {
self.field.get_ring().apply_frobenius(&self.data, self.exponent_of_p, x)
}
}
#[cfg(any(test, feature = "generic_tests"))]
pub mod generic_tests {
use super::{FiniteRing, FiniteRingStore, RingStore};
use crate::divisibility::DivisibilityRingStore;
use crate::integer::{BigIntRing, IntegerRingStore, int_cast};
use crate::ordered::OrderedRingStore;
use crate::primitive_int::StaticRing;
pub fn test_finite_ring_axioms<R>(ring: &R)
where
R: RingStore,
R::Type: FiniteRing,
{
let ZZ = BigIntRing::RING;
let size = ring.size(&ZZ).unwrap();
let char = ring.characteristic(&ZZ).unwrap();
assert!(ZZ.divides(&size, &char));
if ZZ.is_geq(&size, &ZZ.power_of_two(7)) {
assert_eq!(None, ring.size(&StaticRing::<i8>::RING));
}
if ZZ.is_leq(&size, &ZZ.power_of_two(30)) {
assert_eq!(
int_cast(size, &StaticRing::<i64>::RING, &ZZ) as usize,
ring.elements().count()
);
}
}
}