use super::field::{AsField, AsFieldBase};
use super::poly::dense_poly::DensePolyRing;
use super::poly::{PolyRing, PolyRingStore};
use crate::algorithms::extension_ops;
use crate::algorithms::linsolve::LinSolveRing;
use crate::algorithms::poly_factor::FactorPolyField;
use crate::divisibility::DivisibilityRing;
use crate::field::*;
use crate::homomorphism::*;
use crate::pid::PrincipalIdealRing;
use crate::ring::*;
use crate::seq::*;
use crate::wrapper::RingElementWrapper;
pub mod extension_impl;
pub mod galois_field;
pub mod number_field;
pub mod conway;
pub trait FreeAlgebra: RingExtension {
type VectorRepresentation<'a>: VectorFn<El<Self::BaseRing>>
where
Self: 'a;
fn canonical_gen(&self) -> Self::Element;
fn rank(&self) -> usize;
fn wrt_canonical_basis<'a>(&'a self, el: &'a Self::Element) -> Self::VectorRepresentation<'a>;
fn from_canonical_basis<V>(&self, vec: V) -> Self::Element
where
V: IntoIterator<Item = El<Self::BaseRing>>,
V::IntoIter: DoubleEndedIterator,
{
let mut given_len = 0;
let x = self.canonical_gen();
let mut result = self.zero();
for c in vec.into_iter().rev() {
self.mul_assign_ref(&mut result, &x);
self.add_assign(&mut result, self.from(c));
given_len += 1;
}
assert_eq!(given_len, self.rank());
return result;
}
fn mul_assign_gen_power(&self, el: &mut Self::Element, power: usize) {
self.mul_assign(el, RingRef::new(self).pow(self.canonical_gen(), power));
}
fn from_canonical_basis_extended<V>(&self, vec: V) -> Self::Element
where
V: IntoIterator<Item = El<Self::BaseRing>>,
{
extension_ops::from_canonical_basis_extended(self, vec)
}
fn charpoly<P, H>(&self, el: &Self::Element, poly_ring: P, hom: H) -> El<P>
where
P: RingStore,
P::Type: PolyRing,
<<P::Type as RingExtension>::BaseRing as RingStore>::Type: LinSolveRing,
H: Homomorphism<<Self::BaseRing as RingStore>::Type, <<P::Type as RingExtension>::BaseRing as RingStore>::Type>,
{
extension_ops::charpoly(self, el, poly_ring, hom)
}
fn minpoly<P, H>(&self, el: &Self::Element, poly_ring: P, hom: H) -> El<P>
where
P: RingStore,
P::Type: PolyRing,
<<P::Type as RingExtension>::BaseRing as RingStore>::Type: LinSolveRing,
H: Homomorphism<<Self::BaseRing as RingStore>::Type, <<P::Type as RingExtension>::BaseRing as RingStore>::Type>,
{
extension_ops::minpoly(self, el, poly_ring, hom)
}
fn trace(&self, el: Self::Element) -> El<Self::BaseRing> {
let mut current = el;
let generator = self.canonical_gen();
return self.base_ring().sum((0..self.rank()).map(|i| {
let result = self.wrt_canonical_basis(¤t).at(i);
self.mul_assign_ref(&mut current, &generator);
return result;
}));
}
fn discriminant(&self) -> El<Self::BaseRing>
where
<Self::BaseRing as RingStore>::Type: PrincipalIdealRing,
{
extension_ops::discriminant(self)
}
}
pub trait FreeAlgebraStore: RingStore
where
Self::Type: FreeAlgebra,
{
delegate! { FreeAlgebra, fn canonical_gen(&self) -> El<Self> }
delegate! { FreeAlgebra, fn rank(&self) -> usize }
delegate! { FreeAlgebra, fn trace(&self, el: El<Self>) -> El<<Self::Type as RingExtension>::BaseRing> }
delegate! { FreeAlgebra, fn mul_assign_gen_power(&self, el: &mut El<Self>, power: usize) -> () }
fn wrt_canonical_basis<'a>(&'a self, el: &'a El<Self>) -> <Self::Type as FreeAlgebra>::VectorRepresentation<'a> {
self.get_ring().wrt_canonical_basis(el)
}
fn from_canonical_basis<V>(&self, vec: V) -> El<Self>
where
V: IntoIterator<Item = El<<Self::Type as RingExtension>::BaseRing>>,
V::IntoIter: DoubleEndedIterator,
{
self.get_ring().from_canonical_basis(vec)
}
fn from_canonical_basis_extended<V>(&self, vec: V) -> El<Self>
where
V: IntoIterator<Item = El<<Self::Type as RingExtension>::BaseRing>>,
{
self.get_ring().from_canonical_basis_extended(vec)
}
fn generating_poly<P, H>(&self, poly_ring: P, hom: H) -> El<P>
where
P: PolyRingStore,
P::Type: PolyRing,
H: Homomorphism<
<<Self::Type as RingExtension>::BaseRing as RingStore>::Type,
<<P::Type as RingExtension>::BaseRing as RingStore>::Type,
>,
{
assert!(hom.domain().get_ring() == self.base_ring().get_ring());
poly_ring.sub(
poly_ring.from_terms([(poly_ring.base_ring().one(), self.rank())]),
self.poly_repr(&poly_ring, &self.pow(self.canonical_gen(), self.rank()), hom),
)
}
fn as_field(self) -> Result<AsField<Self>, Self>
where
Self::Type: DivisibilityRing,
<<Self::Type as RingExtension>::BaseRing as RingStore>::Type: Field + FactorPolyField,
{
let poly_ring = DensePolyRing::new(self.base_ring(), "X");
if <_ as FactorPolyField>::factor_poly(
&poly_ring,
&self.generating_poly(&poly_ring, self.base_ring().identity()),
)
.0
.len()
> 1
{
return Err(self);
} else {
return Ok(RingValue::from(AsFieldBase::promise_is_perfect_field(self)));
}
}
fn poly_repr<P, H>(&self, to: P, el: &El<Self>, hom: H) -> El<P>
where
P: PolyRingStore,
P::Type: PolyRing,
H: Homomorphism<
<<Self::Type as RingExtension>::BaseRing as RingStore>::Type,
<<P::Type as RingExtension>::BaseRing as RingStore>::Type,
>,
{
let coeff_vec = self.wrt_canonical_basis(el);
to.from_terms(
(0..self.rank())
.map(|i| coeff_vec.at(i))
.enumerate()
.filter(|(_, x)| !self.base_ring().is_zero(x))
.map(|(j, x)| (hom.map(x), j)),
)
}
fn discriminant(&self) -> El<<Self::Type as RingExtension>::BaseRing>
where
<<Self::Type as RingExtension>::BaseRing as RingStore>::Type: PrincipalIdealRing,
{
self.get_ring().discriminant()
}
fn charpoly<P, H>(&self, el: &El<Self>, poly_ring: P, hom: H) -> El<P>
where
P: RingStore,
P::Type: PolyRing,
<<P::Type as RingExtension>::BaseRing as RingStore>::Type: LinSolveRing,
H: Homomorphism<
<<Self::Type as RingExtension>::BaseRing as RingStore>::Type,
<<P::Type as RingExtension>::BaseRing as RingStore>::Type,
>,
{
self.get_ring().charpoly(el, poly_ring, hom)
}
#[stability::unstable(feature = "enable")]
fn with_wrapped_generator<'a, F, const M: usize>(&'a self, f: F) -> [El<Self>; M]
where
F: FnOnce(&RingElementWrapper<&'a Self>) -> [RingElementWrapper<&'a Self>; M],
{
let wrapped_indet = RingElementWrapper::new(self, self.canonical_gen());
let mut result_it = f(&wrapped_indet).into_iter();
return std::array::from_fn(|_| result_it.next().unwrap().unwrap());
}
}
impl<R: RingStore> FreeAlgebraStore for R where R::Type: FreeAlgebra {}
#[stability::unstable(feature = "enable")]
pub struct FreeAlgebraHom<R, S>
where
R: RingStore,
R::Type: FreeAlgebra,
S: RingStore,
S::Type: FreeAlgebra,
<S::Type as RingExtension>::BaseRing: RingStore<Type = <<R::Type as RingExtension>::BaseRing as RingStore>::Type>,
{
from: R,
to: S,
image_of_generator: El<S>,
}
impl<R> FreeAlgebraHom<R, R>
where
R: RingStore + Clone,
R::Type: FreeAlgebra,
{
#[stability::unstable(feature = "enable")]
pub fn identity(ring: R) -> Self {
Self {
image_of_generator: ring.canonical_gen(),
from: ring.clone(),
to: ring,
}
}
}
impl<R, S> FreeAlgebraHom<R, S>
where
R: RingStore,
R::Type: FreeAlgebra,
S: RingStore,
S::Type: FreeAlgebra,
<S::Type as RingExtension>::BaseRing: RingStore<Type = <<R::Type as RingExtension>::BaseRing as RingStore>::Type>,
{
#[stability::unstable(feature = "enable")]
pub fn promise_is_well_defined(from: R, to: S, image_of_generator: El<S>) -> Self {
assert!(from.base_ring().get_ring() == to.base_ring().get_ring());
Self {
from,
to,
image_of_generator,
}
}
#[stability::unstable(feature = "enable")]
pub fn new(from: R, to: S, image_of_generator: El<S>) -> Self {
assert!(from.base_ring().get_ring() == to.base_ring().get_ring());
let poly_ring = DensePolyRing::new(to.base_ring(), "X");
assert!(to.is_zero(&poly_ring.evaluate(
&from.generating_poly(&poly_ring, poly_ring.base_ring().identity()),
&image_of_generator,
to.inclusion()
)));
Self {
from,
to,
image_of_generator,
}
}
#[stability::unstable(feature = "enable")]
pub fn destruct(self) -> (R, S, El<S>) { (self.from, self.to, self.image_of_generator) }
}
impl<R, S> Homomorphism<R::Type, S::Type> for FreeAlgebraHom<R, S>
where
R: RingStore,
R::Type: FreeAlgebra,
S: RingStore,
S::Type: FreeAlgebra,
<S::Type as RingExtension>::BaseRing: RingStore<Type = <<R::Type as RingExtension>::BaseRing as RingStore>::Type>,
{
type DomainStore = R;
type CodomainStore = S;
fn domain(&self) -> &Self::DomainStore { &self.from }
fn codomain(&self) -> &Self::CodomainStore { &self.to }
fn map(&self, x: El<R>) -> El<S> { self.map_ref(&x) }
fn map_ref(&self, x: &El<R>) -> El<S> {
let poly_ring = DensePolyRing::new(self.to.base_ring(), "X");
return poly_ring.evaluate(
&self.from.poly_repr(&poly_ring, x, self.to.base_ring().identity()),
&self.image_of_generator,
self.to.inclusion(),
);
}
}
#[cfg(any(test, feature = "generic_tests"))]
pub mod generic_tests {
use super::*;
pub fn test_free_algebra_axioms<R: FreeAlgebraStore>(ring: R)
where
R::Type: FreeAlgebra,
{
let x = ring.canonical_gen();
let n = ring.rank();
let xn_original = ring.pow(ring.clone_el(&x), n);
let xn_vec = ring.wrt_canonical_basis(&xn_original);
let xn = ring.sum(Iterator::map(0..n, |i| {
ring.mul(ring.inclusion().map(xn_vec.at(i)), ring.pow(ring.clone_el(&x), i))
}));
assert_el_eq!(ring, xn_original, xn);
let x_n_1_vec_expected = (0..n).map_fn(|i| {
if i > 0 {
ring.base_ring()
.add(ring.base_ring().mul(xn_vec.at(n - 1), xn_vec.at(i)), xn_vec.at(i - 1))
} else {
ring.base_ring().mul(xn_vec.at(n - 1), xn_vec.at(0))
}
});
let x_n_1 = ring.pow(ring.clone_el(&x), n + 1);
let x_n_1_vec_actual = ring.wrt_canonical_basis(&x_n_1);
for i in 0..n {
assert_el_eq!(ring.base_ring(), x_n_1_vec_expected.at(i), x_n_1_vec_actual.at(i));
}
for i in (0..ring.rank()).step_by(3) {
for j in (1..ring.rank()).step_by(5) {
if i == j {
continue;
}
let element = ring.from_canonical_basis((0..n).map(|k| {
if k == i {
ring.base_ring().one()
} else if k == j {
ring.base_ring().int_hom().map(2)
} else {
ring.base_ring().zero()
}
}));
let expected = ring.add(
ring.pow(ring.clone_el(&x), i),
ring.int_hom().mul_map(ring.pow(ring.clone_el(&x), j), 2),
);
assert_el_eq!(ring, expected, element);
let element_vec = ring.wrt_canonical_basis(&expected);
for k in 0..ring.rank() {
if k == i {
assert_el_eq!(ring.base_ring(), ring.base_ring().one(), element_vec.at(k));
} else if k == j {
assert_el_eq!(ring.base_ring(), ring.base_ring().int_hom().map(2), element_vec.at(k));
} else {
assert_el_eq!(ring.base_ring(), ring.base_ring().zero(), element_vec.at(k));
}
}
}
}
for i in (0..ring.rank()).step_by(3) {
for j in (0..ring.rank()).step_by(5) {
let element = ring.add(ring.pow(ring.canonical_gen(), i), ring.one());
let mut actual = ring.clone_el(&element);
ring.mul_assign_gen_power(&mut actual, j);
assert_el_eq!(ring, ring.mul(element, ring.pow(ring.canonical_gen(), j)), actual);
}
}
}
}