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