feat(ex05): done + rustfmt oops

This commit is contained in:
gbrochar 2024-01-24 13:27:46 +01:00
parent 4abcd4c832
commit dea2e2d6a3
12 changed files with 335 additions and 140 deletions

View File

@ -12,4 +12,3 @@ pub fn adder(a: u32, b: u32) -> u32 {
}
result
}

View File

@ -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<T> {
pub enum Node<T>
where
T: Clone + std::fmt::Debug,
{
Leaf(T),
Unary {
operator: Token,
operand: Box<Node<T>>
operand: Box<Node<T>>,
},
Binary {
operator: Token,
@ -26,27 +28,207 @@ pub enum Node<T> {
}
impl<T> Node<T>
where T: Clone {
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 => {
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<bool> {
pub fn parse_formula(formula: &str) -> Node<bool> {
let mut stack = vec![];
@ -60,7 +242,7 @@ impl Node<bool> {
'^' => 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<bool> {
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<char> {
pub fn parse_formula(formula: &str) -> Node<char> {
@ -96,7 +278,7 @@ impl Node<char> {
'^' => 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<char> {
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<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());
stack.push(Node::Unary {
operator: token,
@ -128,31 +313,33 @@ pub fn add_unary_node<T>(stack: &mut Vec<Node<T>>, token: Token) {
});
}
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 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 => '=',
}
}

View File

@ -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::<bool>::ast_to_formula(&Node::<bool>::parse_formula(formula)), formula);
assert_eq!(
Node::<bool>::ast_to_formula(&Node::<bool>::parse_formula(formula)),
formula
);
let formula = "01&00|&";
assert_eq!(Node::<bool>::ast_to_formula(&Node::<bool>::parse_formula(formula)), formula);
assert_eq!(
Node::<bool>::ast_to_formula(&Node::<bool>::parse_formula(formula)),
formula
);
let formula = "01&00|&11^&";
assert_eq!(Node::<bool>::ast_to_formula(&Node::<bool>::parse_formula(formula)), formula);
assert_eq!(
Node::<bool>::ast_to_formula(&Node::<bool>::parse_formula(formula)),
formula
);
let formula = "01&00|&11=^";
assert_eq!(Node::<bool>::ast_to_formula(&Node::<bool>::parse_formula(formula)), formula);
assert_eq!(
Node::<bool>::ast_to_formula(&Node::<bool>::parse_formula(formula)),
formula
);
let formula = "01&00|&0!=";
assert_eq!(Node::<bool>::ast_to_formula(&Node::<bool>::parse_formula(formula)), formula);
assert_eq!(
Node::<bool>::ast_to_formula(&Node::<bool>::parse_formula(formula)),
formula
);
}
#[test]
fn ast_to_formula_char() {
let formula = "AB&";
assert_eq!(Node::<char>::ast_to_formula(&Node::<char>::parse_formula(formula)), formula);
assert_eq!(
Node::<char>::ast_to_formula(&Node::<char>::parse_formula(formula)),
formula
);
let formula = "AB&CD|&";
assert_eq!(Node::<char>::ast_to_formula(&Node::<char>::parse_formula(formula)), formula);
assert_eq!(
Node::<char>::ast_to_formula(&Node::<char>::parse_formula(formula)),
formula
);
let formula = "AB&AC|&DE^&";
assert_eq!(Node::<char>::ast_to_formula(&Node::<char>::parse_formula(formula)), formula);
assert_eq!(
Node::<char>::ast_to_formula(&Node::<char>::parse_formula(formula)),
formula
);
let formula = "AB&CD|&EF=^";
assert_eq!(Node::<char>::ast_to_formula(&Node::<char>::parse_formula(formula)), formula);
assert_eq!(
Node::<char>::ast_to_formula(&Node::<char>::parse_formula(formula)),
formula
);
let formula = "AB&CD|&E!=";
assert_eq!(Node::<char>::ast_to_formula(&Node::<char>::parse_formula(formula)), formula);
assert_eq!(
Node::<char>::ast_to_formula(&Node::<char>::parse_formula(formula)),
formula
);
}
}
}

View File

@ -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>) -> bool {
pub fn eval_formula(formula: &str) -> bool {
let tree = Node::<bool>::parse_formula(formula);
evaluate(tree)
}
}

View File

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

View File

@ -10,4 +10,3 @@ pub fn gray_code(n: u32) -> u32 {
}
result
}

View File

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

View File

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

View File

@ -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);

View File

@ -2,76 +2,8 @@ mod tests;
use crate::ast::Node;
// fn cancel_double_negation(ast: &mut Node<char>, parent: Option<&mut Node<char>>) -> Node<char> {
// 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<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 {
let mut ast = Node::<char>::parse_formula(formula);
// let mut tmp = Node::<char>::parse_formula((formula.to_string() + "!").as_str());
// let mut clone = ast.clone();
// while Node::<char>::ast_to_formula(&clone) != Node::<char>::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::<char>::ast_to_formula(&ast)
}
}

View File

@ -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|&");
}
}
#[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");
}
}

View File

@ -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<bool> {
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::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<char> {
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<char>, 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
}
// call eval formula a lot
}