use super::free_group_term::*;
use super::*;
use super::literal::*;
use std::collections::BTreeSet;
use std::ops::Mul;
use super::l_group_term_reducing::*;
mod parse_l_group_term;
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
pub enum LGroupTerm {
Atom(FreeGroupTerm),
Meet(BTreeSet<LGroupTerm>),
Join(BTreeSet<LGroupTerm>),
Prod(Vec<LGroupTerm>)
}
pub const IDENTITY: LGroupTerm = LGroupTerm::Atom(FreeGroupTerm { literals: vec![] } );
impl From<FreeGroupTerm> for LGroupTerm {
fn from(x: FreeGroupTerm) -> LGroupTerm {
LGroupTerm::Atom(x).reduced()
}
}
impl From<Literal> for LGroupTerm {
fn from(x: Literal) -> LGroupTerm {
LGroupTerm::Atom(FreeGroupTerm::from(x))
}
}
impl From<&str> for LGroupTerm {
fn from(s: &str) -> LGroupTerm {
let result = parse_l_group_term::parse(s);
match result {
Ok(term) => term.reduced(),
Err(e) => panic!(e)
}
}
}
impl From<char> for LGroupTerm {
fn from(c: char) -> LGroupTerm {
LGroupTerm::Atom(FreeGroupTerm::from(c))
}
}
impl Mul for LGroupTerm {
type Output = LGroupTerm;
fn mul(self, other: LGroupTerm) -> LGroupTerm {
match (self.clone(), other.clone()) {
(LGroupTerm::Atom(x), LGroupTerm::Atom(y)) => LGroupTerm::Atom(x * y),
_ => LGroupTerm::Prod(vec![self, other]).reduced()
}
}
}
impl Term for LGroupTerm {
fn inverse(&self) -> LGroupTerm {
match self {
LGroupTerm::Atom(x) => LGroupTerm::Atom(x.inverse()),
LGroupTerm::Meet(xs) => LGroupTerm::Join(xs.iter().map(|x| x.inverse()).collect()),
LGroupTerm::Join(xs) => LGroupTerm::Meet(xs.iter().map(|x| x.inverse()).collect()),
LGroupTerm::Prod(xs) => {
let mut new_xs: Vec<LGroupTerm> = xs.iter().map(|x| x.inverse()).collect();
new_xs.reverse();
LGroupTerm::Prod(new_xs)
}
}
}
}
impl Reducable for LGroupTerm {
fn reduced(self) -> LGroupTerm {
match self {
LGroupTerm::Atom(x) => atom_reduced(x),
LGroupTerm::Meet(xs) => meet_reduced(xs).expect("Reducing failed."),
LGroupTerm::Join(xs) => join_reduced(xs).expect("Reducing failed."),
LGroupTerm::Prod(xs) => prod_reduced(xs).expect("Reducing failed.")
}
}
}
impl ToString for LGroupTerm {
fn to_string(&self) -> String {
let delimiter: char;
let mut elements = Vec::new();
match self {
LGroupTerm::Atom(x) => return x.to_string(),
LGroupTerm::Meet(xs) => {
delimiter = '^';
for x in xs { elements.push(x); }
},
LGroupTerm::Join(xs) => {
delimiter = 'v';
for x in xs { elements.push(x); }
},
LGroupTerm::Prod(xs) => {
delimiter = '*';
for x in xs { elements.push(x); }
}
}
if elements.len() == 0 {
return format!("Empty '{}'", delimiter);
}
let mut string = format!("{}", elements[0].to_string());
for i in 1 .. elements.len() {
string.push_str(format!(" {} {}", delimiter, elements[i].to_string()).as_str());
}
return format!("({})", string);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_inverse_atom() {
let x = Literal::from('x');
let y = Literal::from('y');
let z = Literal::from('z');
let xyz = FreeGroupTerm { literals: vec![x,y,z] };
let term = LGroupTerm::Atom(xyz);
let inverse = LGroupTerm::Atom(FreeGroupTerm { literals: vec![z.inverse(), y.inverse(), x.inverse()]});
assert_eq!(inverse, term.inverse());
}
#[test]
fn test_inverse_meet() {
let x = LGroupTerm::Atom(FreeGroupTerm { literals: vec![Literal::from('x')]});
let y = LGroupTerm::Atom(FreeGroupTerm { literals: vec![Literal::from('y')]});
let mut meetands = BTreeSet::new();
meetands.insert(x.clone());
meetands.insert(y.clone());
let meet = LGroupTerm::Meet(meetands);
let mut inverse_meetands = BTreeSet::new();
inverse_meetands.insert(x.inverse());
inverse_meetands.insert(y.inverse());
let inverse = LGroupTerm::Join(inverse_meetands);
assert_eq!(inverse, meet.inverse());
}
#[test]
fn test_inverse_join() {
let x = LGroupTerm::Atom(FreeGroupTerm { literals: vec![Literal::from('x')]});
let y = LGroupTerm::Atom(FreeGroupTerm { literals: vec![Literal::from('y')]});
let mut joinands = BTreeSet::new();
joinands.insert(x.clone());
joinands.insert(y.clone());
let join = LGroupTerm::Join(joinands);
let mut inverse_joinands = BTreeSet::new();
inverse_joinands.insert(x.inverse());
inverse_joinands.insert(y.inverse());
let inverse = LGroupTerm::Meet(inverse_joinands);
assert_eq!(inverse, join.inverse());
}
#[test]
fn test_inverse_recursive() {
let x = LGroupTerm::Atom(FreeGroupTerm { literals: vec![Literal::from('x')]});
let y = LGroupTerm::Atom(FreeGroupTerm { literals: vec![Literal::from('y')]});
let z = LGroupTerm::Atom(FreeGroupTerm { literals: vec![Literal::from('z')]});
let z_inv = z.inverse();
let mut meetands = BTreeSet::new();
meetands.insert(x.clone());
meetands.insert(y.clone());
let meet = LGroupTerm::Meet(meetands);
let mut joinands = BTreeSet::new();
joinands.insert(x.inverse());
joinands.insert(y.inverse());
let inverse_of_meet = LGroupTerm::Join(joinands);
let prod = LGroupTerm::Prod(vec![meet, z]);
let prod_inverse = LGroupTerm::Prod(vec![z_inv, inverse_of_meet]);
assert_eq!(prod_inverse, prod.inverse());
}
#[test]
fn test_mul_atoms() {
let x = LGroupTerm::from(Literal::from('x'));
let y = LGroupTerm::from(Literal::from('y'));
assert_eq!(LGroupTerm::Atom(FreeGroupTerm::new(vec![Literal::from('x'), Literal::from('y')])), x * y)
}
#[test]
fn test_to_string() {
let mut inner_meetands = BTreeSet::new();
inner_meetands.insert(LGroupTerm::from(Literal::from('x')));
inner_meetands.insert(LGroupTerm::from(Literal::from('y')));
let inner_meet = LGroupTerm::Meet(inner_meetands);
let mut meetands = BTreeSet::new();
meetands.insert(inner_meet);
meetands.insert(LGroupTerm::from(Literal::from('z')));
let meet = LGroupTerm::Meet(meetands);
assert_eq!(String::from("(z ^ (x ^ y))"), meet.to_string());
}
}