Fixed parenthesis when not needed. Removed some unused functions

This commit is contained in:
Martin Berg Alstad 2024-06-17 11:41:28 +02:00
parent 9226060397
commit 78368772eb
5 changed files with 81 additions and 90 deletions

View File

@ -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<Expression>;
type IntoIter = ExpressionIterator;
fn into_iter(self) -> Self::IntoIter {
ExpressionIterator::new(self)
}
}
impl OppositeEq for Expression {
@ -83,20 +69,27 @@ impl TryFrom<String> 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(

View File

@ -1,50 +0,0 @@
use std::ops::Deref;
use std::rc::Rc;
use crate::expressions::expression::Expression;
pub struct ExpressionIterator {
stack: Vec<Rc<Expression>>,
}
impl ExpressionIterator {
pub fn new(expression: Expression) -> Self {
let stack = vec![expression.into()];
Self { stack }
}
}
impl Iterator for ExpressionIterator {
type Item = Rc<Expression>;
fn next(&mut self) -> Option<Self::Item> {
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);
}
}

View File

@ -2,5 +2,4 @@ pub mod expression;
pub mod operator;
pub mod helpers;
pub mod simplify;
pub mod truth_table;
mod iterator;
pub mod truth_table;

View File

@ -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]

View File

@ -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"]);
}
}