use std::ops::Deref;
use serde::{Deserialize, Serialize};
use crate::algorithms;
use crate::homomorphism::*;
use crate::integer::*;
use crate::ordered::OrderedRingStore;
use crate::primitive_int::StaticRing;
#[derive(PartialEq, Eq, Debug, Clone, Copy, PartialOrd, Ord)]
pub enum EnvBindingStrength {
Weakest,
Sum,
Product,
Power,
Strongest,
}
#[allow(missing_docs)]
pub trait RingBase: PartialEq {
type Element: Sized;
fn clone_el(&self, val: &Self::Element) -> Self::Element;
fn add_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) { self.add_assign(lhs, self.clone_el(rhs)) }
fn add_assign(&self, lhs: &mut Self::Element, rhs: Self::Element);
fn sub_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) { self.sub_assign(lhs, self.clone_el(rhs)) }
fn negate_inplace(&self, lhs: &mut Self::Element);
fn mul_assign(&self, lhs: &mut Self::Element, rhs: Self::Element);
fn mul_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) { self.mul_assign(lhs, self.clone_el(rhs)) }
fn zero(&self) -> Self::Element { self.from_int(0) }
fn one(&self) -> Self::Element { self.from_int(1) }
fn neg_one(&self) -> Self::Element { self.from_int(-1) }
fn from_int(&self, value: i32) -> Self::Element;
fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool;
fn is_zero(&self, value: &Self::Element) -> bool { self.eq_el(value, &self.zero()) }
fn is_one(&self, value: &Self::Element) -> bool { self.eq_el(value, &self.one()) }
fn is_neg_one(&self, value: &Self::Element) -> bool { self.eq_el(value, &self.neg_one()) }
fn fma(&self, lhs: &Self::Element, rhs: &Self::Element, summand: Self::Element) -> Self::Element {
self.add(summand, self.mul_ref(lhs, rhs))
}
fn is_commutative(&self) -> bool;
fn is_noetherian(&self) -> bool;
fn is_approximate(&self) -> bool;
fn dbg<'a>(&self, value: &Self::Element, out: &mut std::fmt::Formatter<'a>) -> std::fmt::Result {
self.dbg_within(value, out, EnvBindingStrength::Weakest)
}
fn dbg_within<'a>(
&self,
value: &Self::Element,
out: &mut std::fmt::Formatter<'a>,
_env: EnvBindingStrength,
) -> std::fmt::Result;
fn square(&self, value: &mut Self::Element) { self.mul_assign(value, self.clone_el(value)); }
fn negate(&self, mut value: Self::Element) -> Self::Element {
self.negate_inplace(&mut value);
return value;
}
fn sub_assign(&self, lhs: &mut Self::Element, mut rhs: Self::Element) {
self.negate_inplace(&mut rhs);
self.add_assign(lhs, rhs);
}
fn mul_assign_int(&self, lhs: &mut Self::Element, rhs: i32) { self.mul_assign(lhs, self.from_int(rhs)); }
fn mul_int(&self, mut lhs: Self::Element, rhs: i32) -> Self::Element {
self.mul_assign_int(&mut lhs, rhs);
return lhs;
}
fn mul_int_ref(&self, lhs: &Self::Element, rhs: i32) -> Self::Element { self.mul_int(self.clone_el(lhs), rhs) }
fn fma_int(&self, lhs: &Self::Element, rhs: i32, summand: Self::Element) -> Self::Element {
self.add(summand, self.mul_int_ref(lhs, rhs))
}
fn sub_self_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) {
self.negate_inplace(lhs);
self.add_assign(lhs, rhs);
}
fn sub_self_assign_ref(&self, lhs: &mut Self::Element, rhs: &Self::Element) {
self.negate_inplace(lhs);
self.add_assign_ref(lhs, rhs);
}
fn add_ref(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
let mut result = self.clone_el(lhs);
self.add_assign_ref(&mut result, rhs);
return result;
}
fn add_ref_fst(&self, lhs: &Self::Element, mut rhs: Self::Element) -> Self::Element {
self.add_assign_ref(&mut rhs, lhs);
return rhs;
}
fn add_ref_snd(&self, mut lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
self.add_assign_ref(&mut lhs, rhs);
return lhs;
}
fn add(&self, mut lhs: Self::Element, rhs: Self::Element) -> Self::Element {
self.add_assign(&mut lhs, rhs);
return lhs;
}
fn sub_ref(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
let mut result = self.clone_el(lhs);
self.sub_assign_ref(&mut result, rhs);
return result;
}
fn sub_ref_fst(&self, lhs: &Self::Element, mut rhs: Self::Element) -> Self::Element {
self.sub_assign_ref(&mut rhs, lhs);
self.negate_inplace(&mut rhs);
return rhs;
}
fn sub_ref_snd(&self, mut lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
self.sub_assign_ref(&mut lhs, rhs);
return lhs;
}
fn sub(&self, mut lhs: Self::Element, rhs: Self::Element) -> Self::Element {
self.sub_assign(&mut lhs, rhs);
return lhs;
}
fn mul_ref(&self, lhs: &Self::Element, rhs: &Self::Element) -> Self::Element {
let mut result = self.clone_el(lhs);
self.mul_assign_ref(&mut result, rhs);
return result;
}
fn mul_ref_fst(&self, lhs: &Self::Element, mut rhs: Self::Element) -> Self::Element {
if self.is_commutative() {
self.mul_assign_ref(&mut rhs, lhs);
return rhs;
} else {
let mut result = self.clone_el(lhs);
self.mul_assign(&mut result, rhs);
return result;
}
}
fn mul_ref_snd(&self, mut lhs: Self::Element, rhs: &Self::Element) -> Self::Element {
self.mul_assign_ref(&mut lhs, rhs);
return lhs;
}
fn mul(&self, mut lhs: Self::Element, rhs: Self::Element) -> Self::Element {
self.mul_assign(&mut lhs, rhs);
return lhs;
}
fn pow_gen<R: RingStore>(&self, x: Self::Element, power: &El<R>, integers: R) -> Self::Element
where
R::Type: IntegerRing,
{
assert!(!integers.is_neg(power));
algorithms::sqr_mul::generic_pow_shortest_chain_table(
x,
power,
&integers,
|a| {
let mut a_copy = self.clone_el(a);
self.square(&mut a_copy);
Ok(a_copy)
},
|a, b| Ok(self.mul_ref(a, b)),
|a| self.clone_el(a),
self.one(),
)
.unwrap_or_else(|x| x)
}
fn sum<I>(&self, els: I) -> Self::Element
where
I: IntoIterator<Item = Self::Element>,
{
els.into_iter().fold(self.zero(), |a, b| self.add(a, b))
}
fn prod<I>(&self, els: I) -> Self::Element
where
I: IntoIterator<Item = Self::Element>,
{
els.into_iter().fold(self.one(), |a, b| self.mul(a, b))
}
fn characteristic<I: RingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
where
I::Type: IntegerRing;
}
#[macro_export]
macro_rules! delegate {
($base_trait:ty, fn $name:ident (&self, $($pname:ident: $ptype:ty),*) -> $rtype:ty) => {
#[doc = concat!(" See [`", stringify!($base_trait), "::", stringify!($name), "()`]")]
fn $name (&self, $($pname: $ptype),*) -> $rtype {
<Self::Type as $base_trait>::$name(self.get_ring(), $($pname),*)
}
};
($base_trait:ty, fn $name:ident (&self) -> $rtype:ty) => {
#[doc = concat!(" See [`", stringify!($base_trait), "::", stringify!($name), "()`]")]
fn $name (&self) -> $rtype {
<Self::Type as $base_trait>::$name(self.get_ring())
}
};
}
#[macro_export]
macro_rules! assert_el_eq {
($ring:expr,$lhs:expr,$rhs:expr) => {
match (&$ring, &$lhs, &$rhs) {
(ring_val, lhs_val, rhs_val) => {
assert!(
<_ as $crate::ring::RingStore>::eq_el(ring_val, lhs_val, rhs_val),
"Assertion failed: {} != {}",
<_ as $crate::ring::RingStore>::format(ring_val, lhs_val),
<_ as $crate::ring::RingStore>::format(ring_val, rhs_val)
);
}
}
};
}
pub trait RingStore: Sized {
type Type: RingBase + ?Sized;
fn get_ring(&self) -> &Self::Type;
delegate! { RingBase, fn clone_el(&self, val: &El<Self>) -> El<Self> }
delegate! { RingBase, fn add_assign_ref(&self, lhs: &mut El<Self>, rhs: &El<Self>) -> () }
delegate! { RingBase, fn add_assign(&self, lhs: &mut El<Self>, rhs: El<Self>) -> () }
delegate! { RingBase, fn sub_assign_ref(&self, lhs: &mut El<Self>, rhs: &El<Self>) -> () }
delegate! { RingBase, fn sub_self_assign(&self, lhs: &mut El<Self>, rhs: El<Self>) -> () }
delegate! { RingBase, fn sub_self_assign_ref(&self, lhs: &mut El<Self>, rhs: &El<Self>) -> () }
delegate! { RingBase, fn negate_inplace(&self, lhs: &mut El<Self>) -> () }
delegate! { RingBase, fn mul_assign(&self, lhs: &mut El<Self>, rhs: El<Self>) -> () }
delegate! { RingBase, fn mul_assign_ref(&self, lhs: &mut El<Self>, rhs: &El<Self>) -> () }
delegate! { RingBase, fn zero(&self) -> El<Self> }
delegate! { RingBase, fn one(&self) -> El<Self> }
delegate! { RingBase, fn neg_one(&self) -> El<Self> }
delegate! { RingBase, fn eq_el(&self, lhs: &El<Self>, rhs: &El<Self>) -> bool }
delegate! { RingBase, fn is_zero(&self, value: &El<Self>) -> bool }
delegate! { RingBase, fn is_one(&self, value: &El<Self>) -> bool }
delegate! { RingBase, fn is_neg_one(&self, value: &El<Self>) -> bool }
delegate! { RingBase, fn is_commutative(&self) -> bool }
delegate! { RingBase, fn is_noetherian(&self) -> bool }
delegate! { RingBase, fn negate(&self, value: El<Self>) -> El<Self> }
delegate! { RingBase, fn sub_assign(&self, lhs: &mut El<Self>, rhs: El<Self>) -> () }
delegate! { RingBase, fn add_ref(&self, lhs: &El<Self>, rhs: &El<Self>) -> El<Self> }
delegate! { RingBase, fn add_ref_fst(&self, lhs: &El<Self>, rhs: El<Self>) -> El<Self> }
delegate! { RingBase, fn add_ref_snd(&self, lhs: El<Self>, rhs: &El<Self>) -> El<Self> }
delegate! { RingBase, fn add(&self, lhs: El<Self>, rhs: El<Self>) -> El<Self> }
delegate! { RingBase, fn sub_ref(&self, lhs: &El<Self>, rhs: &El<Self>) -> El<Self> }
delegate! { RingBase, fn sub_ref_fst(&self, lhs: &El<Self>, rhs: El<Self>) -> El<Self> }
delegate! { RingBase, fn sub_ref_snd(&self, lhs: El<Self>, rhs: &El<Self>) -> El<Self> }
delegate! { RingBase, fn sub(&self, lhs: El<Self>, rhs: El<Self>) -> El<Self> }
delegate! { RingBase, fn mul_ref(&self, lhs: &El<Self>, rhs: &El<Self>) -> El<Self> }
delegate! { RingBase, fn mul_ref_fst(&self, lhs: &El<Self>, rhs: El<Self>) -> El<Self> }
delegate! { RingBase, fn mul_ref_snd(&self, lhs: El<Self>, rhs: &El<Self>) -> El<Self> }
delegate! { RingBase, fn mul(&self, lhs: El<Self>, rhs: El<Self>) -> El<Self> }
delegate! { RingBase, fn square(&self, value: &mut El<Self>) -> () }
delegate! { RingBase, fn fma(&self, lhs: &El<Self>, rhs: &El<Self>, summand: El<Self>) -> El<Self> }
fn coerce<S>(&self, from: &S, el: El<S>) -> El<Self>
where
S: RingStore,
Self::Type: CanHomFrom<S::Type>,
{
self.get_ring().map_in(
from.get_ring(),
el,
&self.get_ring().has_canonical_hom(from.get_ring()).unwrap(),
)
}
fn into_identity(self) -> Identity<Self> { Identity::new(self) }
fn identity(&self) -> Identity<&Self> { self.into_identity() }
fn into_can_hom<S>(self, from: S) -> Result<CanHom<S, Self>, (S, Self)>
where
Self: Sized,
S: RingStore,
Self::Type: CanHomFrom<S::Type>,
{
CanHom::new(from, self)
}
fn into_can_iso<S>(self, from: S) -> Result<CanIso<S, Self>, (S, Self)>
where
Self: Sized,
S: RingStore,
Self::Type: CanIsoFromTo<S::Type>,
{
CanIso::new(from, self)
}
fn can_hom<'a, S>(&'a self, from: &'a S) -> Option<CanHom<&'a S, &'a Self>>
where
S: RingStore,
Self::Type: CanHomFrom<S::Type>,
{
self.into_can_hom(from).ok()
}
fn can_iso<'a, S>(&'a self, from: &'a S) -> Option<CanIso<&'a S, &'a Self>>
where
S: RingStore,
Self::Type: CanIsoFromTo<S::Type>,
{
self.into_can_iso(from).ok()
}
fn into_int_hom(self) -> IntHom<Self> { IntHom::new(self) }
fn int_hom(&self) -> IntHom<&Self> { self.into_int_hom() }
fn sum<I>(&self, els: I) -> El<Self>
where
I: IntoIterator<Item = El<Self>>,
{
self.get_ring().sum(els)
}
#[stability::unstable(feature = "enable")]
fn try_sum<I, E>(&self, els: I) -> Result<El<Self>, E>
where
I: IntoIterator<Item = Result<El<Self>, E>>,
{
let mut error = None;
let result = self.get_ring().sum(els.into_iter().map_while(|el| match el {
Ok(el) => Some(el),
Err(err) => {
error = Some(err);
None
}
}));
if let Some(err) = error {
return Err(err);
} else {
return Ok(result);
}
}
fn prod<I>(&self, els: I) -> El<Self>
where
I: IntoIterator<Item = El<Self>>,
{
self.get_ring().prod(els)
}
fn pow(&self, mut x: El<Self>, power: usize) -> El<Self> {
if power == 0 {
return self.one();
} else if power == 1 {
return x;
} else if power == 2 {
self.square(&mut x);
return x;
}
self.pow_gen(x, &power.try_into().unwrap(), StaticRing::<i64>::RING)
}
fn pow_gen<R: RingStore>(&self, x: El<Self>, power: &El<R>, integers: R) -> El<Self>
where
R::Type: IntegerRing,
{
self.get_ring().pow_gen(x, power, integers)
}
fn format<'a>(&'a self, value: &'a El<Self>) -> RingElementDisplayWrapper<'a, Self> {
self.format_within(value, EnvBindingStrength::Weakest)
}
fn format_within<'a>(
&'a self,
value: &'a El<Self>,
within: EnvBindingStrength,
) -> RingElementDisplayWrapper<'a, Self> {
RingElementDisplayWrapper {
ring: self,
element: value,
within,
}
}
fn println(&self, value: &El<Self>) {
println!("{}", self.format(value));
}
fn characteristic<I: RingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
where
I::Type: IntegerRing,
{
self.get_ring().characteristic(ZZ)
}
}
pub trait RingExtensionStore: RingStore
where
Self::Type: RingExtension,
{
delegate! { RingExtension, fn base_ring(&self) -> &<Self::Type as RingExtension>::BaseRing }
fn into_inclusion(self) -> Inclusion<Self> { Inclusion::new(self) }
fn inclusion(&self) -> Inclusion<&Self> { self.into_inclusion() }
}
impl<R: RingStore> RingExtensionStore for R where R::Type: RingExtension {}
pub struct RingElementDisplayWrapper<'a, R: RingStore + ?Sized> {
ring: &'a R,
element: &'a El<R>,
within: EnvBindingStrength,
}
impl<'a, R: RingStore + ?Sized> std::fmt::Display for RingElementDisplayWrapper<'a, R> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.ring.get_ring().dbg_within(self.element, f, self.within)
}
}
impl<'a, R: RingStore + ?Sized> std::fmt::Debug for RingElementDisplayWrapper<'a, R> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.ring.get_ring().dbg_within(self.element, f, self.within)
}
}
pub trait RingExtension: RingBase {
type BaseRing: RingStore;
fn base_ring(&self) -> &Self::BaseRing;
fn from(&self, x: El<Self::BaseRing>) -> Self::Element;
fn from_ref(&self, x: &El<Self::BaseRing>) -> Self::Element { self.from(self.base_ring().get_ring().clone_el(x)) }
fn mul_assign_base(&self, lhs: &mut Self::Element, rhs: &El<Self::BaseRing>) {
self.mul_assign(lhs, self.from_ref(rhs));
}
fn fma_base(&self, lhs: &Self::Element, rhs: &El<Self::BaseRing>, summand: Self::Element) -> Self::Element {
let mut tmp = self.clone_el(lhs);
self.mul_assign_base(&mut tmp, rhs);
return self.add(summand, tmp);
}
#[stability::unstable(feature = "enable")]
fn mul_assign_base_through_hom<S: ?Sized + RingBase, H: Homomorphism<S, <Self::BaseRing as RingStore>::Type>>(
&self,
lhs: &mut Self::Element,
rhs: &S::Element,
hom: H,
) {
self.mul_assign_base(lhs, &hom.map_ref(rhs));
}
}
pub trait HashableElRing: RingBase {
fn hash<H: std::hash::Hasher>(&self, el: &Self::Element, h: &mut H);
}
pub trait HashableElRingStore: RingStore
where
Self::Type: HashableElRing,
{
fn hash<H: std::hash::Hasher>(&self, el: &El<Self>, h: &mut H) { self.get_ring().hash(el, h) }
fn default_hash(&self, el: &El<Self>) -> u64 {
let mut hasher = std::collections::hash_map::DefaultHasher::new();
self.hash(el, &mut hasher);
return <std::collections::hash_map::DefaultHasher as std::hash::Hasher>::finish(&hasher);
}
}
impl<R> HashableElRingStore for R
where
R: RingStore,
R::Type: HashableElRing,
{
}
pub type El<R> = <<R as RingStore>::Type as RingBase>::Element;
#[repr(transparent)]
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct RingValue<R: RingBase> {
ring: R,
}
impl<R: RingBase> RingValue<R> {
pub const fn from(value: R) -> Self { RingValue { ring: value } }
pub fn from_ref(value: &R) -> &Self { unsafe { std::mem::transmute(value) } }
pub fn into(self) -> R { self.ring }
}
impl<R: RingBase> RingStore for RingValue<R> {
type Type = R;
fn get_ring(&self) -> &R { &self.ring }
}
impl<R: RingBase + Default> Default for RingValue<R> {
fn default() -> Self { Self::from(R::default()) }
}
#[repr(transparent)]
#[derive(Debug)]
pub struct RingRef<'a, R: RingBase + ?Sized> {
ring: &'a R,
}
impl<'a, R: RingBase + ?Sized> Clone for RingRef<'a, R> {
fn clone(&self) -> Self { *self }
}
impl<'a, R: RingBase + ?Sized> Copy for RingRef<'a, R> {}
impl<'a, R: RingBase + ?Sized> RingRef<'a, R> {
pub const fn new(value: &'a R) -> Self { RingRef { ring: value } }
pub fn into(self) -> &'a R { self.ring }
}
impl<'a, R: RingBase + ?Sized> RingStore for RingRef<'a, R> {
type Type = R;
fn get_ring(&self) -> &R { self.ring }
}
impl<'a, S: Deref> RingStore for S
where
S::Target: RingStore,
{
type Type = <<S as Deref>::Target as RingStore>::Type;
fn get_ring(&self) -> &Self::Type { (**self).get_ring() }
}
#[cfg(test)]
use std::rc::Rc;
#[cfg(test)]
use crate::impl_eq_based_self_iso;
#[test]
fn test_ring_rc_lifetimes() {
let ring = Rc::new(StaticRing::<i32>::RING);
let mut ring_ref = None;
assert!(ring_ref.is_none());
{
ring_ref = Some(ring.get_ring());
}
assert!(ring.get_ring().is_commutative());
assert!(ring_ref.is_some());
}
#[test]
fn test_internal_wrappings_dont_matter() {
#[derive(Clone, PartialEq)]
pub struct ABase;
#[allow(unused)]
#[derive(Clone)]
pub struct BBase<R: RingStore> {
base: R,
}
impl<R: RingStore> PartialEq for BBase<R> {
fn eq(&self, other: &Self) -> bool { self.base.get_ring() == other.base.get_ring() }
}
impl RingBase for ABase {
type Element = i32;
fn clone_el(&self, val: &Self::Element) -> Self::Element { *val }
fn add_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) { *lhs += rhs; }
fn negate_inplace(&self, lhs: &mut Self::Element) { *lhs = -*lhs; }
fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool { *lhs == *rhs }
fn is_commutative(&self) -> bool { true }
fn is_noetherian(&self) -> bool { true }
fn from_int(&self, value: i32) -> Self::Element { value }
fn mul_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) { *lhs *= rhs; }
fn dbg_within<'a>(
&self,
_: &Self::Element,
_: &mut std::fmt::Formatter<'a>,
_: EnvBindingStrength,
) -> std::fmt::Result {
Ok(())
}
fn characteristic<I: RingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
where
I::Type: IntegerRing,
{
Some(ZZ.zero())
}
fn is_approximate(&self) -> bool { false }
}
impl_eq_based_self_iso! { ABase }
impl<R: RingStore> RingBase for BBase<R> {
type Element = i32;
fn clone_el(&self, val: &Self::Element) -> Self::Element { *val }
fn add_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) { *lhs += rhs; }
fn negate_inplace(&self, lhs: &mut Self::Element) { *lhs = -*lhs; }
fn eq_el(&self, lhs: &Self::Element, rhs: &Self::Element) -> bool { *lhs == *rhs }
fn is_commutative(&self) -> bool { true }
fn is_noetherian(&self) -> bool { true }
fn from_int(&self, value: i32) -> Self::Element { value }
fn mul_assign(&self, lhs: &mut Self::Element, rhs: Self::Element) { *lhs *= rhs; }
fn dbg_within<'a>(
&self,
_: &Self::Element,
_: &mut std::fmt::Formatter<'a>,
_: EnvBindingStrength,
) -> std::fmt::Result {
Ok(())
}
fn characteristic<I: RingStore + Copy>(&self, ZZ: I) -> Option<El<I>>
where
I::Type: IntegerRing,
{
Some(ZZ.zero())
}
fn is_approximate(&self) -> bool { false }
}
impl<R: RingStore> CanHomFrom<ABase> for BBase<R> {
type Homomorphism = ();
fn has_canonical_hom(&self, _: &ABase) -> Option<()> { Some(()) }
fn map_in(&self, _: &ABase, el: <ABase as RingBase>::Element, _: &()) -> Self::Element { el }
}
impl<R: RingStore, S: RingStore> CanHomFrom<BBase<S>> for BBase<R>
where
R::Type: CanHomFrom<S::Type>,
{
type Homomorphism = ();
fn has_canonical_hom(&self, _: &BBase<S>) -> Option<()> { Some(()) }
fn map_in(&self, _: &BBase<S>, el: <BBase<S> as RingBase>::Element, _: &()) -> Self::Element { el }
}
impl<R: RingStore> CanIsoFromTo<BBase<R>> for BBase<R>
where
R::Type: CanHomFrom<R::Type>,
{
type Isomorphism = ();
fn has_canonical_iso(&self, _: &BBase<R>) -> Option<()> { Some(()) }
fn map_out(&self, _: &BBase<R>, el: <BBase<R> as RingBase>::Element, _: &()) -> Self::Element { el }
}
type A = RingValue<ABase>;
type B<R> = RingValue<BBase<R>>;
let a: A = RingValue { ring: ABase };
let b1: B<A> = RingValue {
ring: BBase { base: a.clone() },
};
let b2: B<&B<A>> = RingValue {
ring: BBase { base: &b1 },
};
let b3: B<&A> = RingValue {
ring: BBase { base: &a },
};
_ = b1.coerce(&a, 0);
_ = b2.coerce(&a, 0);
_ = b2.coerce(&b1, 0);
_ = b2.coerce(&b3, 0);
_ = (&b2).coerce(&b3, 0);
_ = (&b2).coerce(&&&b3, 0);
}
#[allow(missing_docs)]
#[cfg(any(test, feature = "generic_tests"))]
pub mod generic_tests {
use std::cmp::min;
use super::*;
use crate::integer::{BigIntRing, int_cast};
pub fn test_hom_axioms<R: RingStore, S: RingStore, I: Iterator<Item = El<R>>>(from: R, to: S, edge_case_elements: I)
where
S::Type: CanHomFrom<R::Type>,
{
let hom = to.can_hom(&from).unwrap();
crate::homomorphism::generic_tests::test_homomorphism_axioms(hom, edge_case_elements);
}
pub fn test_iso_axioms<R: RingStore, S: RingStore, I: Iterator<Item = El<R>>>(from: R, to: S, edge_case_elements: I)
where
S::Type: CanIsoFromTo<R::Type>,
{
let hom = to.get_ring().has_canonical_hom(from.get_ring()).unwrap();
let iso = to.get_ring().has_canonical_iso(from.get_ring()).unwrap();
let elements = edge_case_elements.collect::<Vec<_>>();
for a in &elements {
let map_in = to.get_ring().map_in_ref(from.get_ring(), a, &hom);
let map_in_out = to.get_ring().map_out(from.get_ring(), to.clone_el(&map_in), &iso);
assert!(
from.eq_el(&map_in_out, &a),
"Bijectivity failed: {} != {} = hom^-1({}) = hom^-1(hom({}))",
from.format(a),
from.format(&map_in_out),
to.format(&map_in),
from.format(a)
);
}
}
pub fn test_self_iso<R: RingStore, I: Iterator<Item = El<R>>>(ring: R, edge_case_elements: I)
where
R::Type: SelfIso,
{
let hom = ring.get_ring().has_canonical_hom(ring.get_ring()).unwrap();
let iso = ring.get_ring().has_canonical_iso(ring.get_ring()).unwrap();
let elements = edge_case_elements.collect::<Vec<_>>();
test_hom_axioms(&ring, &ring, elements.iter().map(|x| ring.clone_el(x)));
test_iso_axioms(&ring, &ring, elements.iter().map(|x| ring.clone_el(x)));
for a in &elements {
assert_el_eq!(ring, a, ring.get_ring().map_in_ref(ring.get_ring(), a, &hom));
assert_el_eq!(
ring,
a,
ring.get_ring().map_out(ring.get_ring(), ring.clone_el(a), &iso)
);
}
}
pub fn test_hash_axioms<R: RingStore, I: Iterator<Item = El<R>>>(ring: R, edge_case_elements: I)
where
R::Type: HashableElRing,
{
let elements = edge_case_elements.collect::<Vec<_>>();
assert_ne!(ring.default_hash(&ring.one()), ring.default_hash(&ring.zero()));
for a in &elements {
for b in &elements {
assert!(!ring.eq_el(a, b) || ring.default_hash(a) == ring.default_hash(b));
}
}
for a in &elements {
for b in &elements {
let expr = ring.sub(ring.mul_ref_fst(a, ring.add_ref_fst(b, ring.one())), ring.mul_ref(a, b));
assert!(ring.default_hash(a) == ring.default_hash(&expr));
}
}
}
pub fn test_ring_axioms<R: RingStore, I: Iterator<Item = El<R>>>(ring: R, edge_case_elements: I) {
let elements = edge_case_elements.collect::<Vec<_>>();
let zero = ring.zero();
let one = ring.one();
assert!(ring.is_zero(&zero));
assert!(ring.is_one(&one));
assert!(ring.is_neg_one(&ring.neg_one()));
assert!(ring.eq_el(&ring.neg_one(), &ring.get_ring().from_int(-1)));
assert!(ring.eq_el(&zero, &ring.get_ring().from_int(0)));
assert!(ring.eq_el(&one, &ring.get_ring().from_int(1)));
for a in &elements {
let a_minus_a = ring.sub(ring.clone_el(a), ring.clone_el(a));
assert!(
ring.eq_el(&zero, &a_minus_a),
"Additive inverse failed: {} - {} = {} != {}",
ring.format_within(a, EnvBindingStrength::Sum),
ring.format_within(a, EnvBindingStrength::Product),
ring.format(&a_minus_a),
ring.format(&zero)
);
}
for a in &elements {
let a_plus_zero = ring.add(ring.clone_el(a), ring.clone_el(&zero));
assert!(
ring.eq_el(a, &a_plus_zero),
"Additive neutral element failed: {} + {} = {} != {}",
ring.format_within(a, EnvBindingStrength::Sum),
ring.format(&zero),
ring.format(&a_plus_zero),
ring.format(a)
);
let a_times_one = ring.mul(ring.clone_el(a), ring.clone_el(&one));
assert!(
ring.eq_el(a, &a_times_one),
"Multiplicative neutral element failed: {} * {} = {} != {}",
ring.format_within(a, EnvBindingStrength::Product),
ring.format(&one),
ring.format(&a_times_one),
ring.format(a)
);
}
for a in &elements {
for b in &elements {
{
let ab = ring.add_ref(a, b);
let ba = ring.add_ref(b, a);
assert!(
ring.eq_el(&ab, &ba),
"Additive commutativity failed: {} + {} = {} != {} = {} + {}",
ring.format_within(a, EnvBindingStrength::Sum),
ring.format_within(b, EnvBindingStrength::Sum),
ring.format(&ab),
ring.format(&ba),
ring.format_within(b, EnvBindingStrength::Sum),
ring.format_within(a, EnvBindingStrength::Sum)
);
}
if ring.is_commutative() {
let ab = ring.mul_ref(a, b);
let ba = ring.mul_ref(b, a);
assert!(
ring.eq_el(&ab, &ba),
"Multiplicative commutativity failed: {} * {} = {} != {} = {} * {}",
ring.format_within(a, EnvBindingStrength::Product),
ring.format_within(b, EnvBindingStrength::Product),
ring.format(&ab),
ring.format(&ba),
ring.format_within(b, EnvBindingStrength::Product),
ring.format_within(a, EnvBindingStrength::Product)
);
}
}
}
for a in &elements {
for b in &elements {
for c in &elements {
{
let ab_c = ring.add_ref_snd(ring.add_ref(a, b), c);
let a_bc = ring.add_ref_fst(c, ring.add_ref(b, a));
assert!(
ring.eq_el(&ab_c, &a_bc),
"Additive associativity failed: ({} + {}) + {} = {} != {} = {} + ({} + {})",
ring.format_within(a, EnvBindingStrength::Sum),
ring.format_within(b, EnvBindingStrength::Sum),
ring.format_within(c, EnvBindingStrength::Sum),
ring.format(&ab_c),
ring.format(&a_bc),
ring.format_within(a, EnvBindingStrength::Sum),
ring.format_within(b, EnvBindingStrength::Sum),
ring.format_within(c, EnvBindingStrength::Sum)
);
}
{
let ab_c = ring.mul_ref_snd(ring.mul_ref(a, b), c);
let a_bc = ring.mul_ref_fst(c, ring.mul_ref(b, a));
assert!(
ring.eq_el(&ab_c, &a_bc),
"Multiplicative associativity failed: ({} * {}) * {} = {} != {} = {} * ({} * {})",
ring.format_within(a, EnvBindingStrength::Sum),
ring.format_within(b, EnvBindingStrength::Sum),
ring.format_within(c, EnvBindingStrength::Sum),
ring.format(&ab_c),
ring.format(&a_bc),
ring.format_within(a, EnvBindingStrength::Sum),
ring.format_within(b, EnvBindingStrength::Sum),
ring.format_within(c, EnvBindingStrength::Sum)
);
}
}
}
}
for a in &elements {
for b in &elements {
for c in &elements {
let ab_c = ring.mul_ref_snd(ring.add_ref(a, b), c);
let ac_bc = ring.add(ring.mul_ref(a, c), ring.mul_ref(b, c));
assert!(
ring.eq_el(&ab_c, &ac_bc),
"Distributivity failed: ({} + {}) * {} = {} != {} = {} * {} + {} * {}",
ring.format_within(a, EnvBindingStrength::Product),
ring.format_within(b, EnvBindingStrength::Sum),
ring.format_within(c, EnvBindingStrength::Sum),
ring.format(&ab_c),
ring.format(&ac_bc),
ring.format_within(a, EnvBindingStrength::Product),
ring.format_within(c, EnvBindingStrength::Product),
ring.format_within(b, EnvBindingStrength::Product),
ring.format_within(c, EnvBindingStrength::Product)
);
let a_bc = ring.mul_ref_fst(a, ring.add_ref(b, c));
let ab_ac = ring.add(ring.mul_ref(a, b), ring.mul_ref(a, c));
assert!(
ring.eq_el(&a_bc, &ab_ac),
"Distributivity failed: {} * ({} + {}) = {} != {} = {} * {} + {} * {}",
ring.format_within(a, EnvBindingStrength::Product),
ring.format_within(b, EnvBindingStrength::Sum),
ring.format_within(c, EnvBindingStrength::Sum),
ring.format(&a_bc),
ring.format(&ab_ac),
ring.format_within(a, EnvBindingStrength::Product),
ring.format_within(b, EnvBindingStrength::Product),
ring.format_within(a, EnvBindingStrength::Product),
ring.format_within(c, EnvBindingStrength::Product)
);
}
}
}
for a in &elements {
for b in &elements {
for c in &elements {
let actual = ring.fma(a, b, ring.clone_el(c));
let expected = ring.add(ring.mul_ref(a, b), ring.clone_el(c));
assert!(
ring.eq_el(&expected, &actual),
"FMA failed: fma({}, {}, {}) = {} != {} = ({} * {}) + {}",
ring.format(a),
ring.format(b),
ring.format(c),
ring.format(&actual),
ring.format(&expected),
ring.format_within(a, EnvBindingStrength::Product),
ring.format_within(b, EnvBindingStrength::Product),
ring.format_within(c, EnvBindingStrength::Sum)
);
}
let actual = ring.get_ring().fma_int(a, 2, ring.clone_el(b));
let expected = ring.get_ring().add(ring.get_ring().add_ref(a, a), ring.clone_el(b));
assert!(
ring.eq_el(&expected, &actual),
"Int-FMA failed: int-fma({}, 2, {}) = {} != {} = ({} * 2) + {}",
ring.format(a),
ring.format(b),
ring.format(&actual),
ring.format(&expected),
ring.format_within(a, EnvBindingStrength::Product),
ring.format_within(b, EnvBindingStrength::Sum)
);
}
}
for a in &elements {
for n in [0, 1, 2, 3, 7, 8] {
let expected = (0..n).map(|_| a).fold(ring.one(), |x, y| ring.mul_ref_snd(x, y));
let actual = ring.pow(ring.clone_el(a), n);
assert!(
ring.eq_el(&expected, &actual),
"Powering failed: {} * ... * {} = {} != {} = {}^{}",
ring.format_within(a, EnvBindingStrength::Product),
ring.format_within(a, EnvBindingStrength::Product),
ring.format(&expected),
ring.format(&actual),
ring.format_within(a, EnvBindingStrength::Power),
n
);
}
}
let ZZbig = BigIntRing::RING;
let char = ring.characteristic(&ZZbig).unwrap();
if ZZbig.is_geq(&char, &ZZbig.power_of_two(7)) {
assert_eq!(None, ring.characteristic(&StaticRing::<i8>::RING));
}
if ZZbig.is_geq(&char, &ZZbig.power_of_two(15)) {
assert_eq!(None, ring.characteristic(&StaticRing::<i16>::RING));
}
if ZZbig.is_geq(&char, &ZZbig.power_of_two(31)) {
assert_eq!(None, ring.characteristic(&StaticRing::<i32>::RING));
}
if ZZbig.is_geq(&char, &ZZbig.power_of_two(63)) {
assert_eq!(None, ring.characteristic(&StaticRing::<i64>::RING));
}
if ZZbig.is_geq(&char, &ZZbig.power_of_two(127)) {
assert_eq!(None, ring.characteristic(&StaticRing::<i128>::RING));
}
if ZZbig.is_lt(&char, &ZZbig.power_of_two(31)) {
let char = int_cast(char, &StaticRing::<i32>::RING, &ZZbig);
assert_el_eq!(ring, ring.zero(), ring.get_ring().from_int(char));
if char == 0 {
for i in 1..(1 << 10) {
assert!(!ring.is_zero(&ring.get_ring().from_int(i)));
}
} else {
for i in 1..min(1 << 10, char) {
assert!(!ring.is_zero(&ring.get_ring().from_int(i)));
}
}
}
}
}
#[test]
fn test_environment_binding() {
assert!(EnvBindingStrength::Strongest > EnvBindingStrength::Power);
assert!(EnvBindingStrength::Power > EnvBindingStrength::Product);
assert!(EnvBindingStrength::Product > EnvBindingStrength::Sum);
assert!(EnvBindingStrength::Sum > EnvBindingStrength::Weakest);
}