use std::fmt::Debug;
use std::marker::PhantomData;
use crate::primitive_int::{StaticRing, StaticRingBase};
use crate::ring::*;
pub trait Homomorphism<Domain: ?Sized, Codomain: ?Sized>
where
Domain: RingBase,
Codomain: RingBase,
{
type DomainStore: RingStore<Type = Domain>;
type CodomainStore: RingStore<Type = Codomain>;
fn domain(&self) -> &Self::DomainStore;
fn codomain(&self) -> &Self::CodomainStore;
fn map(&self, x: Domain::Element) -> Codomain::Element;
fn map_ref(&self, x: &Domain::Element) -> Codomain::Element { self.map(self.domain().clone_el(x)) }
fn mul_assign_map(&self, lhs: &mut Codomain::Element, rhs: Domain::Element) {
self.codomain().mul_assign(lhs, self.map(rhs))
}
fn mul_assign_ref_map(&self, lhs: &mut Codomain::Element, rhs: &Domain::Element) {
self.codomain().mul_assign(lhs, self.map_ref(rhs))
}
fn mul_map(&self, mut lhs: Codomain::Element, rhs: Domain::Element) -> Codomain::Element {
self.mul_assign_map(&mut lhs, rhs);
lhs
}
fn fma_map(&self, lhs: &Codomain::Element, rhs: &Domain::Element, summand: Codomain::Element) -> Codomain::Element {
self.codomain().add(summand, self.mul_ref_map(lhs, rhs))
}
fn mul_ref_fst_map(&self, lhs: &Codomain::Element, rhs: Domain::Element) -> Codomain::Element {
self.mul_map(self.codomain().clone_el(lhs), rhs)
}
fn mul_ref_snd_map(&self, mut lhs: Codomain::Element, rhs: &Domain::Element) -> Codomain::Element {
self.mul_assign_ref_map(&mut lhs, rhs);
lhs
}
fn mul_ref_map(&self, lhs: &Codomain::Element, rhs: &Domain::Element) -> Codomain::Element {
self.mul_ref_snd_map(self.codomain().clone_el(lhs), rhs)
}
fn compose<F, PrevDomain: ?Sized + RingBase>(self, prev: F) -> ComposedHom<PrevDomain, Domain, Codomain, F, Self>
where
Self: Sized,
F: Homomorphism<PrevDomain, Domain>,
{
assert!(prev.codomain().get_ring() == self.domain().get_ring());
ComposedHom {
f: prev,
g: self,
domain: PhantomData,
intermediate: PhantomData,
codomain: PhantomData,
}
}
#[stability::unstable(feature = "enable")]
fn mul_assign_ref_map_through_hom<First: ?Sized + RingBase, H: Homomorphism<First, Domain>>(
&self,
lhs: &mut Codomain::Element,
rhs: &First::Element,
hom: H,
) {
self.mul_assign_map(lhs, hom.map_ref(rhs));
}
#[stability::unstable(feature = "enable")]
fn mul_assign_map_through_hom<First: ?Sized + RingBase, H: Homomorphism<First, Domain>>(
&self,
lhs: &mut Codomain::Element,
rhs: First::Element,
hom: H,
) {
self.mul_assign_map(lhs, hom.map(rhs));
}
}
pub trait CanHomFrom<S>: RingBase
where
S: RingBase + ?Sized,
{
type Homomorphism;
fn has_canonical_hom(&self, from: &S) -> Option<Self::Homomorphism>;
fn map_in(&self, from: &S, el: S::Element, hom: &Self::Homomorphism) -> Self::Element;
fn map_in_ref(&self, from: &S, el: &S::Element, hom: &Self::Homomorphism) -> Self::Element {
self.map_in(from, from.clone_el(el), hom)
}
fn mul_assign_map_in(&self, from: &S, lhs: &mut Self::Element, rhs: S::Element, hom: &Self::Homomorphism) {
self.mul_assign(lhs, self.map_in(from, rhs, hom));
}
fn mul_assign_map_in_ref(&self, from: &S, lhs: &mut Self::Element, rhs: &S::Element, hom: &Self::Homomorphism) {
self.mul_assign(lhs, self.map_in_ref(from, rhs, hom));
}
fn fma_map_in(
&self,
from: &S,
lhs: &Self::Element,
rhs: &S::Element,
summand: Self::Element,
hom: &Self::Homomorphism,
) -> Self::Element {
let mut lhs_copy = self.clone_el(lhs);
self.mul_assign_map_in_ref(from, &mut lhs_copy, rhs, hom);
return self.add(lhs_copy, summand);
}
}
pub trait CanIsoFromTo<S>: CanHomFrom<S>
where
S: RingBase + ?Sized,
{
type Isomorphism;
fn has_canonical_iso(&self, from: &S) -> Option<Self::Isomorphism>;
fn map_out(&self, from: &S, el: Self::Element, iso: &Self::Isomorphism) -> S::Element;
}
pub trait SelfIso: CanIsoFromTo<Self> {}
impl<R: ?Sized + CanIsoFromTo<R>> SelfIso for R {}
pub struct CanHom<R, S>
where
R: RingStore,
S: RingStore,
S::Type: CanHomFrom<R::Type>,
{
from: R,
to: S,
data: <S::Type as CanHomFrom<R::Type>>::Homomorphism,
}
impl<R, S> Debug for CanHom<R, S>
where
R: RingStore + Debug,
S: RingStore + Debug,
S::Type: CanHomFrom<R::Type>,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CanHom")
.field("from", &self.from)
.field("to", &self.to)
.finish()
}
}
impl<R, S> CanHom<R, S>
where
R: RingStore,
S: RingStore,
S::Type: CanHomFrom<R::Type>,
{
pub fn new(from: R, to: S) -> Result<Self, (R, S)> {
match to.get_ring().has_canonical_hom(from.get_ring()) {
Some(data) => Ok(Self::from_raw_parts(from, to, data)),
_ => Err((from, to)),
}
}
pub fn raw_hom(&self) -> &<S::Type as CanHomFrom<R::Type>>::Homomorphism { &self.data }
pub fn into_raw_hom(self) -> <S::Type as CanHomFrom<R::Type>>::Homomorphism { self.data }
#[stability::unstable(feature = "enable")]
pub fn from_raw_parts(from: R, to: S, data: <S::Type as CanHomFrom<R::Type>>::Homomorphism) -> Self {
Self { from, to, data }
}
}
impl<R, S> Clone for CanHom<R, S>
where
R: RingStore + Clone,
S: RingStore + Clone,
S::Type: CanHomFrom<R::Type>,
{
fn clone(&self) -> Self { Self::new(self.from.clone(), self.to.clone()).ok().unwrap() }
}
impl<R, S> Homomorphism<R::Type, S::Type> for CanHom<R, S>
where
R: RingStore,
S: RingStore,
S::Type: CanHomFrom<R::Type>,
{
type CodomainStore = S;
type DomainStore = R;
fn map(&self, el: El<R>) -> El<S> { self.to.get_ring().map_in(self.from.get_ring(), el, &self.data) }
fn map_ref(&self, el: &El<R>) -> El<S> { self.to.get_ring().map_in_ref(self.from.get_ring(), el, &self.data) }
fn domain(&self) -> &R { &self.from }
fn codomain(&self) -> &S { &self.to }
fn mul_assign_map(&self, lhs: &mut El<S>, rhs: El<R>) {
self.to
.get_ring()
.mul_assign_map_in(self.from.get_ring(), lhs, rhs, &self.data);
}
fn mul_assign_ref_map(&self, lhs: &mut El<S>, rhs: &El<R>) {
self.to
.get_ring()
.mul_assign_map_in_ref(self.from.get_ring(), lhs, rhs, &self.data);
}
fn fma_map(&self, lhs: &El<S>, rhs: &El<R>, summand: El<S>) -> El<S> {
self.to
.get_ring()
.fma_map_in(self.from.get_ring(), lhs, rhs, summand, &self.data)
}
}
#[stability::unstable(feature = "enable")]
pub struct CanHomRef<'a, R, S>
where
R: RingStore,
S: RingStore,
S::Type: CanHomFrom<R::Type>,
{
from: R,
to: S,
data: &'a <S::Type as CanHomFrom<R::Type>>::Homomorphism,
}
impl<'a, R, S> CanHomRef<'a, R, S>
where
R: RingStore,
S: RingStore,
S::Type: CanHomFrom<R::Type>,
{
#[stability::unstable(feature = "enable")]
pub fn raw_hom(&self) -> &<S::Type as CanHomFrom<R::Type>>::Homomorphism { &self.data }
#[stability::unstable(feature = "enable")]
pub fn from_raw_parts(from: R, to: S, data: &'a <S::Type as CanHomFrom<R::Type>>::Homomorphism) -> Self {
Self { from, to, data }
}
}
impl<'a, R, S> Clone for CanHomRef<'a, R, S>
where
R: RingStore + Clone,
S: RingStore + Clone,
S::Type: CanHomFrom<R::Type>,
{
fn clone(&self) -> Self { Self::from_raw_parts(self.from.clone(), self.to.clone(), self.data) }
}
impl<'a, R, S> Copy for CanHomRef<'a, R, S>
where
R: RingStore + Copy,
S: RingStore + Copy,
S::Type: CanHomFrom<R::Type>,
El<R>: Copy,
El<S>: Copy,
{
}
impl<'a, R, S> Homomorphism<R::Type, S::Type> for CanHomRef<'a, R, S>
where
R: RingStore,
S: RingStore,
S::Type: CanHomFrom<R::Type>,
{
type CodomainStore = S;
type DomainStore = R;
fn map(&self, el: El<R>) -> El<S> { self.to.get_ring().map_in(self.from.get_ring(), el, self.data) }
fn map_ref(&self, el: &El<R>) -> El<S> { self.to.get_ring().map_in_ref(self.from.get_ring(), el, self.data) }
fn domain(&self) -> &R { &self.from }
fn codomain(&self) -> &S { &self.to }
fn mul_assign_map(&self, lhs: &mut El<S>, rhs: El<R>) {
self.to
.get_ring()
.mul_assign_map_in(self.from.get_ring(), lhs, rhs, self.data);
}
fn mul_assign_ref_map(&self, lhs: &mut El<S>, rhs: &El<R>) {
self.to
.get_ring()
.mul_assign_map_in_ref(self.from.get_ring(), lhs, rhs, self.data);
}
fn fma_map(&self, lhs: &El<S>, rhs: &El<R>, summand: El<S>) -> El<S> {
self.to
.get_ring()
.fma_map_in(self.from.get_ring(), lhs, rhs, summand, self.data)
}
}
pub struct CanIso<R, S>
where
R: RingStore,
S: RingStore,
S::Type: CanIsoFromTo<R::Type>,
{
from: R,
to: S,
data: <S::Type as CanIsoFromTo<R::Type>>::Isomorphism,
}
impl<R, S> Debug for CanIso<R, S>
where
R: RingStore + Debug,
S: RingStore + Debug,
S::Type: CanIsoFromTo<R::Type>,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CanIso")
.field("from", &self.from)
.field("to", &self.to)
.finish()
}
}
impl<R, S> Clone for CanIso<R, S>
where
R: RingStore + Clone,
S: RingStore + Clone,
S::Type: CanIsoFromTo<R::Type>,
{
fn clone(&self) -> Self { Self::new(self.from.clone(), self.to.clone()).ok().unwrap() }
}
impl<R, S> CanIso<R, S>
where
R: RingStore,
S: RingStore,
S::Type: CanIsoFromTo<R::Type>,
{
pub fn new(from: R, to: S) -> Result<Self, (R, S)> {
match to.get_ring().has_canonical_iso(from.get_ring()) {
Some(data) => {
assert!(to.get_ring().has_canonical_hom(from.get_ring()).is_some());
Ok(Self { from, to, data })
}
_ => Err((from, to)),
}
}
pub fn into_inv(self) -> CanHom<R, S> { CanHom::new(self.from, self.to).unwrap_or_else(|_| unreachable!()) }
pub fn inv(&self) -> CanHom<&R, &S> { CanHom::new(&self.from, &self.to).unwrap_or_else(|_| unreachable!()) }
pub fn raw_iso(&self) -> &<S::Type as CanIsoFromTo<R::Type>>::Isomorphism { &self.data }
pub fn into_raw_iso(self) -> <S::Type as CanIsoFromTo<R::Type>>::Isomorphism { self.data }
}
impl<R, S> Homomorphism<S::Type, R::Type> for CanIso<R, S>
where
R: RingStore,
S: RingStore,
S::Type: CanIsoFromTo<R::Type>,
{
type DomainStore = S;
type CodomainStore = R;
fn map(&self, x: El<S>) -> El<R> { self.to.get_ring().map_out(self.from.get_ring(), x, &self.data) }
fn domain(&self) -> &S { &self.to }
fn codomain(&self) -> &R { &self.from }
}
#[derive(Clone, Debug)]
pub struct Inclusion<R>
where
R: RingStore,
R::Type: RingExtension,
{
ring: R,
}
impl<R: RingStore> Copy for Inclusion<R>
where
R: Copy,
El<R>: Copy,
R::Type: RingExtension,
{
}
impl<R> Inclusion<R>
where
R: RingStore,
R::Type: RingExtension,
{
pub fn new(ring: R) -> Self { Inclusion { ring } }
}
impl<R> Homomorphism<<<R::Type as RingExtension>::BaseRing as RingStore>::Type, R::Type> for Inclusion<R>
where
R: RingStore,
R::Type: RingExtension,
{
type CodomainStore = R;
type DomainStore = <R::Type as RingExtension>::BaseRing;
fn domain(&self) -> &Self::DomainStore { self.ring.base_ring() }
fn codomain(&self) -> &Self::CodomainStore { &self.ring }
fn map(&self, x: El<<R::Type as RingExtension>::BaseRing>) -> El<R> { self.ring.get_ring().from(x) }
fn map_ref(&self, x: &El<<R::Type as RingExtension>::BaseRing>) -> El<R> { self.ring.get_ring().from_ref(x) }
fn mul_assign_ref_map(&self, lhs: &mut El<R>, rhs: &El<<R::Type as RingExtension>::BaseRing>) {
self.ring.get_ring().mul_assign_base(lhs, rhs)
}
fn mul_assign_map(&self, lhs: &mut El<R>, rhs: El<<R::Type as RingExtension>::BaseRing>) {
self.mul_assign_ref_map(lhs, &rhs)
}
fn mul_assign_map_through_hom<
First: ?Sized + RingBase,
H: Homomorphism<First, <<R::Type as RingExtension>::BaseRing as RingStore>::Type>,
>(
&self,
lhs: &mut El<R>,
rhs: First::Element,
hom: H,
) {
self.ring.get_ring().mul_assign_base_through_hom(lhs, &rhs, hom)
}
fn mul_assign_ref_map_through_hom<
First: ?Sized + RingBase,
H: Homomorphism<First, <<R::Type as RingExtension>::BaseRing as RingStore>::Type>,
>(
&self,
lhs: &mut El<R>,
rhs: &First::Element,
hom: H,
) {
self.ring.get_ring().mul_assign_base_through_hom(lhs, rhs, hom)
}
fn fma_map(&self, lhs: &El<R>, rhs: &El<<R::Type as RingExtension>::BaseRing>, summand: El<R>) -> El<R> {
self.ring.get_ring().fma_base(lhs, rhs, summand)
}
}
#[derive(Clone)]
pub struct IntHom<R>
where
R: RingStore,
{
ring: R,
}
impl<R: RingStore> Copy for IntHom<R>
where
R: Copy,
El<R>: Copy,
{
}
impl<R> Homomorphism<StaticRingBase<i32>, R::Type> for IntHom<R>
where
R: RingStore,
{
type CodomainStore = R;
type DomainStore = StaticRing<i32>;
fn domain(&self) -> &Self::DomainStore { &StaticRing::<i32>::RING }
fn codomain(&self) -> &Self::CodomainStore { &self.ring }
fn map(&self, x: i32) -> El<R> { self.ring.get_ring().from_int(x) }
fn mul_assign_map(&self, lhs: &mut El<R>, rhs: i32) { self.ring.get_ring().mul_assign_int(lhs, rhs) }
fn mul_assign_ref_map(&self, lhs: &mut El<R>, rhs: &<StaticRingBase<i32> as RingBase>::Element) {
self.mul_assign_map(lhs, *rhs)
}
fn fma_map(&self, lhs: &El<R>, rhs: &i32, summand: El<R>) -> El<R> {
self.ring.get_ring().fma_int(lhs, *rhs, summand)
}
}
impl<R> IntHom<R>
where
R: RingStore,
{
pub fn new(ring: R) -> Self { Self { ring } }
}
#[derive(Clone)]
pub struct Identity<R: RingStore> {
ring: R,
}
impl<R: RingStore> Copy for Identity<R>
where
R: Copy,
El<R>: Copy,
{
}
impl<R: RingStore> Identity<R> {
pub fn new(ring: R) -> Self { Identity { ring } }
}
impl<R: RingStore> Homomorphism<R::Type, R::Type> for Identity<R> {
type CodomainStore = R;
type DomainStore = R;
fn codomain(&self) -> &Self::CodomainStore { &self.ring }
fn domain(&self) -> &Self::DomainStore { &self.ring }
fn map(&self, x: El<R>) -> El<R> { x }
fn mul_assign_map_through_hom<First: ?Sized + RingBase, H: Homomorphism<First, R::Type>>(
&self,
lhs: &mut El<R>,
rhs: First::Element,
hom: H,
) {
hom.mul_assign_map(lhs, rhs);
}
fn mul_assign_ref_map_through_hom<First: ?Sized + RingBase, H: Homomorphism<First, R::Type>>(
&self,
lhs: &mut El<R>,
rhs: &First::Element,
hom: H,
) {
hom.mul_assign_ref_map(lhs, rhs);
}
fn fma_map(&self, lhs: &El<R>, rhs: &El<R>, summand: El<R>) -> El<R> { self.ring.get_ring().fma(lhs, rhs, summand) }
}
impl<S, R, H> Homomorphism<S, R> for &H
where
S: ?Sized + RingBase,
R: ?Sized + RingBase,
H: Homomorphism<S, R>,
{
type CodomainStore = H::CodomainStore;
type DomainStore = H::DomainStore;
fn codomain(&self) -> &Self::CodomainStore { (*self).codomain() }
fn domain(&self) -> &Self::DomainStore { (*self).domain() }
fn map(&self, x: <S as RingBase>::Element) -> <R as RingBase>::Element { (*self).map(x) }
fn map_ref(&self, x: &<S as RingBase>::Element) -> <R as RingBase>::Element { (*self).map_ref(x) }
fn mul_assign_map(&self, lhs: &mut <R as RingBase>::Element, rhs: <S as RingBase>::Element) {
(*self).mul_assign_map(lhs, rhs)
}
fn mul_assign_ref_map(&self, lhs: &mut <R as RingBase>::Element, rhs: &<S as RingBase>::Element) {
(*self).mul_assign_ref_map(lhs, rhs)
}
fn fma_map(
&self,
lhs: &<R as RingBase>::Element,
rhs: &<S as RingBase>::Element,
summand: <R as RingBase>::Element,
) -> <R as RingBase>::Element {
(*self).fma_map(lhs, rhs, summand)
}
}
#[derive(Clone)]
pub struct LambdaHom<R: RingStore, S: RingStore, F>
where
F: Fn(&R, &S, &El<R>) -> El<S>,
{
from: R,
to: S,
f: F,
}
impl<R: RingStore, S: RingStore, F> Copy for LambdaHom<R, S, F>
where
F: Copy + Fn(&R, &S, &El<R>) -> El<S>,
R: Copy,
El<R>: Copy,
S: Copy,
El<S>: Copy,
{
}
impl<R: RingStore, S: RingStore, F> LambdaHom<R, S, F>
where
F: Fn(&R, &S, &El<R>) -> El<S>,
{
pub fn new(from: R, to: S, f: F) -> Self { Self { from, to, f } }
#[stability::unstable(feature = "enable")]
pub fn into_domain_codomain(self) -> (R, S) { (self.from, self.to) }
}
impl<R: RingStore, S: RingStore, F> Homomorphism<R::Type, S::Type> for LambdaHom<R, S, F>
where
F: Fn(&R, &S, &El<R>) -> El<S>,
{
type CodomainStore = S;
type DomainStore = R;
fn codomain(&self) -> &Self::CodomainStore { &self.to }
fn domain(&self) -> &Self::DomainStore { &self.from }
fn map(&self, x: El<R>) -> <S::Type as RingBase>::Element { (self.f)(self.domain(), self.codomain(), &x) }
fn map_ref(&self, x: &El<R>) -> <S::Type as RingBase>::Element { (self.f)(self.domain(), self.codomain(), x) }
}
pub struct ComposedHom<R, S, T, F, G>
where
F: Homomorphism<R, S>,
G: Homomorphism<S, T>,
R: ?Sized + RingBase,
S: ?Sized + RingBase,
T: ?Sized + RingBase,
{
f: F,
g: G,
domain: PhantomData<R>,
intermediate: PhantomData<S>,
codomain: PhantomData<T>,
}
impl<R, S, T, F, G> ComposedHom<R, S, T, F, G>
where
F: Clone + Homomorphism<R, S>,
G: Clone + Homomorphism<S, T>,
R: ?Sized + RingBase,
S: ?Sized + RingBase,
T: ?Sized + RingBase,
{
#[stability::unstable(feature = "enable")]
pub fn first(&self) -> &F { &self.f }
#[stability::unstable(feature = "enable")]
pub fn second(&self) -> &G { &self.g }
}
impl<R, S, T, F, G> Clone for ComposedHom<R, S, T, F, G>
where
F: Clone + Homomorphism<R, S>,
G: Clone + Homomorphism<S, T>,
R: ?Sized + RingBase,
S: ?Sized + RingBase,
T: ?Sized + RingBase,
{
fn clone(&self) -> Self {
Self {
f: self.f.clone(),
g: self.g.clone(),
domain: PhantomData,
codomain: PhantomData,
intermediate: PhantomData,
}
}
}
impl<R, S, T, F, G> Copy for ComposedHom<R, S, T, F, G>
where
F: Copy + Homomorphism<R, S>,
G: Copy + Homomorphism<S, T>,
R: ?Sized + RingBase,
S: ?Sized + RingBase,
T: ?Sized + RingBase,
{
}
impl<R, S, T, F, G> Homomorphism<R, T> for ComposedHom<R, S, T, F, G>
where
F: Homomorphism<R, S>,
G: Homomorphism<S, T>,
R: ?Sized + RingBase,
S: ?Sized + RingBase,
T: ?Sized + RingBase,
{
type DomainStore = <F as Homomorphism<R, S>>::DomainStore;
type CodomainStore = <G as Homomorphism<S, T>>::CodomainStore;
fn domain(&self) -> &Self::DomainStore { self.f.domain() }
fn codomain(&self) -> &Self::CodomainStore { self.g.codomain() }
fn map(&self, x: <R as RingBase>::Element) -> <T as RingBase>::Element { self.g.map(self.f.map(x)) }
fn map_ref(&self, x: &<R as RingBase>::Element) -> <T as RingBase>::Element { self.g.map(self.f.map_ref(x)) }
fn mul_assign_map(&self, lhs: &mut <T as RingBase>::Element, rhs: <R as RingBase>::Element) {
self.g.mul_assign_map_through_hom(lhs, rhs, &self.f)
}
fn mul_assign_ref_map(&self, lhs: &mut <T as RingBase>::Element, rhs: &<R as RingBase>::Element) {
self.g.mul_assign_ref_map_through_hom(lhs, rhs, &self.f)
}
fn fma_map(
&self,
lhs: &<T as RingBase>::Element,
rhs: &<R as RingBase>::Element,
summand: <T as RingBase>::Element,
) -> <T as RingBase>::Element {
self.g.fma_map(lhs, &self.f.map_ref(rhs), summand)
}
}
#[macro_export]
macro_rules! impl_eq_based_self_iso {
($type:ty) => {
impl $crate::homomorphism::CanHomFrom<Self> for $type {
type Homomorphism = ();
fn has_canonical_hom(&self, from: &Self) -> Option<()> { if self == from { Some(()) } else { None } }
fn map_in(
&self,
_from: &Self,
el: <Self as $crate::ring::RingBase>::Element,
_: &Self::Homomorphism,
) -> <Self as $crate::ring::RingBase>::Element {
el
}
}
impl $crate::homomorphism::CanIsoFromTo<Self> for $type {
type Isomorphism = ();
fn has_canonical_iso(&self, from: &Self) -> Option<()> { if self == from { Some(()) } else { None } }
fn map_out(
&self,
_from: &Self,
el: <Self as $crate::ring::RingBase>::Element,
_: &Self::Homomorphism,
) -> <Self as $crate::ring::RingBase>::Element {
el
}
}
};
}
#[cfg(any(test, feature = "generic_tests"))]
pub mod generic_tests {
use super::*;
pub fn test_homomorphism_axioms<R: ?Sized + RingBase, S: ?Sized + RingBase, H, I: Iterator<Item = R::Element>>(
hom: H,
edge_case_elements: I,
) where
H: Homomorphism<R, S>,
{
let from = hom.domain();
let to = hom.codomain();
let elements = edge_case_elements.collect::<Vec<_>>();
assert!(to.is_zero(&hom.map(from.zero())));
assert!(to.is_one(&hom.map(from.one())));
for a in &elements {
for b in &elements {
{
let map_a = hom.map_ref(a);
let map_b = hom.map_ref(b);
let map_sum = to.add_ref(&map_a, &map_b);
let sum_map = hom.map(from.add_ref(a, b));
assert!(
to.eq_el(&map_sum, &sum_map),
"Additive homomorphic property failed: hom({} + {}) = {} != {} = {} + {}",
from.format(a),
from.format(b),
to.format(&sum_map),
to.format(&map_sum),
to.format(&map_a),
to.format(&map_b)
);
}
{
let map_a = hom.map_ref(a);
let map_b = hom.map_ref(b);
let map_prod = to.mul_ref(&map_a, &map_b);
let prod_map = hom.map(from.mul_ref(a, b));
assert!(
to.eq_el(&map_prod, &prod_map),
"Multiplicative homomorphic property failed: hom({} * {}) = {} != {} = {} * {}",
from.format(a),
from.format(b),
to.format(&prod_map),
to.format(&map_prod),
to.format(&map_a),
to.format(&map_b)
);
}
{
let map_a = hom.map_ref(a);
let prod_map = hom.map(from.mul_ref(a, b));
let mut mul_assign = to.clone_el(&map_a);
hom.mul_assign_ref_map(&mut mul_assign, b);
assert!(
to.eq_el(&mul_assign, &prod_map),
"mul_assign_ref_map() failed: hom({} * {}) = {} != {} = mul_map_in(hom({}), {})",
from.format(a),
from.format(b),
to.format(&prod_map),
to.format(&mul_assign),
to.format(&map_a),
from.format(b)
);
}
}
}
}
}