use super::*;
use super::literal::*;
use super::short_free_group_term::ShortFreeGroupTerm;
use std::ops::{Mul, MulAssign};
mod parse_free_group_term;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct FreeGroupTerm {
pub literals: Vec<literal::Literal>
}
impl FreeGroupTerm {
pub fn new(literals: Vec<literal::Literal>) -> FreeGroupTerm {
FreeGroupTerm { literals: literals }.reduced()
}
}
pub const FREE_GROUP_IDENTITY: FreeGroupTerm = FreeGroupTerm { literals: vec![] };
impl From<Literal> for FreeGroupTerm {
fn from(x: Literal) -> FreeGroupTerm {
FreeGroupTerm::new(vec![x])
}
}
impl From<char> for FreeGroupTerm {
fn from(c: char) -> FreeGroupTerm {
FreeGroupTerm::from(Literal::from(c))
}
}
impl From<&str> for FreeGroupTerm {
fn from(s: &str) -> FreeGroupTerm {
let result = parse_free_group_term::parse(s);
match result {
Ok(t) => t,
Err(e) => panic!(e)
}
}
}
impl From<ShortFreeGroupTerm> for FreeGroupTerm {
fn from(t: ShortFreeGroupTerm) -> FreeGroupTerm {
match (t.left, t.mid, t.right) {
(None, None, None) => FreeGroupTerm::new(Vec::new()),
(Some(x), None, None) => FreeGroupTerm::from(x),
(Some(x), Some(y), None) => x * y,
(Some(x), Some(y), Some(z)) => x * y * z,
_ => panic!("Invalid ShortFreeGroupTerm")
}
}
}
impl Term for FreeGroupTerm {
fn inverse(&self) -> FreeGroupTerm {
let mut result = Vec::new();
for x in &self.literals {
result.push(x.inverse())
}
result.reverse();
FreeGroupTerm {
literals: result
}
}
}
impl Mul for FreeGroupTerm {
type Output = FreeGroupTerm;
fn mul(self, other: FreeGroupTerm) -> FreeGroupTerm {
if self.literals.len() == 0 { other }
else if other.literals.len() == 0 { self }
else {
FreeGroupTerm::new([&self.literals[..], &other.literals[..]].concat())
}
}
}
impl Mul<Literal> for FreeGroupTerm {
type Output = FreeGroupTerm;
fn mul(self, other: Literal) -> FreeGroupTerm {
self * FreeGroupTerm::from(other)
}
}
impl MulAssign for FreeGroupTerm {
fn mul_assign(&mut self, rhs: FreeGroupTerm) {
for x in rhs.literals {
self.literals.push(x);
}
*self = FreeGroupTerm::new(self.literals.clone());
}
}
impl ToString for FreeGroupTerm {
fn to_string(&self) -> String {
let mut result = String::from("");
for l in &self.literals {
result.push_str(&l.to_string());
}
if result == "" {
return String::from("e");
}
return result;
}
}
impl Reducable for FreeGroupTerm {
fn reduced(self) -> FreeGroupTerm {
let mut index: usize = 0;
let mut literals = self.literals.clone();
enum ReducingState {
ReducedInBeginning,
ReducedElsewhere,
DidNotReduce
}
while literals.len() > 0 && index < literals.len() - 1 {
let mut reducing_state = ReducingState::DidNotReduce;
if literals[index] == literals[index + 1].inverse() {
literals.remove(index);
literals.remove(index);
match index {
0 | 1 => reducing_state = ReducingState::ReducedInBeginning,
_ => reducing_state = ReducingState::ReducedElsewhere
};
}
index = match reducing_state {
ReducingState::ReducedInBeginning => 0,
ReducingState::ReducedElsewhere => index - 1,
ReducingState::DidNotReduce => index + 1
};
}
return FreeGroupTerm { literals: (literals).to_vec() }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_reduce() {
let x = Literal::from('x');
let x_inv = Literal::from('x').inverse();
let y = Literal::from('y');
let result = FreeGroupTerm { literals: vec![x, x_inv, y] };
assert_eq!(FreeGroupTerm { literals: vec![y] }, result.reduced());
let x = Literal::from('x');
let y = Literal::from('y');
let z = Literal::from('z');
let result = FreeGroupTerm { literals: vec![x, y, z, z.inverse(), y.inverse(), x.inverse()]};
assert_eq!(FreeGroupTerm::new(vec![]), result.reduced());
}
#[test]
fn test_to_string() {
let term = FreeGroupTerm::new(vec![Literal::from('x'), Literal::from('y'), Literal::from('z')]);
assert_eq!("xyz", term.to_string());
}
#[test]
fn test_inverse() {
let x = Literal::from('x');
let y = Literal::from('y');
let z = Literal::from('z');
let term = FreeGroupTerm { literals: vec![x,y,z] };
let other_term = FreeGroupTerm { literals: vec![z.inverse(), y.inverse(), x.inverse()] };
assert_eq!(other_term, term.inverse())
}
#[test]
fn test_mul() {
let x = FreeGroupTerm::new(vec![Literal::from('x')]);
let x_inv = FreeGroupTerm::new(vec![Literal::from('x').inverse()]);
assert_eq!(FREE_GROUP_IDENTITY, x*x_inv);
}
#[test]
fn test_mul_assign() {
let mut term = FreeGroupTerm::from(Literal::from('x').inverse());
term *= FreeGroupTerm::from(Literal::from('x'));
assert_eq!(FreeGroupTerm::new(Vec::new()), term);
}
}