ready_set_boole/src/ast.rs

346 lines
11 KiB
Rust
Raw Permalink Normal View History

2024-01-22 09:10:45 +00:00
mod tests;
2024-01-05 16:11:59 +00:00
2024-01-23 20:20:03 +00:00
#[derive(Debug, Clone, Copy, PartialEq)]
2024-01-05 16:11:59 +00:00
pub enum Token {
Negation,
Conjunction,
Disjunction,
ExclusiveDisjunction,
MaterialCondition,
2024-01-24 12:27:46 +00:00
LogicalEquivalence,
2024-01-05 16:11:59 +00:00
}
2024-01-22 09:10:45 +00:00
#[derive(Debug, Clone, PartialEq)]
2024-01-24 12:27:46 +00:00
pub enum Node<T>
where
T: Clone + std::fmt::Debug,
{
2024-01-05 16:11:59 +00:00
Leaf(T),
Unary {
operator: Token,
2024-01-24 12:27:46 +00:00
operand: Box<Node<T>>,
2024-01-05 16:11:59 +00:00
},
Binary {
operator: Token,
lhs: Box<Node<T>>,
rhs: Box<Node<T>>,
},
}
2024-01-23 20:20:03 +00:00
impl<T> Node<T>
2024-01-24 12:27:46 +00:00
where
T: Clone + std::fmt::Debug,
{
fn negation_conjunction_to_nnf(lhs: &Box<Node<T>>, rhs: &Box<Node<T>>) -> Node<T> {
Node::Binary {
operator: Token::Disjunction,
lhs: Box::new(Node::Unary {
operator: Token::Negation,
operand: Box::new(*lhs.clone()),
}),
rhs: Box::new(Node::Unary {
operator: Token::Negation,
operand: Box::new(*rhs.clone()),
}),
}
}
fn negation_disjunction_to_nnf(lhs: &Box<Node<T>>, rhs: &Box<Node<T>>) -> Node<T> {
Node::Binary {
operator: Token::Conjunction,
lhs: Box::new(Node::Unary {
operator: Token::Negation,
operand: Box::new(*lhs.clone()),
}),
rhs: Box::new(Node::Unary {
operator: Token::Negation,
operand: Box::new(*rhs.clone()),
}),
}
}
fn negation_material_condition_to_nnf(lhs: &Box<Node<T>>, rhs: &Box<Node<T>>) -> Node<T> {
Node::Binary {
operator: Token::Conjunction,
lhs: Box::new(*lhs.clone()),
rhs: Box::new(Node::Unary {
operator: Token::Negation,
operand: Box::new(*rhs.clone()),
}),
}
}
fn material_condition_to_nnf(lhs: &Box<Node<T>>, rhs: &Box<Node<T>>) -> Node<T> {
Node::Binary {
operator: Token::Disjunction,
lhs: Box::new(Node::Unary {
operator: Token::Negation,
operand: Box::new(*lhs.clone()),
}),
rhs: Box::new(*rhs.clone()),
}
}
fn negation_exclusive_disjunction_to_nnf(lhs: &Box<Node<T>>, rhs: &Box<Node<T>>) -> Node<T> {
Node::Binary {
operator: Token::Disjunction,
lhs: Box::new(Node::Binary {
operator: Token::Conjunction,
lhs: Box::new(Node::Unary {
operator: Token::Negation,
operand: Box::new(*lhs.clone()),
}),
rhs: Box::new(Node::Unary {
operator: Token::Negation,
operand: Box::new(*rhs.clone()),
}),
}),
rhs: Box::new(Node::Binary {
operator: Token::Conjunction,
lhs: Box::new(*lhs.clone()),
rhs: Box::new(*rhs.clone()),
}),
}
}
fn exclusive_disjunction_to_nnf(lhs: &Box<Node<T>>, rhs: &Box<Node<T>>) -> Node<T> {
Node::Binary {
operator: Token::Conjunction,
lhs: Box::new(Node::Binary {
operator: Token::Disjunction,
lhs: Box::new(*lhs.clone()),
rhs: Box::new(*rhs.clone()),
}),
rhs: Box::new(Node::Binary {
operator: Token::Disjunction,
lhs: Box::new(Node::Unary {
operator: Token::Negation,
operand: Box::new(*lhs.clone()),
}),
rhs: Box::new(Node::Unary {
operator: Token::Negation,
operand: Box::new(*rhs.clone()),
}),
}),
}
}
fn logical_equivalence_to_nnf(lhs: &Box<Node<T>>, rhs: &Box<Node<T>>) -> Node<T> {
Node::Binary {
operator: Token::Conjunction,
lhs: Box::new(Node::Binary {
operator: Token::Disjunction,
lhs: Box::new(Node::Unary {
operator: Token::Negation,
operand: Box::new(*lhs.clone()),
}),
rhs: Box::new(*rhs.clone()),
}),
rhs: Box::new(Node::Binary {
operator: Token::Disjunction,
lhs: Box::new(Node::Unary {
operator: Token::Negation,
operand: Box::new(*rhs.clone()),
}),
rhs: Box::new(*lhs.clone()),
}),
}
}
fn negation_logical_equivalence_to_nnf(lhs: &Box<Node<T>>, rhs: &Box<Node<T>>) -> Node<T> {
Node::Binary {
operator: Token::Disjunction,
lhs: Box::new(Node::Binary {
operator: Token::Conjunction,
lhs: Box::new(*lhs.clone()),
rhs: Box::new(Node::Unary {
operator: Token::Negation,
operand: Box::new(*rhs.clone()),
}),
}),
rhs: Box::new(Node::Binary {
operator: Token::Conjunction,
lhs: Box::new(*rhs.clone()),
rhs: Box::new(Node::Unary {
operator: Token::Negation,
operand: Box::new(*lhs.clone()),
}),
}),
}
}
2024-01-23 20:20:03 +00:00
pub fn simplify(&mut self) {
match self {
2024-01-24 12:27:46 +00:00
Node::Unary { operator, operand } if *operator == Token::Negation => match &**operand {
Node::Unary {
operator: inner_op,
operand: inner_operand,
} if *inner_op == Token::Negation => {
*self = *inner_operand.clone();
self.simplify();
}
Node::Binary {
operator: inner_op,
lhs: inner_lhs,
rhs: inner_rhs,
} => {
*self = match *inner_op {
Token::Conjunction => {
Self::negation_conjunction_to_nnf(inner_lhs, inner_rhs)
}
Token::Disjunction => {
Self::negation_disjunction_to_nnf(inner_lhs, inner_rhs)
}
Token::ExclusiveDisjunction => {
Self::negation_exclusive_disjunction_to_nnf(inner_lhs, inner_rhs)
}
Token::LogicalEquivalence => {
Self::negation_logical_equivalence_to_nnf(inner_lhs, inner_rhs)
}
Token::MaterialCondition => {
Self::negation_material_condition_to_nnf(inner_lhs, inner_rhs)
}
_ => unreachable!(),
};
self.simplify();
}
_ => (),
},
Node::Binary {
operator, lhs, rhs, ..
} => {
if let Some(node) = match *operator {
Token::ExclusiveDisjunction => {
Some(Self::exclusive_disjunction_to_nnf(lhs, rhs))
2024-01-23 20:20:03 +00:00
}
2024-01-24 12:27:46 +00:00
Token::LogicalEquivalence => Some(Self::logical_equivalence_to_nnf(lhs, rhs)),
Token::MaterialCondition => Some(Self::material_condition_to_nnf(lhs, rhs)),
_ => None,
} {
*self = node.clone();
self.simplify();
} else {
lhs.simplify();
rhs.simplify();
2024-01-23 20:20:03 +00:00
}
}
2024-01-24 12:27:46 +00:00
_ => (),
2024-01-23 20:20:03 +00:00
}
}
}
2024-01-22 17:34:40 +00:00
impl Node<bool> {
pub fn parse_formula(formula: &str) -> Node<bool> {
let mut stack = vec![];
for c in formula.chars() {
match c {
'0' => stack.push(Node::Leaf(false)),
'1' => stack.push(Node::Leaf(true)),
'!' => add_unary_node(&mut stack, Token::Negation),
'&' => add_binary_node(&mut stack, Token::Conjunction),
'|' => add_binary_node(&mut stack, Token::Disjunction),
'^' => add_binary_node(&mut stack, Token::ExclusiveDisjunction),
'>' => add_binary_node(&mut stack, Token::MaterialCondition),
'=' => add_binary_node(&mut stack, Token::LogicalEquivalence),
2024-01-24 12:27:46 +00:00
_ => panic!("Error: {} is not a valid character", c),
2024-01-22 17:34:40 +00:00
}
}
stack.pop().unwrap()
}
2024-01-23 20:20:03 +00:00
pub fn ast_to_formula(ast: &Node<bool>) -> String {
2024-01-22 17:34:40 +00:00
let mut str = String::from("");
match ast {
Node::Unary { operator, operand } => {
2024-01-23 20:20:03 +00:00
str.push_str(Self::ast_to_formula(operand).as_str());
str.push(token_to_char(*operator));
2024-01-24 12:27:46 +00:00
}
2024-01-22 17:34:40 +00:00
Node::Binary { operator, lhs, rhs } => {
2024-01-23 20:20:03 +00:00
str.push_str(Self::ast_to_formula(lhs).as_str());
str.push_str(Self::ast_to_formula(rhs).as_str());
str.push(token_to_char(*operator));
2024-01-24 12:27:46 +00:00
}
2024-01-23 20:20:03 +00:00
Node::Leaf(b) => str.push(bool_to_char(*b)),
2024-01-22 17:34:40 +00:00
};
str
}
2024-01-24 12:27:46 +00:00
}
2024-01-22 17:34:40 +00:00
impl Node<char> {
pub fn parse_formula(formula: &str) -> Node<char> {
let mut stack = vec![];
for c in formula.chars() {
match c {
'A'..='Z' => stack.push(Node::Leaf(c)),
'!' => add_unary_node(&mut stack, Token::Negation),
'&' => add_binary_node(&mut stack, Token::Conjunction),
'|' => add_binary_node(&mut stack, Token::Disjunction),
'^' => add_binary_node(&mut stack, Token::ExclusiveDisjunction),
'>' => add_binary_node(&mut stack, Token::MaterialCondition),
'=' => add_binary_node(&mut stack, Token::LogicalEquivalence),
2024-01-24 12:27:46 +00:00
_ => panic!("Error: {} is not a valid character", c),
2024-01-22 17:34:40 +00:00
}
}
stack.pop().unwrap()
}
2024-01-23 20:20:03 +00:00
pub fn ast_to_formula(ast: &Node<char>) -> String {
2024-01-22 17:34:40 +00:00
let mut str = String::from("");
match ast {
Node::Unary { operator, operand } => {
2024-01-23 20:20:03 +00:00
str.push_str(Self::ast_to_formula(operand).as_str());
str.push(token_to_char(*operator));
2024-01-24 12:27:46 +00:00
}
2024-01-22 17:34:40 +00:00
Node::Binary { operator, lhs, rhs } => {
2024-01-23 20:20:03 +00:00
str.push_str(Self::ast_to_formula(lhs).as_str());
str.push_str(Self::ast_to_formula(rhs).as_str());
str.push(token_to_char(*operator));
2024-01-24 12:27:46 +00:00
}
2024-01-23 20:20:03 +00:00
Node::Leaf(c) => str.push(*c),
2024-01-22 17:34:40 +00:00
};
str
}
}
2024-01-24 12:27:46 +00:00
pub fn add_unary_node<T>(stack: &mut Vec<Node<T>>, token: Token)
where
T: Clone + std::fmt::Debug,
{
2024-01-05 16:11:59 +00:00
let operand = Box::new(stack.pop().unwrap());
stack.push(Node::Unary {
operator: token,
operand,
});
}
2024-01-24 12:27:46 +00:00
pub fn add_binary_node<T>(stack: &mut Vec<Node<T>>, token: Token)
where
T: Clone + std::fmt::Debug,
{
2024-01-05 16:11:59 +00:00
let rhs = Box::new(stack.pop().unwrap());
2024-01-22 09:10:45 +00:00
let lhs = Box::new(stack.pop().unwrap());
2024-01-05 16:11:59 +00:00
stack.push(Node::Binary {
operator: token,
lhs,
2024-01-24 12:27:46 +00:00
rhs,
2024-01-05 16:11:59 +00:00
});
2024-01-22 09:10:45 +00:00
}
fn bool_to_char(b: bool) -> char {
match b {
false => '0',
2024-01-24 12:27:46 +00:00
true => '1',
2024-01-22 09:10:45 +00:00
}
}
fn token_to_char(token: Token) -> char {
match token {
Token::Negation => '!',
2024-01-24 12:27:46 +00:00
Token::Conjunction => '&',
2024-01-22 09:10:45 +00:00
Token::Disjunction => '|',
Token::ExclusiveDisjunction => '^',
Token::MaterialCondition => '>',
Token::LogicalEquivalence => '=',
}
}