use crate::{matrix::dense::DenseMatrix, ring::*};
use crate::vector::vec_fn::*;
use crate::homomorphism::*;
use super::poly::{PolyRingStore, PolyRing};
pub mod extension_impl;
pub mod galois_field;
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: ExactSizeIterator + DoubleEndedIterator + Iterator<Item = El<Self::BaseRing>>
{
assert_eq!(vec.len(), self.rank());
let x = self.canonical_gen();
let mut result = self.zero();
for c in vec.rev() {
self.mul_assign_ref(&mut result, &x);
self.add_assign(&mut result, self.from(c));
}
return result;
}
}
pub trait FreeAlgebraStore: RingStore
where Self::Type: FreeAlgebra
{
delegate!{ FreeAlgebra, fn canonical_gen(&self) -> El<Self> }
delegate!{ FreeAlgebra, fn rank(&self) -> 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: ExactSizeIterator + DoubleEndedIterator + Iterator<Item = El<<Self::Type as RingExtension>::BaseRing>>
{
self.get_ring().from_canonical_basis(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>
{
poly_ring.sub(
poly_ring.from_terms([(poly_ring.base_ring().one(), self.rank())].into_iter()),
self.poly_repr(&poly_ring, &self.pow(self.canonical_gen(), self.rank()), hom)
)
}
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 create_multiplication_matrix(&self, el: &El<Self>) -> DenseMatrix<<<Self::Type as RingExtension>::BaseRing as RingStore>::Type> {
let mut result = DenseMatrix::zero(self.rank(), self.rank(), self.base_ring());
let mut current = self.clone_el(el);
let gen = self.canonical_gen();
for i in 0..self.rank() {
{
let current_basis_repr = self.wrt_canonical_basis(¤t);
for j in 0..self.rank() {
*result.at_mut(j, i) = current_basis_repr.at(j);
}
}
self.mul_assign_ref(&mut current, &gen);
}
return result;
}
}
impl<R: RingStore> FreeAlgebraStore for R
where R::Type: FreeAlgebra
{}
#[cfg(any(test, feature = "generic_tests"))]
pub fn generic_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).into_fn().map(|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(5) {
for j in (1..ring.rank()).step_by(7) {
if i == j {
continue;
}
let element = ring.from_canonical_basis(Iterator::map(0..n, |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));
}
}
}
}
}