use super::*;
pub type FreeGroup<C> = MonoidalString<FreeInv<C>,InvRule>;
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub enum FreeInv<T:Eq> {
Id(T),
Inv(T)
}
impl<T:Eq> From<T> for FreeInv<T> {
fn from(t:T) -> Self { FreeInv::Id(t) }
}
impl<T:Eq> AsRef<T> for FreeInv<T> {
fn as_ref(&self) -> &T {
match self {
FreeInv::Id(ref x) => x,
FreeInv::Inv(ref x) => x
}
}
}
impl<T:Eq> AsMut<T> for FreeInv<T> {
fn as_mut(&mut self) -> &mut T {
match self {
FreeInv::Id(ref mut x) => x,
FreeInv::Inv(ref mut x) => x
}
}
}
impl<T:Eq> PartialEq<T> for FreeInv<T> {
fn eq(&self, rhs:&T) -> bool {
match self {
FreeInv::Id(x) => x==rhs,
FreeInv::Inv(_) => false
}
}
}
impl<T:Eq+Display> Display for FreeInv<T> {
fn fmt(&self, f: &mut Formatter) -> ::std::fmt::Result {
match self {
Self::Id(x) => write!(f, "{}", x),
Self::Inv(x) => write!(f, "{}⁻¹", x),
}
}
}
impl<T:Eq> FreeInv<T> {
pub fn is_inv(&self) -> bool {
match self { Self::Inv(_) => true, _ => false }
}
pub fn is_id(&self) -> bool {
match self { Self::Id(_) => true, _ => false }
}
fn are_inverses(&self, rhs:&Self) -> bool {
self.as_ref()==rhs.as_ref() && self.is_inv()^rhs.is_inv()
}
}
pub struct InvRule;
impl<T:Eq> AssociativeMonoidRule<FreeInv<T>> for InvRule {}
impl<T:Eq> MonoidRule<FreeInv<T>> for InvRule {
fn apply(mut string: Vec<FreeInv<T>>, letter: FreeInv<T>) -> Vec<FreeInv<T>> {
if string.last().map_or(false, |last| letter.are_inverses(last)) {
string.pop();
} else {
string.push(letter);
}
string
}
}
impl<T:Eq> InvMonoidRule<FreeInv<T>> for InvRule {
fn invert(letter: FreeInv<T>) -> FreeInv<T> { letter.inv() }
}
impl<T:Eq> Inv for FreeInv<T> {
type Output = Self;
fn inv(self) -> Self {
match self {
Self::Id(x) => Self::Inv(x),
Self::Inv(x) => Self::Id(x)
}
}
}
impl<T:Eq> Mul for FreeInv<T> {
type Output = FreeGroup<T>;
fn mul(self, rhs:Self) -> FreeGroup<T> { FreeGroup::from(self) * rhs }
}
impl<T:Eq> Div for FreeInv<T> {
type Output = FreeGroup<T>;
fn div(self, rhs:Self) -> FreeGroup<T> { self * rhs.inv() }
}
impl<T:Eq> Mul<FreeGroup<T>> for FreeInv<T> {
type Output = FreeGroup<T>;
fn mul(self, rhs:FreeGroup<T>) -> FreeGroup<T> { FreeGroup::from(self) * rhs }
}
impl<T:Eq> Div<FreeGroup<T>> for FreeInv<T> {
type Output = FreeGroup<T>;
fn div(self, rhs:FreeGroup<T>) -> FreeGroup<T> { FreeGroup::from(self) / rhs }
}