use crate::{
impl_group_via_mul,
traits::{
Different, ExactCmp, FromReal, Interval, Metric, Real, ReflectedContext, Same, Tensor, ι,
𝐂𝐅𝐥𝐝,
},
};
use core::ops::{Add, Mul, Neg, Sub};
use num_traits::{Inv, NumCast, One, Zero, real::Real as _};
use super::{Point, Smooth};
pub trait CMonoid: Point + Zero {
#[cfg(feature = "testing")]
fn check_left_identity(&self) -> bool
where
Self: PartialEq,
{
Self::zero() + self.clone() == *self
}
#[cfg(feature = "testing")]
fn check_right_identity(&self) -> bool
where
Self: PartialEq,
{
self.clone() + Self::zero() == *self
}
#[cfg(feature = "testing")]
fn check_associativity(a: Self, b: Self, c: Self) -> bool
where
Self: PartialEq,
{
(a.clone() + b.clone()) + c.clone() == a + (b + c)
}
#[cfg(feature = "testing")]
fn check_commutativity(a: Self, b: Self) -> bool
where
Self: PartialEq,
{
a.clone() + b.clone() == b + a
}
}
impl<M: Point + Zero> CMonoid for M {}
pub trait Monoid: Point + One {
#[cfg(feature = "testing")]
fn check_left_identity(&self) -> bool
where
Self: PartialEq,
{
Self::one() * self.clone() == *self
}
#[cfg(feature = "testing")]
fn check_right_identity(&self) -> bool
where
Self: PartialEq,
{
self.clone() * Self::one() == *self
}
#[cfg(feature = "testing")]
fn check_associativity(a: Self, b: Self, c: Self) -> bool
where
Self: PartialEq,
{
(a.clone() * b.clone()) * c.clone() == a * (b * c)
}
}
impl<M: Point + One> Monoid for M {}
pub trait CGroup: CMonoid + Sub<Output = Self> + Neg<Output = Self> {
#[cfg(feature = "testing")]
fn check_left_inverse(&self) -> bool
where
Self: PartialEq,
{
-self.clone() + self.clone() == Self::zero()
}
#[cfg(feature = "testing")]
fn check_right_inverse(&self) -> bool
where
Self: PartialEq,
{
self.clone() + -self.clone() == Self::zero()
}
#[cfg(feature = "testing")]
fn check_sub_agrees_with_neg(a: &Self, b: &Self) -> bool
where
Self: PartialEq,
{
a.clone() - b.clone() == a.clone() + -(b.clone())
}
}
impl<G: CMonoid + Sub<Output = Self> + Neg<Output = Self>> CGroup for G {}
#[macro_export]
macro_rules! impl_group_via_add {
($target:ty, $($generics:tt)*) => {
impl<$($generics)*> $crate::traits::Group for $target {
fn identity() -> Self {
<Self as num_traits::Zero>::zero()
}
fn compose(&self, other: &Self) -> Self {
self.clone() + other.clone()
}
fn inverse(&self) -> Self {
-self.clone()
}
}
};
}
#[macro_export]
macro_rules! impl_abelian_group_via_grothendieck {
($target:ty, $monoid:ty, $($generics:tt)*) => {
impl<$($generics)*> num_traits::Zero for $target {
fn zero() -> Self {
(<$monoid as num_traits::Zero>::zero(), <$monoid as num_traits::Zero>::zero()).into()
}
fn is_zero(&self) -> bool {
let (a, b) = self.clone().into();
a == b
}
}
impl<$($generics)*> core::ops::Add for $target {
type Output = Self;
fn add(self, other: Self) -> Self {
let (a, b) = self.into();
let (c, d) = other.into();
(a + c, b + d).into()
}
}
impl<$($generics)*> core::ops::Sub for $target {
type Output = Self;
fn sub(self, other: Self) -> Self {
self + -other
}
}
impl<$($generics)*> core::ops::Neg for $target {
type Output = Self;
fn neg(self) -> Self {
let (a, b) = self.into();
(b, a).into()
}
}
};
}
#[macro_export]
macro_rules! impl_ring_via_grothendieck {
($target:ty, $rig:ty, $($generics:tt)*) => {
$crate::impl_abelian_group_via_grothendieck!($target, $rig, $($generics)*);
impl<$($generics)*> num_traits::One for $target {
fn one() -> Self {
(<$rig as num_traits::One>::one(), <$rig as num_traits::Zero>::zero()).into()
}
}
impl<$($generics)*> core::ops::Mul for $target {
type Output = Self;
fn mul(self, other: Self) -> Self {
let (a, b) = self.into();
let (c, d) = other.into();
let pos = (a.clone() * c.clone()) + (b.clone() * d.clone());
let neg = (a * d) + (b * c);
(pos, neg).into()
}
}
}
}
pub trait Rig: CMonoid + Monoid {
#[cfg(feature = "testing")]
fn check_left_distributivity(a: Self, b: Self, c: Self) -> bool
where
Self: PartialEq,
{
a.clone() * (b.clone() + c.clone()) == (a.clone() * b) + (a * c)
}
#[cfg(feature = "testing")]
fn check_right_distributivity(a: Self, b: Self, c: Self) -> bool
where
Self: PartialEq,
{
(a.clone() + b.clone()) * c.clone() == (a * c.clone()) + (b * c)
}
#[cfg(feature = "testing")]
fn check_left_annihilation(&self) -> bool
where
Self: PartialEq,
{
Self::zero() * self.clone() == Self::zero()
}
#[cfg(feature = "testing")]
fn check_right_annihilation(&self) -> bool
where
Self: PartialEq,
{
self.clone() * Self::zero() == Self::zero()
}
}
impl<R: CMonoid + One> Rig for R {}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct NonZero<T: Zero>(pub T);
impl<T: Zero> NonZero<T> {
pub fn new(value: T) -> Option<Self> {
if !value.is_zero() {
Some(Self(value))
} else {
None
}
}
pub fn new_unchecked(value: T) -> Self {
Self(value)
}
}
impl<T: Zero + One> Mul<Self> for NonZero<T> {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self(self.0 * rhs.0)
}
}
impl<T: Zero + One> One for NonZero<T> {
fn one() -> Self {
Self(T::one())
}
}
impl<T: Zero + One + Inv<Output = T>> Inv for NonZero<T> {
type Output = Self;
fn inv(self) -> Self::Output {
Self(self.0.inv())
}
}
impl<T: Zero + One + Point> Group for NonZero<T>
where
NonZero<T>: Inv<Output = Self>,
{
fn identity() -> Self {
<Self as num_traits::One>::one()
}
fn compose(&self, other: &Self) -> Self {
self.clone() * other.clone()
}
fn inverse(&self) -> Self {
<Self as num_traits::Inv>::inv(self.clone())
}
}
pub trait Ring: CGroup + Rig {}
impl<R: CGroup + Rig> Ring for R {}
pub trait DivRing: Ring {
fn div(self, rhs: Self) -> Self {
self * Self::Mul::from(NonZero::new(rhs).expect("division by zero"))
.inv()
.into()
.0
}
type Mul: MulGroup + From<NonZero<Self>> + Into<NonZero<Self>>;
}
impl<R: Ring> DivRing for R
where
NonZero<Self>: MulGroup,
{
type Mul = NonZero<Self>;
}
pub trait Field: DivRing + Copy + PartialEq + core::fmt::Debug {
type Fixed: CField<Fixed = Self::Fixed>;
fn conj(&self) -> Self;
type Characteristic: Nat;
fn powi(&self, mut s: usize) -> Self {
let mut base = *self;
let mut result = Self::one();
while s != 0 {
if s & 1 != 0 {
result = result * base;
}
base = base * base;
s >>= 1;
}
result
}
fn from_nat(mut n: usize) -> Self {
if Self::Characteristic::N != 0 {
debug_assert!(n < Self::Characteristic::N);
}
let mut result = Self::zero();
let mut current = Self::one();
while n != 0 {
if n & 1 == 1 {
result = result + current;
}
current = current + current;
n >>= 1;
}
result
}
fn norm_squared(self) -> Self::Fixed {
Self::to_fixed(self * self.conj())
}
fn to_fixed(self) -> Self::Fixed;
fn from_fixed(x: Self::Fixed) -> Self;
#[cfg(feature = "testing")]
fn check_conj_additive(a: Self, b: Self) -> bool {
(a + b).conj() == a.conj() + b.conj()
}
#[cfg(feature = "testing")]
fn check_conj_multiplicative(a: Self, b: Self) -> bool {
(a * b).conj() == b.conj() * a.conj()
}
#[cfg(feature = "testing")]
fn check_conj_unit() -> bool {
Self::one().conj() == Self::one()
}
#[cfg(feature = "testing")]
fn check_conj_involution(a: Self) -> bool {
a.conj().conj() == a
}
#[cfg(feature = "testing")]
fn check_from_fixed_additive(x: Self::Fixed, y: Self::Fixed) -> bool {
Self::from_fixed(x + y) == Self::from_fixed(x) + Self::from_fixed(y)
}
#[cfg(feature = "testing")]
fn check_from_fixed_multiplicative(x: Self::Fixed, y: Self::Fixed) -> bool {
Self::from_fixed(x * y) == Self::from_fixed(x) * Self::from_fixed(y)
}
#[cfg(feature = "testing")]
fn check_descent(x: Self) -> bool {
let s = x + x.conj();
Self::from_fixed(s.to_fixed()) == s
}
#[cfg(feature = "testing")]
fn check_norm_squared_self_adjoint(x: Self) -> bool {
let n = x * x.conj();
n.conj() == n
}
#[cfg(feature = "testing")]
fn check_from_fixed_is_fixed(x: Self::Fixed) -> bool {
let y = Self::from_fixed(x);
y.conj() == y
}
#[cfg(feature = "testing")]
fn check_fixed_field_is_central(x: Self::Fixed, y: Self) -> bool {
let x = Self::from_fixed(x);
x * y == y * x
}
#[cfg(feature = "testing")]
fn check_from_fixed_unit() -> bool {
<Self::Fixed as Field>::Characteristic::N == 1
|| Self::from_fixed(Self::Fixed::one()) == Self::one()
}
#[cfg(feature = "testing")]
fn check_characteristic_up_to(bound: usize) -> bool {
let mut acc = Self::zero();
let bound = match Self::Characteristic::N {
0 => bound,
n => bound.min(n),
};
for _ in 1..bound {
acc = acc + Self::one();
if acc == Self::zero() {
return false;
}
}
if bound != 0 && bound == Self::Characteristic::N {
acc + Self::one() == Self::zero()
} else {
acc + Self::one() != Self::zero()
}
}
}
pub trait CField: Field {
#[cfg(feature = "testing")]
fn check_commutativity(a: Self, b: Self) -> bool {
a * b == b * a
}
}
pub trait FieldExp: Field<Characteristic = NatZero> {
fn exp(&self) -> Self;
fn exp_by_series(&self) -> Self
where
Self: Metric,
{
let theta = Self::R::one();
let n = 20;
let r = self.distance(&Self::zero());
let div = r.div(theta);
let s = if !div.exact_lt(Self::R::one()) {
<i32 as NumCast>::from(div.log2().ceil()).unwrap()
} else {
0
};
let scaled = self.div((Self::from_nat(2)).powi(s.try_into().unwrap()));
let (mut result, _, _) = (0..n).fold(
(Self::one(), Self::one(), Self::one()),
|(acc, term, n), _| {
let term = term * scaled.div(n);
(acc + term, term, n + Self::one())
},
);
for _ in 0..s {
result = result * result;
}
result
}
}
pub trait Nat: Copy + Clone + core::fmt::Debug + Send + Sync + 'static {
const N: usize;
}
#[derive(Copy, Clone, Debug)]
pub struct Succ<N: Nat>(N);
#[derive(Copy, Clone, Debug)]
pub enum NatZero {}
pub type NatOne = Succ<NatZero>;
impl Nat for NatZero {
const N: usize = 0;
}
impl<N: Nat> Nat for Succ<N> {
const N: usize = N::N + 1;
}
pub trait NatEq<Rhs: Nat>: Nat {
type Output: Nat;
}
impl NatEq<NatZero> for NatZero {
type Output = NatOne;
}
impl<N: Nat> NatEq<Succ<N>> for NatZero {
type Output = NatZero;
}
pub trait NatCompare<M: Nat>: Nat {
type Relation;
}
impl NatCompare<NatZero> for NatZero {
type Relation = Same;
}
impl<N: Nat> NatCompare<Succ<N>> for NatZero {
type Relation = Different;
}
impl<N: Nat> NatCompare<NatZero> for Succ<N> {
type Relation = Different;
}
impl<N: Nat + NatCompare<M>, M: Nat> NatCompare<Succ<M>> for Succ<N> {
type Relation = <N as NatCompare<M>>::Relation;
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Symmetrized<F: CField>(pub F);
impl<F: CField> Sub for Symmetrized<F> {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self(self.0 - rhs.0)
}
}
impl<F: CField> Add for Symmetrized<F> {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl<F: CField> Neg for Symmetrized<F> {
type Output = Self;
fn neg(self) -> Self::Output {
Self(-self.0)
}
}
impl<F: CField> Mul for Symmetrized<F> {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self(self.0.mul(rhs.0))
}
}
impl<F: CField> One for Symmetrized<F> {
fn one() -> Self {
Self(F::one())
}
fn is_one(&self) -> bool {
self.0.is_one()
}
}
impl<F: CField> Zero for Symmetrized<F> {
fn zero() -> Self {
Self(F::zero())
}
fn is_zero(&self) -> bool {
self.0.is_zero()
}
}
impl<F: CField> Inv for NonZero<Symmetrized<F>> {
type Output = Self;
fn inv(self) -> Self::Output {
NonZero::new_unchecked(Symmetrized(
<F::Mul>::from(NonZero::new_unchecked(self.0.0))
.inv()
.into()
.0,
))
}
}
impl<F: CField> Field for Symmetrized<F> {
type Fixed = Self;
type Characteristic = F::Characteristic;
fn conj(&self) -> Self {
*self
}
fn to_fixed(self) -> Self::Fixed {
self
}
fn from_fixed(x: Self::Fixed) -> Self {
x
}
}
impl<F: CField + Interval> Interval for Symmetrized<F> {
type R = F::R;
fn interval_squared(&self, other: &Self) -> F::R {
self.0.interval_squared(&other.0)
}
}
impl<F: CField<Fixed: Real>> FromReal for Symmetrized<F> {
fn from_real(r: Self::R) -> Self {
Self(F::from_fixed(r))
}
}
impl<F: CField + Metric> Metric for Symmetrized<F> {}
impl<F: CField> CField for Symmetrized<F> {}
impl<F: CField> ι for Symmetrized<F> {
type C = ReflectedContext<𝐂𝐅𝐥𝐝::𝒞, Self>;
}
impl<R: Real, F: Field<Fixed = R>> Interval for F {
type R = R;
fn interval_squared(&self, other: &Self) -> R {
(*self - *other).norm_squared()
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct RootOfUnityPrimitive<F: Field, const N: usize>(RootOfUnity<F, N>);
impl<F: Field, const N: usize> RootOfUnityPrimitive<F, N> {
pub fn new(x: F) -> Option<Self> {
const { assert!(N != 0) }
(0..N)
.try_fold(F::one(), |root, n| {
let power = root * x;
match n {
x if x == N - 1 => power == F::one(),
_ => power != F::one(),
}
.then_some(power)
})
.map(|_| Self(RootOfUnity(x)))
}
pub fn inner(&self) -> RootOfUnity<F, N> {
self.0
}
pub fn roots_of_unity(&self) -> impl Iterator<Item = RootOfUnity<F, N>> {
let mut acc = F::one();
(0..N).map(move |_| {
let ret = acc;
acc = acc * self.0.0;
RootOfUnity(ret)
})
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct RootOfUnity<F: Field, const N: usize>(F);
impl<F: Field, const N: usize> One for RootOfUnity<F, N> {
fn one() -> Self {
const { assert!(N != 0) }
Self(F::one())
}
fn is_one(&self) -> bool {
self.0 == F::one()
}
}
impl<F: Field, const N: usize> Mul<Self> for RootOfUnity<F, N> {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
Self(self.0.mul(rhs.0))
}
}
impl<F: Field, const N: usize> Inv for RootOfUnity<F, N> {
type Output = Self;
fn inv(self) -> Self::Output {
Self(F::Mul::from(NonZero::new_unchecked(self.0)).inv().into().0)
}
}
impl_group_via_mul!(RootOfUnity<F, N>, F: Field, const N: usize);
impl<V: Tensor, const N: usize> LieGroup<V> for RootOfUnity<V::F, N> {
fn identity_exp(_: V) -> Self {
const { assert!(N != 0) }
Self::one()
}
fn identity_log(p: &Self) -> Option<V> {
p.is_one().then(|| V::zero())
}
}
impl<F: Field, const N: usize> RootOfUnity<F, N> {
pub fn new(x: F) -> Option<Self> {
const { assert!(N != 0) }
((1..N).fold(x, |acc, _| acc * x).is_one()).then_some(Self(x))
}
pub fn inner(self) -> F {
self.0
}
}
pub trait MulGroup: Monoid + Inv<Output = Self> {
#[cfg(feature = "testing")]
fn check_left_inverse(&self) -> bool
where
Self: PartialEq,
{
self.clone().inv() * self.clone() == Self::one()
}
#[cfg(feature = "testing")]
fn check_right_inverse(&self) -> bool
where
Self: PartialEq,
{
self.clone() * self.clone().inv() == Self::one()
}
}
impl<G: Monoid + Inv<Output = Self>> MulGroup for G {}
#[macro_export]
macro_rules! impl_group_via_mul {
($target:ty, $($generics:tt)*) => {
impl<$($generics)*> $crate::traits::Group for $target {
fn identity() -> Self {
<Self as num_traits::One>::one()
}
fn compose(&self, other: &Self) -> Self {
self.clone() * other.clone()
}
fn inverse(&self) -> Self {
<Self as num_traits::Inv>::inv(self.clone())
}
}
};
}
pub trait Group: Point {
fn identity() -> Self;
fn compose(&self, other: &Self) -> Self;
fn inverse(&self) -> Self;
#[cfg(feature = "testing")]
fn check_left_identity(&self) -> bool
where
Self: PartialEq,
{
Self::identity().compose(self) == *self
}
#[cfg(feature = "testing")]
fn check_right_identity(&self) -> bool
where
Self: PartialEq,
{
self.clone().compose(&Self::identity()) == *self
}
#[cfg(feature = "testing")]
fn check_associativity(a: Self, b: Self, c: Self) -> bool
where
Self: PartialEq,
{
a.compose(&b).compose(&c) == a.compose(&b.compose(&c))
}
#[cfg(feature = "testing")]
fn check_left_inverse(&self) -> bool
where
Self: PartialEq + core::fmt::Debug,
{
(self.inverse()).compose(self).compose(self) == Self::identity().compose(self)
}
#[cfg(feature = "testing")]
fn check_right_inverse(&self) -> bool
where
Self: PartialEq,
{
self.compose(&self.inverse()).compose(self) == Self::identity().compose(self)
}
}
pub trait LieGroup<V: Tensor>: Group {
fn identity_exp(v: V) -> Self;
fn identity_log(p: &Self) -> Option<V>;
}
impl<V: Tensor, L: LieGroup<V>> Smooth<V> for L {
type Global = Self;
fn exp(&self, coord: V) -> Self {
let translated = Self::identity_exp(coord);
self.compose(&translated)
}
fn log(&self, point: &Self) -> Option<V> {
let translated = self.clone().inverse().compose(point);
Self::identity_log(&translated)
}
}
pub trait Quotient<G: LieGroup<V>, H: LieGroup<V>, V: Tensor>: Point {
fn new(g: G) -> Self;
fn lift(&self) -> G;
fn embed(h: H) -> G;
fn quotient_identity() -> Self {
Self::new(G::identity())
}
fn quotient_compose(&self, other: &Self) -> Self {
Self::new(self.lift().compose(&other.lift()))
}
fn quotient_inverse(&self) -> Self {
Self::new(self.lift().inverse())
}
fn quotient_identity_exp(v: V) -> Self {
Self::new(G::identity_exp(v))
}
fn quotient_identity_log(p: &Self) -> Option<V> {
G::identity_log(&p.lift())
}
#[cfg(feature = "testing")]
fn check_new_respects_coset(g: G, h: H) -> bool
where
Self: PartialEq,
{
Self::new(Self::embed(h).compose(&g)) == Self::new(g)
}
}
#[macro_export]
macro_rules! impl_lie_group_via_quotient {
($type:ty, $g:ty, $h:ty, $v:ty, $($generics:tt)*) => {
impl<$($generics)*> $crate::traits::Group for $type {
fn identity() -> Self {
<Self as $crate::traits::Quotient<$g, $h, $v>>::quotient_identity()
}
fn compose(&self, rhs: &Self) -> Self {
<Self as $crate::traits::Quotient<$g, $h, $v>>::quotient_compose(&self, &rhs)
}
fn inverse(&self) -> Self {
<Self as $crate::traits::Quotient<$g, $h, $v>>::quotient_inverse(&self)
}
}
impl<$($generics)*> $crate::traits::LieGroup<$v> for $type {
fn identity_exp(v: $v) -> Self {
<Self as $crate::traits::Quotient<$g, $h, $v>>::quotient_identity_exp(v)
}
fn identity_log(p: &Self) -> Option<$v> {
<Self as $crate::traits::Quotient<$g, $h, $v>>::quotient_identity_log(p)
}
}
};
}