From 2300d91fad7ad33738e97ec1bc7e15397fe37d70 Mon Sep 17 00:00:00 2001 From: gbrochar Date: Mon, 22 Jan 2024 10:10:45 +0100 Subject: [PATCH 1/5] feat|test: ast --- src/ast.rs | 43 ++++++++++++++++++++++++++++++--- src/ast/tests.rs | 22 +++++++++++++++-- src/boolean_evaluation.rs | 4 +-- src/boolean_evaluation/tests.rs | 2 -- src/main.rs | 12 +++++++++ src/truth_table.rs | 5 ++-- src/truth_table/tests.rs | 2 +- 7 files changed, 78 insertions(+), 12 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index e0efaae..92a5863 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1,5 +1,7 @@ +mod tests; -#[derive(Debug, Clone)] + +#[derive(Debug, Clone, PartialEq)] pub enum Token { Negation, Conjunction, @@ -9,7 +11,7 @@ pub enum Token { LogicalEquivalence } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub enum Node { Leaf(T), Unary { @@ -32,11 +34,46 @@ pub fn add_unary_node(stack: &mut Vec>, token: Token) { } pub fn add_binary_node(stack: &mut Vec>, token: Token) { - let lhs = Box::new(stack.pop().unwrap()); let rhs = Box::new(stack.pop().unwrap()); + let lhs = Box::new(stack.pop().unwrap()); stack.push(Node::Binary { operator: token, lhs, rhs }); +} + +fn bool_to_char(b: bool) -> char { + match b { + false => '0', + true => '1' + } +} + +fn token_to_char(token: Token) -> char { + match token { + Token::Negation => '!', + Token::Conjunction =>'&', + Token::Disjunction => '|', + Token::ExclusiveDisjunction => '^', + Token::MaterialCondition => '>', + Token::LogicalEquivalence => '=', + } +} + +fn ast_to_formula(ast: Node) -> String { + let mut str = String::from(""); + match ast { + Node::Unary { operator, operand } => { + str.push_str(ast_to_formula(*operand).as_str()); + str.push(token_to_char(operator)); + }, + Node::Binary { operator, lhs, rhs } => { + str.push_str(ast_to_formula(*rhs).as_str()); + str.push_str(ast_to_formula(*lhs).as_str()); + str.push(token_to_char(operator)); + }, + Node::Leaf(b) => str.push(bool_to_char(b)), + }; + str } \ No newline at end of file diff --git a/src/ast/tests.rs b/src/ast/tests.rs index 085d695..25c9509 100644 --- a/src/ast/tests.rs +++ b/src/ast/tests.rs @@ -1,13 +1,31 @@ #[cfg(test)] mod tests { + use crate::ast::{ add_binary_node, ast_to_formula, Node, Token }; + use crate::boolean_evaluation::parse_formula; + #[test] fn add_nodes() { - let stack = vec![Node::Leaf(true), Node::Leaf(false)]; + let mut stack = vec![Node::Leaf(true), Node::Leaf(false)]; let rhs = vec![Node::Binary { operator: Token::Conjunction, lhs: Box::new(Node::Leaf(true)), rhs: Box::new(Node::Leaf(false)) }]; - assert_eq!(add_binary_node(&mut stack, Token::Conjunction), rhs); + add_binary_node(&mut stack, Token::Conjunction); + assert_eq!(stack, rhs); + } + + #[test] + fn reverse_ast() { + let formula = "01&"; + assert_eq!(ast_to_formula(parse_formula(formula)), formula); + let formula = "01&00|&"; + assert_eq!(ast_to_formula(parse_formula(formula)), formula); + let formula = "01&00|&11^&"; + assert_eq!(ast_to_formula(parse_formula(formula)), formula); + let formula = "01&00|&11=^"; + assert_eq!(ast_to_formula(parse_formula(formula)), formula); + let formula = "01&00|&0!="; + assert_eq!(ast_to_formula(parse_formula(formula)), formula); } } \ No newline at end of file diff --git a/src/boolean_evaluation.rs b/src/boolean_evaluation.rs index 18f89e7..4a34b80 100644 --- a/src/boolean_evaluation.rs +++ b/src/boolean_evaluation.rs @@ -2,7 +2,7 @@ mod tests; use crate::ast::{ Token, Node, add_unary_node, add_binary_node }; -fn parse_formula(formula: &str) -> Node { +pub fn parse_formula(formula: &str) -> Node { let mut stack = vec![]; for c in formula.chars() { match c { @@ -39,7 +39,7 @@ fn evaluate(tree: Node) -> bool { } } -fn eval_formula(formula: &str) -> bool { +pub fn eval_formula(formula: &str) -> bool { let tree = parse_formula(formula); evaluate(tree) } \ No newline at end of file diff --git a/src/boolean_evaluation/tests.rs b/src/boolean_evaluation/tests.rs index daa6150..2430f40 100644 --- a/src/boolean_evaluation/tests.rs +++ b/src/boolean_evaluation/tests.rs @@ -15,7 +15,6 @@ mod tests { fn only_unary() { assert_eq!(eval_formula("1!"), false); assert_eq!(eval_formula("0!"), true); - } #[test] @@ -24,7 +23,6 @@ mod tests { assert_eq!(eval_formula("0!!"), false); assert_eq!(eval_formula("0!!!"), true); assert_eq!(eval_formula("1!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"), true); - } #[test] diff --git a/src/main.rs b/src/main.rs index 79b9e84..5dc93d7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,8 @@ mod truth_table; mod ast; use gray_code::gray_code; +use truth_table::print_truth_table; +use boolean_evaluation::eval_formula; fn main() { println!("Hello, world!"); @@ -18,4 +20,14 @@ fn main() { println!("{}", gray_code(15)); println!("{}", gray_code(7)); println!("{}", gray_code(3)); + print_truth_table("ABC|&"); + //print_truth_table("ABCF&&&"); + // println!("{}", eval_formula("000|&")); + // println!("{}", eval_formula("001|&")); + // println!("{}", eval_formula("010|&")); + // println!("{}", eval_formula("011|&")); + // println!("{}", eval_formula("100|&")); + // println!("{}", eval_formula("101|&")); + // println!("{}", eval_formula("110|&")); + // println!("{}", eval_formula("111|&")); } diff --git a/src/truth_table.rs b/src/truth_table.rs index 3ec29f5..284761b 100644 --- a/src/truth_table.rs +++ b/src/truth_table.rs @@ -71,7 +71,7 @@ fn recursive_fn(formula: &str, mut vec: Vec, format: String) { } } -fn print_truth_table(formula: &str) { +pub fn print_truth_table(formula: &str) { let set: HashSet = get_hashset(formula); let mut vec: Vec = set.iter().cloned().collect(); vec.sort(); @@ -87,6 +87,7 @@ fn print_truth_table(formula: &str) { separator = format!("{separator}---|"); println!("{format}"); println!("{separator}"); - recursive_fn(formula, vec, String::from("|")); + //dbg!(vec.clone()); + recursive_fn(formula, vec.into_iter().rev().collect(), String::from("|")); // call eval formula a lot } \ No newline at end of file diff --git a/src/truth_table/tests.rs b/src/truth_table/tests.rs index e092e43..79fcc21 100644 --- a/src/truth_table/tests.rs +++ b/src/truth_table/tests.rs @@ -23,6 +23,6 @@ mod tests { #[test] fn big() { - print_truth_table("AB&CD&&EF&GH&&&IJ&KL&&MN&OP&&&QR&ST&&UV&WX&&&YZ&&&") + //print_truth_table("AB&CD&&EF&GH&&&IJ&KL&&MN&OP&&&QR&ST&&UV&WX&&&YZ&&&") } } From a13dfeaeebba0a2681634038a75d42b5de465e2a Mon Sep 17 00:00:00 2001 From: gbrochar Date: Mon, 22 Jan 2024 18:34:40 +0100 Subject: [PATCH 2/5] refacto: use generic types --- src/ast.rs | 89 +++++++++++++++++++++++++------ src/ast/tests.rs | 29 +++++++--- src/boolean_evaluation.rs | 22 +------- src/main.rs | 11 +--- src/negation_normal_form.rs | 30 +++++++++++ src/negation_normal_form/tests.rs | 23 ++++++++ 6 files changed, 150 insertions(+), 54 deletions(-) create mode 100644 src/negation_normal_form.rs create mode 100644 src/negation_normal_form/tests.rs diff --git a/src/ast.rs b/src/ast.rs index 92a5863..3dd53a6 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -25,6 +25,79 @@ pub enum Node { }, } +impl Node { + pub fn parse_formula(formula: &str) -> Node { + 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), + _ => panic!("Error: {} is not a valid character", c) + } + } + stack.pop().unwrap() + } + + pub fn ast_to_formula(ast: Node) -> String { + let mut str = String::from(""); + match ast { + Node::Unary { operator, operand } => { + str.push_str(Self::ast_to_formula(*operand).as_str()); + str.push(token_to_char(operator)); + }, + Node::Binary { operator, lhs, rhs } => { + 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)); + }, + Node::Leaf(b) => str.push(bool_to_char(b)), + }; + str + } +} + +impl Node { + pub fn parse_formula(formula: &str) -> Node { + 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), + _ => panic!("Error: {} is not a valid character", c) + } + } + stack.pop().unwrap() + } + + pub fn ast_to_formula(ast: Node) -> String { + let mut str = String::from(""); + match ast { + Node::Unary { operator, operand } => { + str.push_str(Self::ast_to_formula(*operand).as_str()); + str.push(token_to_char(operator)); + }, + Node::Binary { operator, lhs, rhs } => { + 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)); + }, + Node::Leaf(c) => str.push(c), + }; + str + } +} + pub fn add_unary_node(stack: &mut Vec>, token: Token) { let operand = Box::new(stack.pop().unwrap()); stack.push(Node::Unary { @@ -61,19 +134,3 @@ fn token_to_char(token: Token) -> char { } } -fn ast_to_formula(ast: Node) -> String { - let mut str = String::from(""); - match ast { - Node::Unary { operator, operand } => { - str.push_str(ast_to_formula(*operand).as_str()); - str.push(token_to_char(operator)); - }, - Node::Binary { operator, lhs, rhs } => { - str.push_str(ast_to_formula(*rhs).as_str()); - str.push_str(ast_to_formula(*lhs).as_str()); - str.push(token_to_char(operator)); - }, - Node::Leaf(b) => str.push(bool_to_char(b)), - }; - str -} \ No newline at end of file diff --git a/src/ast/tests.rs b/src/ast/tests.rs index 25c9509..d878aaf 100644 --- a/src/ast/tests.rs +++ b/src/ast/tests.rs @@ -1,7 +1,6 @@ #[cfg(test)] mod tests { - use crate::ast::{ add_binary_node, ast_to_formula, Node, Token }; - use crate::boolean_evaluation::parse_formula; + use crate::ast::{ add_binary_node, Node, Token }; #[test] fn add_nodes() { @@ -16,16 +15,30 @@ mod tests { } #[test] - fn reverse_ast() { + fn ast_to_formula_bool() { let formula = "01&"; - assert_eq!(ast_to_formula(parse_formula(formula)), formula); + assert_eq!(Node::::ast_to_formula(Node::::parse_formula(formula)), formula); let formula = "01&00|&"; - assert_eq!(ast_to_formula(parse_formula(formula)), formula); + assert_eq!(Node::::ast_to_formula(Node::::parse_formula(formula)), formula); let formula = "01&00|&11^&"; - assert_eq!(ast_to_formula(parse_formula(formula)), formula); + assert_eq!(Node::::ast_to_formula(Node::::parse_formula(formula)), formula); let formula = "01&00|&11=^"; - assert_eq!(ast_to_formula(parse_formula(formula)), formula); + assert_eq!(Node::::ast_to_formula(Node::::parse_formula(formula)), formula); let formula = "01&00|&0!="; - assert_eq!(ast_to_formula(parse_formula(formula)), formula); + assert_eq!(Node::::ast_to_formula(Node::::parse_formula(formula)), formula); + } + + #[test] + fn ast_to_formula_char() { + let formula = "AB&"; + assert_eq!(Node::::ast_to_formula(Node::::parse_formula(formula)), formula); + let formula = "AB&CD|&"; + assert_eq!(Node::::ast_to_formula(Node::::parse_formula(formula)), formula); + let formula = "AB&AC|&DE^&"; + assert_eq!(Node::::ast_to_formula(Node::::parse_formula(formula)), formula); + let formula = "AB&CD|&EF=^"; + assert_eq!(Node::::ast_to_formula(Node::::parse_formula(formula)), formula); + let formula = "AB&CD|&E!="; + assert_eq!(Node::::ast_to_formula(Node::::parse_formula(formula)), formula); } } \ No newline at end of file diff --git a/src/boolean_evaluation.rs b/src/boolean_evaluation.rs index 4a34b80..b51b3f5 100644 --- a/src/boolean_evaluation.rs +++ b/src/boolean_evaluation.rs @@ -1,24 +1,6 @@ mod tests; -use crate::ast::{ Token, Node, add_unary_node, add_binary_node }; - -pub fn parse_formula(formula: &str) -> Node { - 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), - _ => panic!("Error: {} is not a valid character", c) - } - } - stack.pop().unwrap() -} +use crate::ast::{ Token, Node }; fn compute(operator: Token, lhs: bool, rhs: bool) -> bool { match operator { @@ -40,6 +22,6 @@ fn evaluate(tree: Node) -> bool { } pub fn eval_formula(formula: &str) -> bool { - let tree = parse_formula(formula); + let tree = Node::::parse_formula(formula); evaluate(tree) } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 5dc93d7..e793fc2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,10 +4,10 @@ mod gray_code; mod boolean_evaluation; mod truth_table; mod ast; +mod negation_normal_form; use gray_code::gray_code; use truth_table::print_truth_table; -use boolean_evaluation::eval_formula; fn main() { println!("Hello, world!"); @@ -21,13 +21,4 @@ fn main() { println!("{}", gray_code(7)); println!("{}", gray_code(3)); print_truth_table("ABC|&"); - //print_truth_table("ABCF&&&"); - // println!("{}", eval_formula("000|&")); - // println!("{}", eval_formula("001|&")); - // println!("{}", eval_formula("010|&")); - // println!("{}", eval_formula("011|&")); - // println!("{}", eval_formula("100|&")); - // println!("{}", eval_formula("101|&")); - // println!("{}", eval_formula("110|&")); - // println!("{}", eval_formula("111|&")); } diff --git a/src/negation_normal_form.rs b/src/negation_normal_form.rs new file mode 100644 index 0000000..88439d8 --- /dev/null +++ b/src/negation_normal_form.rs @@ -0,0 +1,30 @@ +mod tests; + +use crate::ast::Node; + +// fn cancel_double_negation(ast: Node) { +// let mut new_ast = ast.clone(); + +// fn recursion(ast: &mut Node, 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 { + let ast = Node::::parse_formula(formula); + + Node::::ast_to_formula(ast) +} \ No newline at end of file diff --git a/src/negation_normal_form/tests.rs b/src/negation_normal_form/tests.rs new file mode 100644 index 0000000..ff08058 --- /dev/null +++ b/src/negation_normal_form/tests.rs @@ -0,0 +1,23 @@ +#[cfg(test)] +mod tests { + use crate::negation_normal_form::negation_normal_form; + + #[test] + fn double_neg() { + assert_eq!(negation_normal_form("A!!"), "A"); + assert_eq!(negation_normal_form("A!!!!"), "A"); + assert_eq!(negation_normal_form("A!!!"), "A!"); + assert_eq!(negation_normal_form("A!!!!!!!!!!!!!!!!"), "A"); + assert_eq!(negation_normal_form("A!!!!!!!!!!!!!!!"), "A!"); + } + + #[test] + fn neg_and() { + assert_eq!(negation_normal_form("AB&!"), "A!B!|"); + } + + #[test] + fn neg_or() { + assert_eq!(negation_normal_form("AB|!"), "A!B!&"); + } +} \ No newline at end of file From b5e48c41c4ba1ea314a09e8c5f5eda8e8de366cf Mon Sep 17 00:00:00 2001 From: gbrochar Date: Tue, 23 Jan 2024 21:20:03 +0100 Subject: [PATCH 3/5] feat(ex05): cancel double negation --- src/ast.rs | 52 ++++++++++++++++++++++--------- src/ast/tests.rs | 20 ++++++------ src/negation_normal_form.rs | 51 ++++++++++++++++++++++++++++-- src/negation_normal_form/tests.rs | 17 +++++++--- 4 files changed, 108 insertions(+), 32 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 3dd53a6..711ad0e 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1,7 +1,7 @@ mod tests; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub enum Token { Negation, Conjunction, @@ -25,6 +25,28 @@ pub enum Node { }, } +impl Node +where T: Clone { + pub fn simplify(&mut self) { + match self { + Node::Unary { operator, operand } if *operator == Token::Negation => { + if let Node::Unary { operator: inner_op, operand: inner_operand } = &**operand { + if *inner_op == Token::Negation { + *self = *inner_operand.clone(); // Replace unary node with its operand + self.simplify(); // Continue simplification recursively + } + } + } + Node::Binary { lhs, rhs, .. } => { + lhs.simplify(); + rhs.simplify(); + } + _ => {} + } + } +} + + impl Node { pub fn parse_formula(formula: &str) -> Node { let mut stack = vec![]; @@ -44,19 +66,19 @@ impl Node { stack.pop().unwrap() } - pub fn ast_to_formula(ast: Node) -> String { + pub fn ast_to_formula(ast: &Node) -> String { let mut str = String::from(""); match ast { Node::Unary { operator, operand } => { - str.push_str(Self::ast_to_formula(*operand).as_str()); - str.push(token_to_char(operator)); + str.push_str(Self::ast_to_formula(operand).as_str()); + str.push(token_to_char(*operator)); }, Node::Binary { operator, lhs, rhs } => { - 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)); + 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)); }, - Node::Leaf(b) => str.push(bool_to_char(b)), + Node::Leaf(b) => str.push(bool_to_char(*b)), }; str } @@ -80,19 +102,19 @@ impl Node { stack.pop().unwrap() } - pub fn ast_to_formula(ast: Node) -> String { + pub fn ast_to_formula(ast: &Node) -> String { let mut str = String::from(""); match ast { Node::Unary { operator, operand } => { - str.push_str(Self::ast_to_formula(*operand).as_str()); - str.push(token_to_char(operator)); + str.push_str(Self::ast_to_formula(operand).as_str()); + str.push(token_to_char(*operator)); }, Node::Binary { operator, lhs, rhs } => { - 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)); + 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)); }, - Node::Leaf(c) => str.push(c), + Node::Leaf(c) => str.push(*c), }; str } diff --git a/src/ast/tests.rs b/src/ast/tests.rs index d878aaf..28f9c73 100644 --- a/src/ast/tests.rs +++ b/src/ast/tests.rs @@ -17,28 +17,28 @@ mod tests { #[test] fn ast_to_formula_bool() { let formula = "01&"; - assert_eq!(Node::::ast_to_formula(Node::::parse_formula(formula)), formula); + assert_eq!(Node::::ast_to_formula(&Node::::parse_formula(formula)), formula); let formula = "01&00|&"; - assert_eq!(Node::::ast_to_formula(Node::::parse_formula(formula)), formula); + assert_eq!(Node::::ast_to_formula(&Node::::parse_formula(formula)), formula); let formula = "01&00|&11^&"; - assert_eq!(Node::::ast_to_formula(Node::::parse_formula(formula)), formula); + assert_eq!(Node::::ast_to_formula(&Node::::parse_formula(formula)), formula); let formula = "01&00|&11=^"; - assert_eq!(Node::::ast_to_formula(Node::::parse_formula(formula)), formula); + assert_eq!(Node::::ast_to_formula(&Node::::parse_formula(formula)), formula); let formula = "01&00|&0!="; - assert_eq!(Node::::ast_to_formula(Node::::parse_formula(formula)), formula); + assert_eq!(Node::::ast_to_formula(&Node::::parse_formula(formula)), formula); } #[test] fn ast_to_formula_char() { let formula = "AB&"; - assert_eq!(Node::::ast_to_formula(Node::::parse_formula(formula)), formula); + assert_eq!(Node::::ast_to_formula(&Node::::parse_formula(formula)), formula); let formula = "AB&CD|&"; - assert_eq!(Node::::ast_to_formula(Node::::parse_formula(formula)), formula); + assert_eq!(Node::::ast_to_formula(&Node::::parse_formula(formula)), formula); let formula = "AB&AC|&DE^&"; - assert_eq!(Node::::ast_to_formula(Node::::parse_formula(formula)), formula); + assert_eq!(Node::::ast_to_formula(&Node::::parse_formula(formula)), formula); let formula = "AB&CD|&EF=^"; - assert_eq!(Node::::ast_to_formula(Node::::parse_formula(formula)), formula); + assert_eq!(Node::::ast_to_formula(&Node::::parse_formula(formula)), formula); let formula = "AB&CD|&E!="; - assert_eq!(Node::::ast_to_formula(Node::::parse_formula(formula)), formula); + assert_eq!(Node::::ast_to_formula(&Node::::parse_formula(formula)), formula); } } \ No newline at end of file diff --git a/src/negation_normal_form.rs b/src/negation_normal_form.rs index 88439d8..2da9cb1 100644 --- a/src/negation_normal_form.rs +++ b/src/negation_normal_form.rs @@ -2,6 +2,25 @@ mod tests; use crate::ast::Node; +// fn cancel_double_negation(ast: &mut Node, parent: Option<&mut Node>) -> Node { +// match ast { +// Node::Unary { operator: _, operand } => { +// if let Some(node) = parent { + +// } else { +// *ast = cancel_double_negation(&mut *operand, Some(ast)); +// } +// }, +// Node::Binary { operator: _, lhs, rhs } => { +// *ast = cancel_double_negation(&mut *lhs, None); +// *ast = cancel_double_negation(&mut *rhs, None); +// }, +// Node::Leaf(c) => (), +// } + +// ast +// } + // fn cancel_double_negation(ast: Node) { // let mut new_ast = ast.clone(); @@ -24,7 +43,35 @@ use crate::ast::Node; // } fn negation_normal_form(formula: &str) -> String { - let ast = Node::::parse_formula(formula); + let mut ast = Node::::parse_formula(formula); + // let mut tmp = Node::::parse_formula((formula.to_string() + "!").as_str()); + // let mut clone = ast.clone(); - Node::::ast_to_formula(ast) + // while Node::::ast_to_formula(&clone) != Node::::ast_to_formula(&tmp) { + // let copy = ast.clone(); + // clone = ast.clone(); + + // dbg!(&ast); + + // tmp = match copy { + // Node::Unary { operator: _, operand } => { + // match *operand { + // Node::Unary { operator: _, operand } => { + // println!("salut"); + // dbg!(&*operand); + // *operand + // } + // Node::Binary { operator: _, lhs: _, rhs: _ } => ast, + // Node::Leaf(_) => ast, + + // } + // } + // Node::Binary { operator: _, lhs: _, rhs: _ } => ast, + // Node::Leaf(_) => ast, + // }; + + // ast = tmp.clone(); + // } + ast.simplify(); + Node::::ast_to_formula(&ast) } \ No newline at end of file diff --git a/src/negation_normal_form/tests.rs b/src/negation_normal_form/tests.rs index ff08058..8318195 100644 --- a/src/negation_normal_form/tests.rs +++ b/src/negation_normal_form/tests.rs @@ -3,12 +3,19 @@ mod tests { use crate::negation_normal_form::negation_normal_form; #[test] - fn double_neg() { + fn double_neg_simple() { assert_eq!(negation_normal_form("A!!"), "A"); - assert_eq!(negation_normal_form("A!!!!"), "A"); - assert_eq!(negation_normal_form("A!!!"), "A!"); - assert_eq!(negation_normal_form("A!!!!!!!!!!!!!!!!"), "A"); - 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] + fn double_neg() { + assert_eq!(negation_normal_form("A!!B&"), "AB&"); + assert_eq!(negation_normal_form("A!!B!!&"), "AB&"); + assert_eq!(negation_normal_form("A!!B!&"), "AB!&"); } #[test] From 4abcd4c8329a822e5bc9039650277e4ce0dc35e9 Mon Sep 17 00:00:00 2001 From: gbrochar Date: Tue, 23 Jan 2024 21:24:09 +0100 Subject: [PATCH 4/5] test(ex05): add more tests for double negation --- src/negation_normal_form/tests.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/negation_normal_form/tests.rs b/src/negation_normal_form/tests.rs index 8318195..3eafadc 100644 --- a/src/negation_normal_form/tests.rs +++ b/src/negation_normal_form/tests.rs @@ -13,9 +13,12 @@ mod tests { #[test] fn double_neg() { - assert_eq!(negation_normal_form("A!!B&"), "AB&"); - assert_eq!(negation_normal_form("A!!B!!&"), "AB&"); - assert_eq!(negation_normal_form("A!!B!&"), "AB!&"); + assert_eq!(negation_normal_form("A!!A&"), "AA&"); + assert_eq!(negation_normal_form("B!!B!!&"), "BB&"); + assert_eq!(negation_normal_form("C!!C!&"), "CC!&"); + assert_eq!(negation_normal_form("D!!D&!!!!"), "DD&"); + assert_eq!(negation_normal_form("E!!E!!!!&!!"), "EE&"); + assert_eq!(negation_normal_form("F!!F!&!!!!!!!!"), "FF!&"); } #[test] From dea2e2d6a3edd64152f4669a422d2722762779e8 Mon Sep 17 00:00:00 2001 From: gbrochar Date: Wed, 24 Jan 2024 13:27:46 +0100 Subject: [PATCH 5/5] feat(ex05): done + rustfmt oops --- src/adder.rs | 1 - src/ast.rs | 245 ++++++++++++++++++++++++++---- src/ast/tests.rs | 56 +++++-- src/boolean_evaluation.rs | 6 +- src/boolean_evaluation/tests.rs | 5 +- src/gray_code.rs | 1 - src/gray_code/tests.rs | 2 +- src/main.rs | 8 +- src/multiplier.rs | 2 +- src/negation_normal_form.rs | 70 +-------- src/negation_normal_form/tests.rs | 53 +++++-- src/truth_table.rs | 26 +++- 12 files changed, 335 insertions(+), 140 deletions(-) diff --git a/src/adder.rs b/src/adder.rs index 2dfc4c6..09eadf3 100644 --- a/src/adder.rs +++ b/src/adder.rs @@ -12,4 +12,3 @@ pub fn adder(a: u32, b: u32) -> u32 { } result } - diff --git a/src/ast.rs b/src/ast.rs index 711ad0e..bad9321 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1,6 +1,5 @@ mod tests; - #[derive(Debug, Clone, Copy, PartialEq)] pub enum Token { Negation, @@ -8,15 +7,18 @@ pub enum Token { Disjunction, ExclusiveDisjunction, MaterialCondition, - LogicalEquivalence + LogicalEquivalence, } #[derive(Debug, Clone, PartialEq)] -pub enum Node { +pub enum Node +where + T: Clone + std::fmt::Debug, +{ Leaf(T), Unary { operator: Token, - operand: Box> + operand: Box>, }, Binary { operator: Token, @@ -26,27 +28,207 @@ pub enum Node { } impl Node -where T: Clone { +where + T: Clone + std::fmt::Debug, +{ + fn negation_conjunction_to_nnf(lhs: &Box>, rhs: &Box>) -> Node { + 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>, rhs: &Box>) -> Node { + 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>, rhs: &Box>) -> Node { + 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>, rhs: &Box>) -> Node { + 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>, rhs: &Box>) -> Node { + 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>, rhs: &Box>) -> Node { + 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>, rhs: &Box>) -> Node { + 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>, rhs: &Box>) -> Node { + 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 => { - if let Node::Unary { operator: inner_op, operand: inner_operand } = &**operand { - if *inner_op == Token::Negation { - *self = *inner_operand.clone(); // Replace unary node with its operand - self.simplify(); // Continue simplification recursively + 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(); } } - Node::Binary { lhs, rhs, .. } => { - lhs.simplify(); - rhs.simplify(); - } - _ => {} + _ => (), } } } - impl Node { pub fn parse_formula(formula: &str) -> Node { let mut stack = vec![]; @@ -60,7 +242,7 @@ impl Node { '^' => add_binary_node(&mut stack, Token::ExclusiveDisjunction), '>' => add_binary_node(&mut stack, Token::MaterialCondition), '=' => 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() @@ -72,17 +254,17 @@ impl Node { Node::Unary { operator, operand } => { str.push_str(Self::ast_to_formula(operand).as_str()); str.push(token_to_char(*operator)); - }, + } Node::Binary { operator, lhs, rhs } => { 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)); - }, + } Node::Leaf(b) => str.push(bool_to_char(*b)), }; str } -} +} impl Node { pub fn parse_formula(formula: &str) -> Node { @@ -96,7 +278,7 @@ impl Node { '^' => add_binary_node(&mut stack, Token::ExclusiveDisjunction), '>' => add_binary_node(&mut stack, Token::MaterialCondition), '=' => 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() @@ -108,19 +290,22 @@ impl Node { Node::Unary { operator, operand } => { str.push_str(Self::ast_to_formula(operand).as_str()); str.push(token_to_char(*operator)); - }, + } Node::Binary { operator, lhs, rhs } => { 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)); - }, + } Node::Leaf(c) => str.push(*c), }; str } } -pub fn add_unary_node(stack: &mut Vec>, token: Token) { +pub fn add_unary_node(stack: &mut Vec>, token: Token) +where + T: Clone + std::fmt::Debug, +{ let operand = Box::new(stack.pop().unwrap()); stack.push(Node::Unary { operator: token, @@ -128,31 +313,33 @@ pub fn add_unary_node(stack: &mut Vec>, token: Token) { }); } -pub fn add_binary_node(stack: &mut Vec>, token: Token) { +pub fn add_binary_node(stack: &mut Vec>, token: Token) +where + T: Clone + std::fmt::Debug, +{ let rhs = Box::new(stack.pop().unwrap()); let lhs = Box::new(stack.pop().unwrap()); stack.push(Node::Binary { operator: token, lhs, - rhs + rhs, }); } fn bool_to_char(b: bool) -> char { match b { false => '0', - true => '1' + true => '1', } } fn token_to_char(token: Token) -> char { match token { Token::Negation => '!', - Token::Conjunction =>'&', + Token::Conjunction => '&', Token::Disjunction => '|', Token::ExclusiveDisjunction => '^', Token::MaterialCondition => '>', Token::LogicalEquivalence => '=', } } - diff --git a/src/ast/tests.rs b/src/ast/tests.rs index 28f9c73..23df1a9 100644 --- a/src/ast/tests.rs +++ b/src/ast/tests.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod tests { - use crate::ast::{ add_binary_node, Node, Token }; + use crate::ast::{add_binary_node, Node, Token}; #[test] fn add_nodes() { @@ -8,7 +8,7 @@ mod tests { let rhs = vec![Node::Binary { operator: Token::Conjunction, 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); assert_eq!(stack, rhs); @@ -17,28 +17,58 @@ mod tests { #[test] fn ast_to_formula_bool() { let formula = "01&"; - assert_eq!(Node::::ast_to_formula(&Node::::parse_formula(formula)), formula); + assert_eq!( + Node::::ast_to_formula(&Node::::parse_formula(formula)), + formula + ); let formula = "01&00|&"; - assert_eq!(Node::::ast_to_formula(&Node::::parse_formula(formula)), formula); + assert_eq!( + Node::::ast_to_formula(&Node::::parse_formula(formula)), + formula + ); let formula = "01&00|&11^&"; - assert_eq!(Node::::ast_to_formula(&Node::::parse_formula(formula)), formula); + assert_eq!( + Node::::ast_to_formula(&Node::::parse_formula(formula)), + formula + ); let formula = "01&00|&11=^"; - assert_eq!(Node::::ast_to_formula(&Node::::parse_formula(formula)), formula); + assert_eq!( + Node::::ast_to_formula(&Node::::parse_formula(formula)), + formula + ); let formula = "01&00|&0!="; - assert_eq!(Node::::ast_to_formula(&Node::::parse_formula(formula)), formula); + assert_eq!( + Node::::ast_to_formula(&Node::::parse_formula(formula)), + formula + ); } #[test] fn ast_to_formula_char() { let formula = "AB&"; - assert_eq!(Node::::ast_to_formula(&Node::::parse_formula(formula)), formula); + assert_eq!( + Node::::ast_to_formula(&Node::::parse_formula(formula)), + formula + ); let formula = "AB&CD|&"; - assert_eq!(Node::::ast_to_formula(&Node::::parse_formula(formula)), formula); + assert_eq!( + Node::::ast_to_formula(&Node::::parse_formula(formula)), + formula + ); let formula = "AB&AC|&DE^&"; - assert_eq!(Node::::ast_to_formula(&Node::::parse_formula(formula)), formula); + assert_eq!( + Node::::ast_to_formula(&Node::::parse_formula(formula)), + formula + ); let formula = "AB&CD|&EF=^"; - assert_eq!(Node::::ast_to_formula(&Node::::parse_formula(formula)), formula); + assert_eq!( + Node::::ast_to_formula(&Node::::parse_formula(formula)), + formula + ); let formula = "AB&CD|&E!="; - assert_eq!(Node::::ast_to_formula(&Node::::parse_formula(formula)), formula); + assert_eq!( + Node::::ast_to_formula(&Node::::parse_formula(formula)), + formula + ); } -} \ No newline at end of file +} diff --git a/src/boolean_evaluation.rs b/src/boolean_evaluation.rs index b51b3f5..a61b599 100644 --- a/src/boolean_evaluation.rs +++ b/src/boolean_evaluation.rs @@ -1,6 +1,6 @@ mod tests; -use crate::ast::{ Token, Node }; +use crate::ast::{Node, Token}; fn compute(operator: Token, lhs: bool, rhs: bool) -> bool { match operator { @@ -9,7 +9,7 @@ fn compute(operator: Token, lhs: bool, rhs: bool) -> bool { Token::Disjunction => lhs | rhs, Token::ExclusiveDisjunction => lhs ^ rhs, Token::MaterialCondition => !(lhs && !rhs), - Token::LogicalEquivalence => lhs == rhs + Token::LogicalEquivalence => lhs == rhs, } } @@ -24,4 +24,4 @@ fn evaluate(tree: Node) -> bool { pub fn eval_formula(formula: &str) -> bool { let tree = Node::::parse_formula(formula); evaluate(tree) -} \ No newline at end of file +} diff --git a/src/boolean_evaluation/tests.rs b/src/boolean_evaluation/tests.rs index 2430f40..1bf95a3 100644 --- a/src/boolean_evaluation/tests.rs +++ b/src/boolean_evaluation/tests.rs @@ -22,7 +22,10 @@ mod tests { assert_eq!(eval_formula("1!!"), true); assert_eq!(eval_formula("0!!"), false); assert_eq!(eval_formula("0!!!"), true); - assert_eq!(eval_formula("1!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"), true); + assert_eq!( + eval_formula("1!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"), + true + ); } #[test] diff --git a/src/gray_code.rs b/src/gray_code.rs index 108ea83..b8126ad 100644 --- a/src/gray_code.rs +++ b/src/gray_code.rs @@ -10,4 +10,3 @@ pub fn gray_code(n: u32) -> u32 { } result } - diff --git a/src/gray_code/tests.rs b/src/gray_code/tests.rs index 7903e01..6b4d321 100644 --- a/src/gray_code/tests.rs +++ b/src/gray_code/tests.rs @@ -20,6 +20,6 @@ mod tests { fn msb_u32() { assert_eq!(gray_code(3_000_000_000), 3_954_733_312); assert_eq!(gray_code(2_147_483_648), 3_221_225_472); - assert_eq!(gray_code(4_294_967_295), 2_147_483_648); + assert_eq!(gray_code(4_294_967_295), 2_147_483_648); } } diff --git a/src/main.rs b/src/main.rs index e793fc2..588a634 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,10 @@ mod adder; -mod multiplier; -mod gray_code; -mod boolean_evaluation; -mod truth_table; mod ast; +mod boolean_evaluation; +mod gray_code; +mod multiplier; mod negation_normal_form; +mod truth_table; use gray_code::gray_code; use truth_table::print_truth_table; diff --git a/src/multiplier.rs b/src/multiplier.rs index 2e208af..2201b18 100644 --- a/src/multiplier.rs +++ b/src/multiplier.rs @@ -4,7 +4,7 @@ use crate::adder::adder; pub fn multiplier(a: u32, b: u32) -> u32 { let mut result = 0; - + for i in 0..32 { if a >> i & 1 == 1 { result = adder(result, b << i); diff --git a/src/negation_normal_form.rs b/src/negation_normal_form.rs index 2da9cb1..2a63e8d 100644 --- a/src/negation_normal_form.rs +++ b/src/negation_normal_form.rs @@ -2,76 +2,8 @@ mod tests; use crate::ast::Node; -// fn cancel_double_negation(ast: &mut Node, parent: Option<&mut Node>) -> Node { -// match ast { -// Node::Unary { operator: _, operand } => { -// if let Some(node) = parent { - -// } else { -// *ast = cancel_double_negation(&mut *operand, Some(ast)); -// } -// }, -// Node::Binary { operator: _, lhs, rhs } => { -// *ast = cancel_double_negation(&mut *lhs, None); -// *ast = cancel_double_negation(&mut *rhs, None); -// }, -// Node::Leaf(c) => (), -// } - -// ast -// } - -// fn cancel_double_negation(ast: Node) { -// let mut new_ast = ast.clone(); - -// fn recursion(ast: &mut Node, 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 { let mut ast = Node::::parse_formula(formula); - // let mut tmp = Node::::parse_formula((formula.to_string() + "!").as_str()); - // let mut clone = ast.clone(); - - // while Node::::ast_to_formula(&clone) != Node::::ast_to_formula(&tmp) { - // let copy = ast.clone(); - // clone = ast.clone(); - - // dbg!(&ast); - - // tmp = match copy { - // Node::Unary { operator: _, operand } => { - // match *operand { - // Node::Unary { operator: _, operand } => { - // println!("salut"); - // dbg!(&*operand); - // *operand - // } - // Node::Binary { operator: _, lhs: _, rhs: _ } => ast, - // Node::Leaf(_) => ast, - - // } - // } - // Node::Binary { operator: _, lhs: _, rhs: _ } => ast, - // Node::Leaf(_) => ast, - // }; - - // ast = tmp.clone(); - // } ast.simplify(); Node::::ast_to_formula(&ast) -} \ No newline at end of file +} diff --git a/src/negation_normal_form/tests.rs b/src/negation_normal_form/tests.rs index 3eafadc..11a1f9c 100644 --- a/src/negation_normal_form/tests.rs +++ b/src/negation_normal_form/tests.rs @@ -13,21 +13,56 @@ mod tests { #[test] fn double_neg() { - assert_eq!(negation_normal_form("A!!A&"), "AA&"); - assert_eq!(negation_normal_form("B!!B!!&"), "BB&"); - assert_eq!(negation_normal_form("C!!C!&"), "CC!&"); - assert_eq!(negation_normal_form("D!!D&!!!!"), "DD&"); - assert_eq!(negation_normal_form("E!!E!!!!&!!"), "EE&"); - assert_eq!(negation_normal_form("F!!F!&!!!!!!!!"), "FF!&"); + assert_eq!(negation_normal_form("A!!Z&"), "AZ&"); + assert_eq!(negation_normal_form("B!!Z!!&"), "BZ&"); + assert_eq!(negation_normal_form("C!!Z!&"), "CZ!&"); + assert_eq!(negation_normal_form("D!!Z&!!!!"), "DZ&"); + assert_eq!(negation_normal_form("E!!Z!!!!&!!"), "EZ&"); + assert_eq!(negation_normal_form("F!!Z!&!!!!!!!!"), "FZ!&"); } #[test] fn neg_and() { - assert_eq!(negation_normal_form("AB&!"), "A!B!|"); + 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 neg_or() { - assert_eq!(negation_normal_form("AB|!"), "A!B!&"); + 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|&"); } -} \ No newline at end of file + + #[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|C&!"), "A!B!&C!|"); + } + + #[test] + fn complex_tests() { + assert_eq!("A", "A"); + } +} diff --git a/src/truth_table.rs b/src/truth_table.rs index 284761b..c3d2398 100644 --- a/src/truth_table.rs +++ b/src/truth_table.rs @@ -1,7 +1,7 @@ mod tests; +use crate::ast::{add_binary_node, add_unary_node, Node, Token}; use std::collections::HashSet; -use crate::ast::{ Token, Node, add_unary_node, add_binary_node }; fn parse_formula(formula: &str) -> Node { let mut stack = vec![]; @@ -15,7 +15,7 @@ fn parse_formula(formula: &str) -> Node { '^' => add_binary_node(&mut stack, Token::ExclusiveDisjunction), '>' => add_binary_node(&mut stack, Token::MaterialCondition), '=' => 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() @@ -28,7 +28,7 @@ fn compute(operator: Token, lhs: bool, rhs: bool) -> bool { Token::Disjunction => lhs | rhs, Token::ExclusiveDisjunction => lhs ^ rhs, Token::MaterialCondition => !(lhs && !rhs), - Token::LogicalEquivalence => lhs == rhs + Token::LogicalEquivalence => lhs == rhs, } } @@ -45,7 +45,9 @@ fn get_hashset(formula: &str) -> HashSet { for c in formula.chars() { match c { - 'A'..='Z' => { hashset.insert(c); }, + 'A'..='Z' => { + hashset.insert(c); + } '!' | '&' | '|' | '^' | '>' | '=' => (), _ => panic!("Error: {} is not a valid character", c), } @@ -61,8 +63,16 @@ fn eval_formula(formula: &str) -> bool { fn recursive_fn(formula: &str, mut vec: Vec, format: String) { let char = vec.pop(); if let Some(c) = char { - recursive_fn(formula.replace(c, "0").as_str(), vec.clone(), format!("{format} 0 |")); - recursive_fn(formula.replace(c, "1").as_str(), vec.clone(), format!("{format} 1 |")); + recursive_fn( + formula.replace(c, "0").as_str(), + vec.clone(), + format!("{format} 0 |"), + ); + recursive_fn( + formula.replace(c, "1").as_str(), + vec.clone(), + format!("{format} 1 |"), + ); } else { match eval_formula(formula) { false => println!("{format} 0 |"), @@ -89,5 +99,5 @@ pub fn print_truth_table(formula: &str) { println!("{separator}"); //dbg!(vec.clone()); recursive_fn(formula, vec.into_iter().rev().collect(), String::from("|")); - // call eval formula a lot -} \ No newline at end of file + // call eval formula a lot +}