From 78368772ebf6d2fac366e9d4676f1ac4280bf6dd Mon Sep 17 00:00:00 2001 From: Martin Berg Alstad Date: Mon, 17 Jun 2024 11:41:28 +0200 Subject: [PATCH] Fixed parenthesis when not needed. Removed some unused functions --- src/expressions/expression.rs | 100 +++++++++++++++++++++++---------- src/expressions/iterator.rs | 50 ----------------- src/expressions/mod.rs | 3 +- src/expressions/simplify.rs | 8 +-- src/expressions/truth_table.rs | 10 ++-- 5 files changed, 81 insertions(+), 90 deletions(-) delete mode 100644 src/expressions/iterator.rs diff --git a/src/expressions/expression.rs b/src/expressions/expression.rs index e596d64..1c9209c 100644 --- a/src/expressions/expression.rs +++ b/src/expressions/expression.rs @@ -4,7 +4,6 @@ use std::rc::Rc; use serde::{Deserialize, Serialize}; -use crate::expressions::iterator::ExpressionIterator; use crate::expressions::operator::BinaryOperator; use crate::parsing::expression_parser::parse_expression; @@ -40,19 +39,6 @@ impl Expression { Expression::Atomic(value) => HashSet::from([value.clone()]) } } - - pub fn iter(&self) -> ExpressionIterator { - ExpressionIterator::new(self.clone()) - } -} - -impl IntoIterator for Expression { - type Item = Rc; - type IntoIter = ExpressionIterator; - - fn into_iter(self) -> Self::IntoIter { - ExpressionIterator::new(self) - } } impl OppositeEq for Expression { @@ -83,20 +69,27 @@ impl TryFrom for Expression { impl Display for Expression { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Expression::Not(expr) if expr.is_atomic() => write!(f, "¬{expr}"), - Expression::Not(expr) => write!(f, "¬({expr})"), - Expression::Binary { left, operator: BinaryOperator::And, right } => { - write!(f, "{left} ⋀ {right}") + return write!(f, "{}", fmt_helper(self, None)); + + fn fmt_helper(expression: &Expression, parent: Option<&Expression>) -> String { + match expression { + Expression::Not(expr) if expr.is_atomic() => format!("¬{}", fmt_helper(expr, Some(expression))), + Expression::Not(expr) => format!("¬({})", fmt_helper(expr, Some(expression))), + Expression::Binary { left, operator: BinaryOperator::And, right } => { + format!("{} ⋀ {}", fmt_helper(left, Some(expression)), fmt_helper(right, Some(expression))) + } + Expression::Binary { left, operator: BinaryOperator::Or, right } => { + if parent.is_none() || matches!(parent, Some(Expression::Binary { operator: BinaryOperator::Or, .. })) { + format!("{} ⋁ {}", fmt_helper(left, Some(expression)), fmt_helper(right, Some(expression))) + } else { + format!("({} ⋁ {})", fmt_helper(left, Some(expression)), fmt_helper(right, Some(expression))) + } + } + Expression::Binary { left, operator: BinaryOperator::Implication, right } => { + format!("{} ➔ {}", fmt_helper(left, Some(expression)), fmt_helper(right, Some(expression))) + } + Expression::Atomic(value) => value.clone(), } - // TODO do not use parentheses on root level or if several operators are on the same level - Expression::Binary { left, operator: BinaryOperator::Or, right } => { - write!(f, "({left} ⋁ {right})") - } - Expression::Binary { left, operator: BinaryOperator::Implication, right } => { - write!(f, "{left} ➔ {right}") - } - Expression::Atomic(value) => write!(f, "{value}"), } } } @@ -116,9 +109,7 @@ mod tests { } #[test] - #[ignore] fn test_expression_a_or_b_and_c_display() { - // TODO let expression = or( atomic("a"), and( @@ -128,6 +119,57 @@ mod tests { assert_eq!(expression.to_string(), "a ⋁ b ⋀ c"); } + #[test] + fn test_expression_a_or_b() { + let expression = or( + atomic("a"), + atomic("b"), + ); + assert_eq!(expression.to_string(), "a ⋁ b"); + } + + #[test] + fn test_expression_double_or() { + let expression = or( + atomic("a"), + or( + atomic("b"), + atomic("c"), + ), + ); + assert_eq!(expression.to_string(), "a ⋁ b ⋁ c"); + } + + #[test] + fn test_expression_triple_or() { + let expression = or( + atomic("a"), + or( + atomic("b"), + or( + atomic("c"), + atomic("d"), + ), + ), + ); + assert_eq!(expression.to_string(), "a ⋁ b ⋁ c ⋁ d"); + } + + #[test] + fn test_expression_nested_parenthesized_or() { + let expression = or( + atomic("a"), + and( + atomic("b"), + or( + atomic("b"), + atomic("c"), + ), + ), + ); + assert_eq!(expression.to_string(), "a ⋁ b ⋀ (b ⋁ c)"); + } + #[test] fn test_expression_c_and_a_or_b_display() { let expression = and( diff --git a/src/expressions/iterator.rs b/src/expressions/iterator.rs deleted file mode 100644 index c5932a1..0000000 --- a/src/expressions/iterator.rs +++ /dev/null @@ -1,50 +0,0 @@ -use std::ops::Deref; -use std::rc::Rc; -use crate::expressions::expression::Expression; - -pub struct ExpressionIterator { - stack: Vec>, -} - -impl ExpressionIterator { - pub fn new(expression: Expression) -> Self { - let stack = vec![expression.into()]; - Self { stack } - } -} - -impl Iterator for ExpressionIterator { - type Item = Rc; - - fn next(&mut self) -> Option { - let expression = self.stack.pop()?; - match expression.deref() { - Expression::Atomic(_) => Some(expression), - Expression::Not(inner) => { - self.stack.push(inner.clone()); - Some(expression) - } - Expression::Binary { left, right, .. } => { - self.stack.push(right.clone()); - self.stack.push(left.clone()); - Some(expression) - } - } - } -} - -#[cfg(test)] -mod tests { - use crate::expressions::helpers::{and, atomic, not}; - - #[test] - fn test_expression_iterator() { - let expression = not(and(atomic("A"), atomic("B"))); - let mut iterator = expression.iter(); - assert_eq!(iterator.next().unwrap(), expression.into()); - assert_eq!(iterator.next().unwrap(), and(atomic("A"), atomic("B")).into()); - assert_eq!(iterator.next().unwrap(), atomic("A").into()); - assert_eq!(iterator.next().unwrap(), atomic("B").into()); - assert_eq!(iterator.next(), None); - } -} diff --git a/src/expressions/mod.rs b/src/expressions/mod.rs index 32219c5..5fe10e8 100644 --- a/src/expressions/mod.rs +++ b/src/expressions/mod.rs @@ -2,5 +2,4 @@ pub mod expression; pub mod operator; pub mod helpers; pub mod simplify; -pub mod truth_table; -mod iterator; \ No newline at end of file +pub mod truth_table; \ No newline at end of file diff --git a/src/expressions/simplify.rs b/src/expressions/simplify.rs index 0e000f0..0883c2e 100644 --- a/src/expressions/simplify.rs +++ b/src/expressions/simplify.rs @@ -271,7 +271,7 @@ mod tests { assert_eq!(operations.len(), 1); assert_eq!(operations[0].law, Law::EliminationOfImplication); assert_eq!(operations[0].before, "a ➔ b"); - assert_eq!(operations[0].after, "(¬a ⋁ b)"); + assert_eq!(operations[0].after, "¬a ⋁ b"); } #[test] @@ -282,10 +282,10 @@ mod tests { assert_eq!(operations.len(), 2); assert_eq!(operations[0].law, Law::EliminationOfImplication); assert_eq!(operations[0].before, "b ➔ c"); - assert_eq!(operations[0].after, "(¬b ⋁ c)"); + assert_eq!(operations[0].after, "¬b ⋁ c"); assert_eq!(operations[1].law, Law::EliminationOfImplication); assert_eq!(operations[1].before, "a ➔ b ➔ c"); - assert_eq!(operations[1].after, "(¬a ⋁ (¬b ⋁ c))"); + assert_eq!(operations[1].after, "¬a ⋁ ¬b ⋁ c"); } #[test] @@ -362,7 +362,7 @@ mod tests { assert_eq!(operations.len(), 1); assert_eq!(operations[0].law, Law::DeMorgansLaws); assert_eq!(operations[0].before, "¬(a ⋀ b)"); - assert_eq!(operations[0].after, "(¬a ⋁ ¬b)"); + assert_eq!(operations[0].after, "¬a ⋁ ¬b"); } #[test] diff --git a/src/expressions/truth_table.rs b/src/expressions/truth_table.rs index 8e90f4a..a53e6cf 100644 --- a/src/expressions/truth_table.rs +++ b/src/expressions/truth_table.rs @@ -188,7 +188,7 @@ mod tests { let truth_table = TruthTable::new(&expression, Default::default()); let atomics = 3; - assert_eq!(truth_table.header, vec!["A", "C", "(A ⋁ C)", "B", "(B ⋁ C)", "(A ⋁ C) ⋀ (B ⋁ C)"]); + assert_eq!(truth_table.header, vec!["A", "C", "A ⋁ C", "B", "B ⋁ C", "(A ⋁ C) ⋀ (B ⋁ C)"]); assert_eq!(truth_table.truth_matrix.len(), 2usize.pow(atomics as u32)); assert_eq!(truth_table.truth_matrix[0].len(), 6); assert_eq!(truth_table.truth_matrix[0], vec![true, true, true, true, true, true]); @@ -361,7 +361,7 @@ mod tests { fn test_resolve_expression_or_1_true_1_false() { let expression = or(atomic("A"), atomic("B")); let booleans = map!["A".into() => true, "B".into() => false]; - let header = vec!["A".into(), "B".into(), "(A ⋁ B)".into()]; + let header = vec!["A".into(), "B".into(), "A ⋁ B".into()]; let values = TruthTable::resolve_expression(&expression, &booleans, &header); assert_eq!(values, vec![true, false, true]); } @@ -423,7 +423,7 @@ mod tests { fn test_binary_or_expression() { let expression = or(atomic("A"), atomic("B")); let header = TruthTable::extract_header(&expression); - assert_eq!(header, vec!["A", "B", "(A ⋁ B)"]); + assert_eq!(header, vec!["A", "B", "A ⋁ B"]); } #[test] @@ -437,7 +437,7 @@ mod tests { fn test_complex_expression() { let expression = implies(and(atomic("A"), atomic("B")), or(atomic("C"), atomic("D"))); let header = TruthTable::extract_header(&expression); - assert_eq!(header, vec!["A", "B", "A ⋀ B", "C", "D", "(C ⋁ D)", "A ⋀ B ➔ (C ⋁ D)"]); + assert_eq!(header, vec!["A", "B", "A ⋀ B", "C", "D", "C ⋁ D", "A ⋀ B ➔ (C ⋁ D)"]); } #[test] @@ -451,6 +451,6 @@ mod tests { fn test_somewhat_equal() { let expression = and(atomic("A"), and(or(not(atomic("A")), atomic("B")), atomic("A"))); let header = TruthTable::extract_header(&expression); - assert_eq!(header, vec!["A", "¬A", "B", "(¬A ⋁ B)", "(¬A ⋁ B) ⋀ A", "A ⋀ (¬A ⋁ B) ⋀ A"]); + assert_eq!(header, vec!["A", "¬A", "B", "¬A ⋁ B", "(¬A ⋁ B) ⋀ A", "A ⋀ (¬A ⋁ B) ⋀ A"]); } }