Compare commits
No commits in common. "dea2e2d6a3edd64152f4669a422d2722762779e8" and "a13dfeaeebba0a2681634038a75d42b5de465e2a" have entirely different histories.
dea2e2d6a3
...
a13dfeaeeb
|
@ -12,3 +12,4 @@ pub fn adder(a: u32, b: u32) -> u32 {
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
271
src/ast.rs
271
src/ast.rs
|
@ -1,24 +1,22 @@
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
Negation,
|
Negation,
|
||||||
Conjunction,
|
Conjunction,
|
||||||
Disjunction,
|
Disjunction,
|
||||||
ExclusiveDisjunction,
|
ExclusiveDisjunction,
|
||||||
MaterialCondition,
|
MaterialCondition,
|
||||||
LogicalEquivalence,
|
LogicalEquivalence
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Node<T>
|
pub enum Node<T> {
|
||||||
where
|
|
||||||
T: Clone + std::fmt::Debug,
|
|
||||||
{
|
|
||||||
Leaf(T),
|
Leaf(T),
|
||||||
Unary {
|
Unary {
|
||||||
operator: Token,
|
operator: Token,
|
||||||
operand: Box<Node<T>>,
|
operand: Box<Node<T>>
|
||||||
},
|
},
|
||||||
Binary {
|
Binary {
|
||||||
operator: Token,
|
operator: Token,
|
||||||
|
@ -27,208 +25,6 @@ where
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Node<T>
|
|
||||||
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()),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn simplify(&mut self) {
|
|
||||||
match self {
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Node<bool> {
|
impl Node<bool> {
|
||||||
pub fn parse_formula(formula: &str) -> Node<bool> {
|
pub fn parse_formula(formula: &str) -> Node<bool> {
|
||||||
let mut stack = vec![];
|
let mut stack = vec![];
|
||||||
|
@ -242,25 +38,25 @@ impl Node<bool> {
|
||||||
'^' => add_binary_node(&mut stack, Token::ExclusiveDisjunction),
|
'^' => add_binary_node(&mut stack, Token::ExclusiveDisjunction),
|
||||||
'>' => add_binary_node(&mut stack, Token::MaterialCondition),
|
'>' => add_binary_node(&mut stack, Token::MaterialCondition),
|
||||||
'=' => add_binary_node(&mut stack, Token::LogicalEquivalence),
|
'=' => add_binary_node(&mut stack, Token::LogicalEquivalence),
|
||||||
_ => panic!("Error: {} is not a valid character", c),
|
_ => panic!("Error: {} is not a valid character", c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stack.pop().unwrap()
|
stack.pop().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ast_to_formula(ast: &Node<bool>) -> String {
|
pub fn ast_to_formula(ast: Node<bool>) -> String {
|
||||||
let mut str = String::from("");
|
let mut str = String::from("");
|
||||||
match ast {
|
match ast {
|
||||||
Node::Unary { operator, operand } => {
|
Node::Unary { operator, operand } => {
|
||||||
str.push_str(Self::ast_to_formula(operand).as_str());
|
str.push_str(Self::ast_to_formula(*operand).as_str());
|
||||||
str.push(token_to_char(*operator));
|
str.push(token_to_char(operator));
|
||||||
}
|
},
|
||||||
Node::Binary { operator, lhs, rhs } => {
|
Node::Binary { operator, lhs, rhs } => {
|
||||||
str.push_str(Self::ast_to_formula(lhs).as_str());
|
str.push_str(Self::ast_to_formula(*lhs).as_str());
|
||||||
str.push_str(Self::ast_to_formula(rhs).as_str());
|
str.push_str(Self::ast_to_formula(*rhs).as_str());
|
||||||
str.push(token_to_char(*operator));
|
str.push(token_to_char(operator));
|
||||||
}
|
},
|
||||||
Node::Leaf(b) => str.push(bool_to_char(*b)),
|
Node::Leaf(b) => str.push(bool_to_char(b)),
|
||||||
};
|
};
|
||||||
str
|
str
|
||||||
}
|
}
|
||||||
|
@ -278,34 +74,31 @@ impl Node<char> {
|
||||||
'^' => add_binary_node(&mut stack, Token::ExclusiveDisjunction),
|
'^' => add_binary_node(&mut stack, Token::ExclusiveDisjunction),
|
||||||
'>' => add_binary_node(&mut stack, Token::MaterialCondition),
|
'>' => add_binary_node(&mut stack, Token::MaterialCondition),
|
||||||
'=' => add_binary_node(&mut stack, Token::LogicalEquivalence),
|
'=' => add_binary_node(&mut stack, Token::LogicalEquivalence),
|
||||||
_ => panic!("Error: {} is not a valid character", c),
|
_ => panic!("Error: {} is not a valid character", c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stack.pop().unwrap()
|
stack.pop().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ast_to_formula(ast: &Node<char>) -> String {
|
pub fn ast_to_formula(ast: Node<char>) -> String {
|
||||||
let mut str = String::from("");
|
let mut str = String::from("");
|
||||||
match ast {
|
match ast {
|
||||||
Node::Unary { operator, operand } => {
|
Node::Unary { operator, operand } => {
|
||||||
str.push_str(Self::ast_to_formula(operand).as_str());
|
str.push_str(Self::ast_to_formula(*operand).as_str());
|
||||||
str.push(token_to_char(*operator));
|
str.push(token_to_char(operator));
|
||||||
}
|
},
|
||||||
Node::Binary { operator, lhs, rhs } => {
|
Node::Binary { operator, lhs, rhs } => {
|
||||||
str.push_str(Self::ast_to_formula(lhs).as_str());
|
str.push_str(Self::ast_to_formula(*lhs).as_str());
|
||||||
str.push_str(Self::ast_to_formula(rhs).as_str());
|
str.push_str(Self::ast_to_formula(*rhs).as_str());
|
||||||
str.push(token_to_char(*operator));
|
str.push(token_to_char(operator));
|
||||||
}
|
},
|
||||||
Node::Leaf(c) => str.push(*c),
|
Node::Leaf(c) => str.push(c),
|
||||||
};
|
};
|
||||||
str
|
str
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_unary_node<T>(stack: &mut Vec<Node<T>>, token: Token)
|
pub fn add_unary_node<T>(stack: &mut Vec<Node<T>>, token: Token) {
|
||||||
where
|
|
||||||
T: Clone + std::fmt::Debug,
|
|
||||||
{
|
|
||||||
let operand = Box::new(stack.pop().unwrap());
|
let operand = Box::new(stack.pop().unwrap());
|
||||||
stack.push(Node::Unary {
|
stack.push(Node::Unary {
|
||||||
operator: token,
|
operator: token,
|
||||||
|
@ -313,33 +106,31 @@ where
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_binary_node<T>(stack: &mut Vec<Node<T>>, token: Token)
|
pub fn add_binary_node<T>(stack: &mut Vec<Node<T>>, token: Token) {
|
||||||
where
|
|
||||||
T: Clone + std::fmt::Debug,
|
|
||||||
{
|
|
||||||
let rhs = Box::new(stack.pop().unwrap());
|
let rhs = Box::new(stack.pop().unwrap());
|
||||||
let lhs = Box::new(stack.pop().unwrap());
|
let lhs = Box::new(stack.pop().unwrap());
|
||||||
stack.push(Node::Binary {
|
stack.push(Node::Binary {
|
||||||
operator: token,
|
operator: token,
|
||||||
lhs,
|
lhs,
|
||||||
rhs,
|
rhs
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bool_to_char(b: bool) -> char {
|
fn bool_to_char(b: bool) -> char {
|
||||||
match b {
|
match b {
|
||||||
false => '0',
|
false => '0',
|
||||||
true => '1',
|
true => '1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn token_to_char(token: Token) -> char {
|
fn token_to_char(token: Token) -> char {
|
||||||
match token {
|
match token {
|
||||||
Token::Negation => '!',
|
Token::Negation => '!',
|
||||||
Token::Conjunction => '&',
|
Token::Conjunction =>'&',
|
||||||
Token::Disjunction => '|',
|
Token::Disjunction => '|',
|
||||||
Token::ExclusiveDisjunction => '^',
|
Token::ExclusiveDisjunction => '^',
|
||||||
Token::MaterialCondition => '>',
|
Token::MaterialCondition => '>',
|
||||||
Token::LogicalEquivalence => '=',
|
Token::LogicalEquivalence => '=',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::ast::{add_binary_node, Node, Token};
|
use crate::ast::{ add_binary_node, Node, Token };
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add_nodes() {
|
fn add_nodes() {
|
||||||
|
@ -8,7 +8,7 @@ mod tests {
|
||||||
let rhs = vec![Node::Binary {
|
let rhs = vec![Node::Binary {
|
||||||
operator: Token::Conjunction,
|
operator: Token::Conjunction,
|
||||||
lhs: Box::new(Node::Leaf(true)),
|
lhs: Box::new(Node::Leaf(true)),
|
||||||
rhs: Box::new(Node::Leaf(false)),
|
rhs: Box::new(Node::Leaf(false))
|
||||||
}];
|
}];
|
||||||
add_binary_node(&mut stack, Token::Conjunction);
|
add_binary_node(&mut stack, Token::Conjunction);
|
||||||
assert_eq!(stack, rhs);
|
assert_eq!(stack, rhs);
|
||||||
|
@ -17,58 +17,28 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn ast_to_formula_bool() {
|
fn ast_to_formula_bool() {
|
||||||
let formula = "01&";
|
let formula = "01&";
|
||||||
assert_eq!(
|
assert_eq!(Node::<bool>::ast_to_formula(Node::<bool>::parse_formula(formula)), formula);
|
||||||
Node::<bool>::ast_to_formula(&Node::<bool>::parse_formula(formula)),
|
|
||||||
formula
|
|
||||||
);
|
|
||||||
let formula = "01&00|&";
|
let formula = "01&00|&";
|
||||||
assert_eq!(
|
assert_eq!(Node::<bool>::ast_to_formula(Node::<bool>::parse_formula(formula)), formula);
|
||||||
Node::<bool>::ast_to_formula(&Node::<bool>::parse_formula(formula)),
|
|
||||||
formula
|
|
||||||
);
|
|
||||||
let formula = "01&00|&11^&";
|
let formula = "01&00|&11^&";
|
||||||
assert_eq!(
|
assert_eq!(Node::<bool>::ast_to_formula(Node::<bool>::parse_formula(formula)), formula);
|
||||||
Node::<bool>::ast_to_formula(&Node::<bool>::parse_formula(formula)),
|
|
||||||
formula
|
|
||||||
);
|
|
||||||
let formula = "01&00|&11=^";
|
let formula = "01&00|&11=^";
|
||||||
assert_eq!(
|
assert_eq!(Node::<bool>::ast_to_formula(Node::<bool>::parse_formula(formula)), formula);
|
||||||
Node::<bool>::ast_to_formula(&Node::<bool>::parse_formula(formula)),
|
|
||||||
formula
|
|
||||||
);
|
|
||||||
let formula = "01&00|&0!=";
|
let formula = "01&00|&0!=";
|
||||||
assert_eq!(
|
assert_eq!(Node::<bool>::ast_to_formula(Node::<bool>::parse_formula(formula)), formula);
|
||||||
Node::<bool>::ast_to_formula(&Node::<bool>::parse_formula(formula)),
|
|
||||||
formula
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ast_to_formula_char() {
|
fn ast_to_formula_char() {
|
||||||
let formula = "AB&";
|
let formula = "AB&";
|
||||||
assert_eq!(
|
assert_eq!(Node::<char>::ast_to_formula(Node::<char>::parse_formula(formula)), formula);
|
||||||
Node::<char>::ast_to_formula(&Node::<char>::parse_formula(formula)),
|
|
||||||
formula
|
|
||||||
);
|
|
||||||
let formula = "AB&CD|&";
|
let formula = "AB&CD|&";
|
||||||
assert_eq!(
|
assert_eq!(Node::<char>::ast_to_formula(Node::<char>::parse_formula(formula)), formula);
|
||||||
Node::<char>::ast_to_formula(&Node::<char>::parse_formula(formula)),
|
|
||||||
formula
|
|
||||||
);
|
|
||||||
let formula = "AB&AC|&DE^&";
|
let formula = "AB&AC|&DE^&";
|
||||||
assert_eq!(
|
assert_eq!(Node::<char>::ast_to_formula(Node::<char>::parse_formula(formula)), formula);
|
||||||
Node::<char>::ast_to_formula(&Node::<char>::parse_formula(formula)),
|
|
||||||
formula
|
|
||||||
);
|
|
||||||
let formula = "AB&CD|&EF=^";
|
let formula = "AB&CD|&EF=^";
|
||||||
assert_eq!(
|
assert_eq!(Node::<char>::ast_to_formula(Node::<char>::parse_formula(formula)), formula);
|
||||||
Node::<char>::ast_to_formula(&Node::<char>::parse_formula(formula)),
|
|
||||||
formula
|
|
||||||
);
|
|
||||||
let formula = "AB&CD|&E!=";
|
let formula = "AB&CD|&E!=";
|
||||||
assert_eq!(
|
assert_eq!(Node::<char>::ast_to_formula(Node::<char>::parse_formula(formula)), formula);
|
||||||
Node::<char>::ast_to_formula(&Node::<char>::parse_formula(formula)),
|
|
||||||
formula
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
use crate::ast::{Node, Token};
|
use crate::ast::{ Token, Node };
|
||||||
|
|
||||||
fn compute(operator: Token, lhs: bool, rhs: bool) -> bool {
|
fn compute(operator: Token, lhs: bool, rhs: bool) -> bool {
|
||||||
match operator {
|
match operator {
|
||||||
|
@ -9,7 +9,7 @@ fn compute(operator: Token, lhs: bool, rhs: bool) -> bool {
|
||||||
Token::Disjunction => lhs | rhs,
|
Token::Disjunction => lhs | rhs,
|
||||||
Token::ExclusiveDisjunction => lhs ^ rhs,
|
Token::ExclusiveDisjunction => lhs ^ rhs,
|
||||||
Token::MaterialCondition => !(lhs && !rhs),
|
Token::MaterialCondition => !(lhs && !rhs),
|
||||||
Token::LogicalEquivalence => lhs == rhs,
|
Token::LogicalEquivalence => lhs == rhs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,10 +22,7 @@ mod tests {
|
||||||
assert_eq!(eval_formula("1!!"), true);
|
assert_eq!(eval_formula("1!!"), true);
|
||||||
assert_eq!(eval_formula("0!!"), false);
|
assert_eq!(eval_formula("0!!"), false);
|
||||||
assert_eq!(eval_formula("0!!!"), true);
|
assert_eq!(eval_formula("0!!!"), true);
|
||||||
assert_eq!(
|
assert_eq!(eval_formula("1!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"), true);
|
||||||
eval_formula("1!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -10,3 +10,4 @@ pub fn gray_code(n: u32) -> u32 {
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
mod adder;
|
mod adder;
|
||||||
mod ast;
|
|
||||||
mod boolean_evaluation;
|
|
||||||
mod gray_code;
|
|
||||||
mod multiplier;
|
mod multiplier;
|
||||||
mod negation_normal_form;
|
mod gray_code;
|
||||||
|
mod boolean_evaluation;
|
||||||
mod truth_table;
|
mod truth_table;
|
||||||
|
mod ast;
|
||||||
|
mod negation_normal_form;
|
||||||
|
|
||||||
use gray_code::gray_code;
|
use gray_code::gray_code;
|
||||||
use truth_table::print_truth_table;
|
use truth_table::print_truth_table;
|
||||||
|
|
|
@ -2,8 +2,29 @@ mod tests;
|
||||||
|
|
||||||
use crate::ast::Node;
|
use crate::ast::Node;
|
||||||
|
|
||||||
|
// fn cancel_double_negation(ast: Node<char>) {
|
||||||
|
// let mut new_ast = ast.clone();
|
||||||
|
|
||||||
|
// fn recursion(ast: &mut Node<char>, node_count: usize) {
|
||||||
|
// match ast {
|
||||||
|
// Node::Unary { operator: _, operand } => {
|
||||||
|
// recursion(&mut *operand, node_count + 1);
|
||||||
|
// },
|
||||||
|
// Node::Binary { operator: _, lhs, rhs } => {
|
||||||
|
// recursion(&mut *lhs, node_count + 1);
|
||||||
|
// recursion(&mut *rhs, node_count + 1);
|
||||||
|
// },
|
||||||
|
// Node::Leaf(c) => (),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// recursion(&mut new_ast, 0);
|
||||||
|
|
||||||
|
// new_ast
|
||||||
|
// }
|
||||||
|
|
||||||
fn negation_normal_form(formula: &str) -> String {
|
fn negation_normal_form(formula: &str) -> String {
|
||||||
let mut ast = Node::<char>::parse_formula(formula);
|
let ast = Node::<char>::parse_formula(formula);
|
||||||
ast.simplify();
|
|
||||||
Node::<char>::ast_to_formula(&ast)
|
Node::<char>::ast_to_formula(ast)
|
||||||
}
|
}
|
|
@ -2,67 +2,22 @@
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::negation_normal_form::negation_normal_form;
|
use crate::negation_normal_form::negation_normal_form;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn double_neg_simple() {
|
|
||||||
assert_eq!(negation_normal_form("A!!"), "A");
|
|
||||||
assert_eq!(negation_normal_form("B!!!!"), "B");
|
|
||||||
assert_eq!(negation_normal_form("C!!!"), "C!");
|
|
||||||
assert_eq!(negation_normal_form("D!!!!!!!!!!!!!!!!"), "D");
|
|
||||||
assert_eq!(negation_normal_form("E!!!!!!!!!!!!!!!"), "E!");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn double_neg() {
|
fn double_neg() {
|
||||||
assert_eq!(negation_normal_form("A!!Z&"), "AZ&");
|
assert_eq!(negation_normal_form("A!!"), "A");
|
||||||
assert_eq!(negation_normal_form("B!!Z!!&"), "BZ&");
|
assert_eq!(negation_normal_form("A!!!!"), "A");
|
||||||
assert_eq!(negation_normal_form("C!!Z!&"), "CZ!&");
|
assert_eq!(negation_normal_form("A!!!"), "A!");
|
||||||
assert_eq!(negation_normal_form("D!!Z&!!!!"), "DZ&");
|
assert_eq!(negation_normal_form("A!!!!!!!!!!!!!!!!"), "A");
|
||||||
assert_eq!(negation_normal_form("E!!Z!!!!&!!"), "EZ&");
|
assert_eq!(negation_normal_form("A!!!!!!!!!!!!!!!"), "A!");
|
||||||
assert_eq!(negation_normal_form("F!!Z!&!!!!!!!!"), "FZ!&");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn neg_and() {
|
fn neg_and() {
|
||||||
assert_eq!(negation_normal_form("AZ&!"), "A!Z!|");
|
assert_eq!(negation_normal_form("AB&!"), "A!B!|");
|
||||||
assert_eq!(negation_normal_form("BZ&!BZ&!&"), "B!Z!|B!Z!|&");
|
|
||||||
assert_eq!(negation_normal_form("CZ&!CZ&!&!"), "CZ&CZ&|");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn neg_or() {
|
fn neg_or() {
|
||||||
assert_eq!(negation_normal_form("AZ|!"), "A!Z!&");
|
|
||||||
assert_eq!(negation_normal_form("BZ|!BZ|!|"), "B!Z!&B!Z!&|");
|
|
||||||
assert_eq!(negation_normal_form("CZ|!CZ|!|!"), "CZ|CZ|&");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn material_condition() {
|
|
||||||
assert_eq!(negation_normal_form("AZ>"), "A!Z|");
|
|
||||||
assert_eq!(negation_normal_form("BZ>!"), "BZ!&");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn exclusive_disjunction() {
|
|
||||||
assert_eq!(negation_normal_form("AZ^"), "AZ|A!Z!|&");
|
|
||||||
assert_eq!(negation_normal_form("BZ^!"), "B!Z!&BZ&|");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn logical_equivalence() {
|
|
||||||
assert_eq!(negation_normal_form("AZ="), "A!Z|Z!A|&");
|
|
||||||
assert_eq!(negation_normal_form("BZ=!"), "BZ!&ZB!&|");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn subject_tests() {
|
|
||||||
assert_eq!(negation_normal_form("AB&!"), "A!B!|");
|
|
||||||
assert_eq!(negation_normal_form("AB|!"), "A!B!&");
|
assert_eq!(negation_normal_form("AB|!"), "A!B!&");
|
||||||
assert_eq!(negation_normal_form("AB>"), "A!B|");
|
|
||||||
assert_eq!(negation_normal_form("AB|C&!"), "A!B!&C!|");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn complex_tests() {
|
|
||||||
assert_eq!("A", "A");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
use crate::ast::{add_binary_node, add_unary_node, Node, Token};
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use crate::ast::{ Token, Node, add_unary_node, add_binary_node };
|
||||||
|
|
||||||
fn parse_formula(formula: &str) -> Node<bool> {
|
fn parse_formula(formula: &str) -> Node<bool> {
|
||||||
let mut stack = vec![];
|
let mut stack = vec![];
|
||||||
|
@ -15,7 +15,7 @@ fn parse_formula(formula: &str) -> Node<bool> {
|
||||||
'^' => add_binary_node(&mut stack, Token::ExclusiveDisjunction),
|
'^' => add_binary_node(&mut stack, Token::ExclusiveDisjunction),
|
||||||
'>' => add_binary_node(&mut stack, Token::MaterialCondition),
|
'>' => add_binary_node(&mut stack, Token::MaterialCondition),
|
||||||
'=' => add_binary_node(&mut stack, Token::LogicalEquivalence),
|
'=' => add_binary_node(&mut stack, Token::LogicalEquivalence),
|
||||||
_ => panic!("Error: {} is not a valid character", c),
|
_ => panic!("Error: {} is not a valid character", c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stack.pop().unwrap()
|
stack.pop().unwrap()
|
||||||
|
@ -28,7 +28,7 @@ fn compute(operator: Token, lhs: bool, rhs: bool) -> bool {
|
||||||
Token::Disjunction => lhs | rhs,
|
Token::Disjunction => lhs | rhs,
|
||||||
Token::ExclusiveDisjunction => lhs ^ rhs,
|
Token::ExclusiveDisjunction => lhs ^ rhs,
|
||||||
Token::MaterialCondition => !(lhs && !rhs),
|
Token::MaterialCondition => !(lhs && !rhs),
|
||||||
Token::LogicalEquivalence => lhs == rhs,
|
Token::LogicalEquivalence => lhs == rhs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,9 +45,7 @@ fn get_hashset(formula: &str) -> HashSet<char> {
|
||||||
|
|
||||||
for c in formula.chars() {
|
for c in formula.chars() {
|
||||||
match c {
|
match c {
|
||||||
'A'..='Z' => {
|
'A'..='Z' => { hashset.insert(c); },
|
||||||
hashset.insert(c);
|
|
||||||
}
|
|
||||||
'!' | '&' | '|' | '^' | '>' | '=' => (),
|
'!' | '&' | '|' | '^' | '>' | '=' => (),
|
||||||
_ => panic!("Error: {} is not a valid character", c),
|
_ => panic!("Error: {} is not a valid character", c),
|
||||||
}
|
}
|
||||||
|
@ -63,16 +61,8 @@ fn eval_formula(formula: &str) -> bool {
|
||||||
fn recursive_fn(formula: &str, mut vec: Vec<char>, format: String) {
|
fn recursive_fn(formula: &str, mut vec: Vec<char>, format: String) {
|
||||||
let char = vec.pop();
|
let char = vec.pop();
|
||||||
if let Some(c) = char {
|
if let Some(c) = char {
|
||||||
recursive_fn(
|
recursive_fn(formula.replace(c, "0").as_str(), vec.clone(), format!("{format} 0 |"));
|
||||||
formula.replace(c, "0").as_str(),
|
recursive_fn(formula.replace(c, "1").as_str(), vec.clone(), format!("{format} 1 |"));
|
||||||
vec.clone(),
|
|
||||||
format!("{format} 0 |"),
|
|
||||||
);
|
|
||||||
recursive_fn(
|
|
||||||
formula.replace(c, "1").as_str(),
|
|
||||||
vec.clone(),
|
|
||||||
format!("{format} 1 |"),
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
match eval_formula(formula) {
|
match eval_formula(formula) {
|
||||||
false => println!("{format} 0 |"),
|
false => println!("{format} 0 |"),
|
||||||
|
|
Loading…
Reference in New Issue