use super::symbol::{Match, ParseError, Symbol, Symbolic};
use crate::symbol::ParsedSymbols;
use cascade::cascade;
use std::collections::HashMap;
use std::fmt::Display;
use std::hash::Hash;
#[derive(PartialEq, Hash, Eq, PartialOrd, Ord, Clone, Debug)]
pub enum Tree<B, U, A>
where
B: Symbolic,
U: Symbolic,
A: Symbolic,
{
Binary {
conn: B,
left: Box<Tree<B, U, A>>,
right: Box<Tree<B, U, A>>,
},
Unary {
conn: U,
next: Box<Tree<B, U, A>>,
},
Atom(A),
}
impl<B, U, A> Display for Tree<B, U, A>
where
B: Symbolic,
U: Symbolic,
A: Symbolic,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut repr = String::new();
self.read_inorder(&mut repr);
write!(f, "{}", repr)
}
}
impl<B, U, A> std::default::Default for Tree<B, U, A>
where
B: Symbolic,
U: Symbolic,
A: Symbolic,
{
fn default() -> Self {
Tree::Atom(A::default())
}
}
impl<B, U, A> Tree<B, U, A>
where
B: Symbolic,
U: Symbolic,
A: Symbolic,
{
pub fn new(atom: A) -> Self {
Tree::Atom(atom)
}
pub fn is_atomic(&self) -> bool {
if let Tree::Atom(_) = self {
true
} else {
false
}
}
pub fn is_unary(&self) -> bool {
if let Tree::Unary { .. } = self {
true
} else {
false
}
}
pub fn is_binary(&self) -> bool {
if let Tree::Binary { .. } = self {
true
} else {
false
}
}
pub fn combine(&mut self, bin: B, formula: Self) {
let old = std::mem::take(self);
*self = Tree::Binary {
conn: bin,
left: Box::new(old),
right: Box::new(formula),
}
}
pub fn left_combine(&mut self, bin: B, formula: Self) {
let old = std::mem::take(self);
*self = Tree::Binary {
conn: bin,
left: Box::new(formula),
right: Box::new(old),
}
}
pub fn unify(&mut self, un: U) {
let old = std::mem::take(self);
*self = Tree::Unary {
conn: un,
next: Box::new(old),
}
}
pub fn read_inorder(&self, repr: &mut String) {
match self {
Tree::Binary { conn, left, right } => {
if Symbol::from_tree(left.as_ref()) <= Symbol::Binary(*conn) {
repr.push_str("(");
left.read_inorder(repr);
repr.push_str(")");
} else {
left.read_inorder(repr)
};
repr.push_str(&conn.to_string());
if Symbol::from_tree(right.as_ref()) < Symbol::Binary(*conn) {
repr.push_str("(");
right.read_inorder(repr);
repr.push_str(")");
} else {
right.read_inorder(repr)
}
}
Tree::Unary { conn, next } => {
repr.push_str(&conn.to_string());
if Symbol::from_tree(next.as_ref()) < Symbol::Unary(*conn) {
repr.push_str("(");
next.read_inorder(repr);
repr.push_str(")");
} else {
next.read_inorder(repr)
}
}
Tree::Atom(a) => repr.push_str(&a.to_string()),
}
}
pub fn build_tree(syms: &[Symbol<B, U, A>]) -> Result<Self, ParseError> {
let symbols = Symbol::strip_parentheses(syms)?;
match Symbol::main_operator(symbols)? {
(i, Symbol::Binary(b)) => Ok(Tree::Binary {
conn: b,
left: Box::new(Self::build_tree(&symbols[..i])?),
right: Box::new(Self::build_tree(&symbols[i + 1..])?),
}),
(i, Symbol::Unary(u)) => Ok(Tree::Unary {
conn: u,
next: Box::new(Self::build_tree(&symbols[i + 1..])?),
}),
(_, Symbol::Atom(a)) => Ok(Tree::Atom(a)),
_ => unreachable!(), }
}
}
#[derive(PartialEq, Hash, Eq, PartialOrd, Ord, Clone, Debug, Default)]
pub enum Zipper<B, U, A>
where
B: Symbolic,
U: Symbolic,
A: Symbolic,
{
#[default]
Top,
Right {
bin: B,
sub: Tree<B, U, A>,
zip: Box<Zipper<B, U, A>>,
},
Left {
bin: B,
sub: Tree<B, U, A>,
zip: Box<Zipper<B, U, A>>,
},
Up {
un: U,
zip: Box<Zipper<B, U, A>>,
},
}
impl<B: Symbolic, U: Symbolic, A: Symbolic> Zipper<B, U, A> {
pub fn is_left(&self) -> bool {
if let Zipper::Left { .. } = self {
true
} else {
false
}
}
pub fn is_right(&self) -> bool {
if let Zipper::Right { .. } = self {
true
} else {
false
}
}
pub fn is_up(&self) -> bool {
if let Zipper::Up { .. } = self {
true
} else {
false
}
}
pub fn is_top(&self) -> bool {
if let Zipper::Top = self {
true
} else {
false
}
}
pub fn peek_up(&self) -> &Self {
match self {
Zipper::Top => self,
Zipper::Right { zip, .. } | Zipper::Left { zip, .. } | Zipper::Up { zip, .. } => {
zip.as_ref()
}
}
}
pub fn flip(&mut self) {
if let Zipper::Right { bin, sub, zip } = self {
*self = Zipper::Left {
bin: *bin,
sub: std::mem::take(sub),
zip: std::mem::take(zip),
}
} else if let Zipper::Left { bin, sub, zip } = self {
*self = Zipper::Right {
bin: *bin,
sub: std::mem::take(sub),
zip: std::mem::take(zip),
}
}
}
}
#[derive(PartialEq, Hash, Eq, PartialOrd, Ord, Clone, Debug, Default)]
pub struct Formula<B, U, A>
where
B: Symbolic,
U: Symbolic,
A: Symbolic,
{
pub tree: Tree<B, U, A>,
pub zipper: Zipper<B, U, A>,
}
impl<B, U, A> Formula<B, U, A>
where
B: Symbolic,
U: Symbolic,
A: Symbolic,
{
pub fn new(atom: A) -> Self {
Formula {
tree: Tree::Atom(atom),
zipper: Zipper::Top,
}
}
pub fn zip(&mut self) {
match &self.zipper {
Zipper::Top => {}
Zipper::Right { .. } => self.zip_right(),
Zipper::Left { .. } => self.zip_left(),
Zipper::Up { .. } => self.zip_up(),
}
}
pub fn zip_up(&mut self) {
if let Zipper::Up { un, zip } = &mut self.zipper {
self.tree.unify(*un);
self.zipper = std::mem::take((*zip).as_mut());
}
}
pub fn zip_right(&mut self) {
if let Zipper::Right { sub, bin, zip } = &mut self.zipper {
self.tree.combine(*bin, std::mem::take(sub));
self.zipper = std::mem::take((*zip).as_mut());
}
}
pub fn zip_left(&mut self) {
if let Zipper::Left { sub, bin, zip } = &mut self.zipper {
self.tree.left_combine(*bin, std::mem::take(sub));
self.zipper = std::mem::take((*zip).as_mut());
}
}
pub fn unzip_right(&mut self) {
if let Tree::Binary { conn, left, right } = &mut self.tree {
self.zipper = Zipper::Left {
bin: *conn,
sub: std::mem::take((*left).as_mut()),
zip: Box::new(std::mem::take(&mut self.zipper)),
};
self.tree = std::mem::take((*right).as_mut());
}
}
pub fn unzip_left(&mut self) {
if let Tree::Binary { conn, left, right } = &mut self.tree {
self.zipper = Zipper::Right {
bin: *conn,
sub: std::mem::take((*right).as_mut()),
zip: Box::new(std::mem::take(&mut self.zipper)),
};
self.tree = std::mem::take((*left).as_mut());
}
}
pub fn unzip_down(&mut self) {
if let Tree::Unary { conn, next } = &mut self.tree {
self.zipper = Zipper::Up {
un: *conn,
zip: Box::new(std::mem::take(&mut self.zipper)),
};
self.tree = std::mem::take((*next).as_mut());
}
}
pub fn top_zip(&mut self) {
while !self.zipper.is_top() {
self.zip();
}
}
pub fn combine(&mut self, bin: B, new_tree: Tree<B, U, A>) {
self.zipper = Zipper::Right {
bin,
sub: new_tree,
zip: Box::new(std::mem::take(&mut self.zipper)),
};
}
pub fn left_combine(&mut self, bin: B, new_tree: Tree<B, U, A>) {
self.zipper = Zipper::Left {
bin,
sub: new_tree,
zip: Box::new(std::mem::take(&mut self.zipper)),
};
}
pub fn top_combine(&mut self, bin: B, mut formula: Self) {
formula.top_zip();
self.top_zip();
self.combine(bin, formula.tree);
}
pub fn top_left_combine(&mut self, bin: B, mut formula: Self) {
formula.top_zip();
self.top_zip();
self.left_combine(bin, formula.tree)
}
pub fn unify(&mut self, un: U) {
self.zipper = Zipper::Up {
un,
zip: Box::new(std::mem::take(&mut self.zipper)),
};
}
pub fn top_unify(&mut self, un: U) {
cascade! {
self;
..top_zip();
..unify(un)
}
}
pub fn inorder_traverse_mut<F: FnMut(&mut Self)>(&mut self, func: &mut F) {
match &self.tree {
Tree::Binary { .. } => cascade! {
self;
..unzip_left();
..inorder_traverse_mut(func);
..zip(); ..apply_mut(func);
..unzip_right();
..inorder_traverse_mut(func);
..zip() },
Tree::Unary { .. } => cascade! {
self;
..apply_mut(func);
..unzip_down();
..inorder_traverse_mut(func);
..zip() },
Tree::Atom(_) => self.apply_mut(func),
}
}
pub fn preorder_traverse_mut<F: FnMut(&mut Self)>(&mut self, func: &mut F) {
self.apply_mut(func);
match &self.tree {
Tree::Binary { .. } => cascade! {
self;
..apply_mut(func);
..unzip_left();
..preorder_traverse_mut(func);
..zip(); ..unzip_right();
..preorder_traverse_mut(func);
..zip() },
Tree::Unary { .. } => cascade! {
self;
..apply_mut(func);
..unzip_down();
..preorder_traverse_mut(func);
..zip() },
Tree::Atom(_) => self.apply_mut(func),
}
}
pub fn apply_mut<F: FnMut(&mut Self)>(&mut self, func: &mut F) {
func(self);
}
pub fn flip(&mut self) {
self.zipper.flip()
}
pub fn rotate_left(&mut self) {
if let Formula {
tree:
Tree::Binary {
conn,
left: b,
right: c,
},
zipper: Zipper::Left { bin, sub: a, .. },
} = self
{
std::mem::swap(conn, bin);
std::mem::swap(b.as_mut(), c.as_mut());
std::mem::swap(a, b.as_mut()); }
self.flip()
}
pub fn rotate_right(&mut self) {
if let Formula {
tree:
Tree::Binary {
conn,
left: a,
right: b,
},
zipper: Zipper::Right { bin, sub: c, .. },
} = self
{
std::mem::swap(conn, bin);
std::mem::swap(a.as_mut(), b.as_mut());
std::mem::swap(c, b.as_mut()); }
self.flip()
}
pub fn distribute_right(&mut self) {
if !self.zipper.is_left() || !self.tree.is_binary() {
return;
}
cascade! {
let curr = self;
..rotate_left();
let (clone, bin) = if let &Tree::Binary {ref left, conn,.. } = &curr.tree {(left.as_ref().clone(), conn)}
else {unreachable!()};
..zip_right();
..unzip_right();
..left_combine(bin, clone)
}
}
pub fn distribute_left(&mut self) {
if !self.zipper.is_right() || !self.tree.is_binary() {
return;
}
cascade! {
let curr = self;
..rotate_right();
let (clone, bin) = if let &Tree::Binary {ref right, conn,.. } = &curr.tree {(right.as_ref().clone(), conn)}
else {unreachable!()};
..zip_left();
..unzip_left();
..combine(bin, clone)
}
}
pub fn lower_right(&mut self) {
if let Formula {
tree: Tree::Binary { right, .. },
zipper: Zipper::Up { un, zip },
} = self
{
right.as_mut().unify(*un);
self.zipper = *std::mem::take(zip);
}
}
pub fn lower_left(&mut self) {
if let Formula {
tree: Tree::Binary { left, .. },
zipper: Zipper::Up { un, zip },
} = self
{
left.as_mut().unify(*un);
self.zipper = *std::mem::take(zip);
}
}
pub fn distribute_down(&mut self, new_bin: Option<B>) {
if let Formula {
tree: Tree::Binary { conn, left, right },
zipper: Zipper::Up { un, zip },
} = self
{
left.unify(*un);
right.unify(*un);
if let Some(mut b) = new_bin {
std::mem::swap(&mut b, conn)
}
self.zipper = *std::mem::take(zip);
}
}
pub fn push_down(&mut self, new_un: Option<U>) {
if let Formula {
tree: Tree::Unary { conn, .. },
zipper: Zipper::Up { un, .. },
} = self
{
if let Some(mut u) = new_un {
std::mem::swap(&mut u, conn)
}
std::mem::swap(conn, un)
}
}
pub fn instantiate(&mut self, formulas: &HashMap<A, Tree<B, U, A>>) {
if let Tree::Atom(a) = self.tree {
if formulas.contains_key(&a) {
self.tree = formulas[&a].clone()
}
}
}
pub fn read_inorder(&self) -> String {
let mut written = String::new();
self.tree.read_inorder(&mut written);
let mut context: &Zipper<B, U, A> = &self.zipper;
loop {
match context {
Zipper::Top => break,
Zipper::Right { bin, sub, .. } => written += &(bin.to_string() + &sub.to_string()),
Zipper::Left { bin, sub, .. } => {
written = sub.to_string() + &bin.to_string() + &written
}
Zipper::Up { un, .. } => written = un.to_string() + &written,
}
context = context.peek_up();
}
written
}
}
impl<B, U, A> Display for Formula<B, U, A>
where
B: Symbolic,
U: Symbolic,
A: Symbolic,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.read_inorder())
}
}
impl<B: Symbolic + Match, U: Symbolic + Match, A: Symbolic + Match> Formula<B, U, A> {
pub fn from_str(value: &str) -> Result<Self, ParseError> {
Ok(Formula {
tree: Tree::build_tree(&ParsedSymbols::from(value).0?[..])?,
zipper: Zipper::Top,
})
}
}