Finished truth table impl
This commit is contained in:
parent
1afd9d9848
commit
5c8f602d1d
@ -1,5 +1,6 @@
|
||||
use std::fmt::Display;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::expressions::iterator::ExpressionIterator;
|
||||
|
||||
use crate::expressions::operator::BinaryOperator;
|
||||
use crate::parsing::expression_parser::parse_expression;
|
||||
@ -52,6 +53,19 @@ impl Expression {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> ExpressionIterator {
|
||||
ExpressionIterator::new(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for Expression {
|
||||
type Item = Expression;
|
||||
type IntoIter = ExpressionIterator;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
ExpressionIterator::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl OppositeEq for Expression {
|
||||
|
49
src/expressions/iterator.rs
Normal file
49
src/expressions/iterator.rs
Normal file
@ -0,0 +1,49 @@
|
||||
use crate::expressions::expression::Expression;
|
||||
|
||||
pub struct ExpressionIterator {
|
||||
stack: Vec<Expression>,
|
||||
}
|
||||
|
||||
impl ExpressionIterator {
|
||||
pub fn new(expression: Expression) -> Self {
|
||||
let stack = vec![expression];
|
||||
Self { stack }
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for ExpressionIterator {
|
||||
type Item = Expression;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(expression) = self.stack.pop() {
|
||||
match &expression {
|
||||
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)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn test_expression_iterator() {
|
||||
let expression = not!(and!(atomic!("A"), atomic!("B")));
|
||||
let mut iterator = expression.iter();
|
||||
assert_eq!(iterator.next().unwrap(), expression);
|
||||
assert_eq!(iterator.next().unwrap(), and!(atomic!("A"), atomic!("B")));
|
||||
assert_eq!(iterator.next().unwrap(), atomic!("A"));
|
||||
assert_eq!(iterator.next().unwrap(), atomic!("B"));
|
||||
assert_eq!(iterator.next(), None);
|
||||
}
|
||||
}
|
@ -3,4 +3,5 @@ pub mod operator;
|
||||
#[macro_use]
|
||||
pub mod helpers;
|
||||
pub mod simplify;
|
||||
mod truth_table;
|
||||
mod truth_table;
|
||||
mod iterator;
|
@ -1,8 +1,10 @@
|
||||
use std::slice::Iter;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::expressions::expression::Expression;
|
||||
use crate::matrix;
|
||||
use crate::utils::array::{alternating_array, Distinct};
|
||||
use crate::expressions::operator::BinaryOperator;
|
||||
use crate::utils::array::Distinct;
|
||||
|
||||
type TruthMatrix = Vec<Vec<bool>>;
|
||||
|
||||
@ -81,74 +83,106 @@ impl TruthTable {
|
||||
if count == 0 {
|
||||
return vec![];
|
||||
}
|
||||
let helper = Self::helper_matrix(count);
|
||||
for row in &helper {
|
||||
let truths = Self::generate_truth_table(row, expression);
|
||||
}
|
||||
todo!()
|
||||
Self::truth_combinations(count)
|
||||
.iter().map(|combo| {
|
||||
Self::resolve_expression(expression, &mut combo.iter())
|
||||
}).collect()
|
||||
}
|
||||
|
||||
fn helper_matrix(number_of_atomics: usize) -> TruthMatrix {
|
||||
let len = 2usize.pow(number_of_atomics as u32);
|
||||
let mut change_index = len / 2;
|
||||
let mut rows: Vec<Vec<bool>> = matrix![false; 0 => number_of_atomics];
|
||||
for row in &mut rows {
|
||||
*row = alternating_array(len, change_index);
|
||||
change_index /= 2;
|
||||
}
|
||||
rows
|
||||
fn truth_combinations(count: usize) -> TruthMatrix {
|
||||
(0..2usize.pow(count as u32))
|
||||
.map(|i| (0..count).rev()
|
||||
// Just trust me bro
|
||||
.map(|j| (i >> j) & 1 == 0).collect()
|
||||
).collect()
|
||||
}
|
||||
|
||||
// TODO store the expressions along with their values in a list tree structure
|
||||
// For each node. Their left child is index * 2 + 1 and right child is index * 2 + 2
|
||||
// Ex: 0 -> (1, 2), 1 -> (3, 4), 2 -> (5, 6)
|
||||
fn generate_truth_table<'a>(truth_row: &[bool], expression: &'a Expression) -> Vec<Option<(&'a Expression, bool)>> {
|
||||
fn resolve_expression(expression: &Expression, booleans: &mut Iter<bool>) -> Vec<bool> {
|
||||
match expression {
|
||||
not @ Expression::Not(expr) => {
|
||||
[
|
||||
vec![Some((not, Self::resolve_expression(not, truth_row)))],
|
||||
Self::generate_truth_table(truth_row, expr),
|
||||
vec![None]
|
||||
].concat()
|
||||
Expression::Not(expr) => {
|
||||
Self::resolve_expression(expr, booleans)
|
||||
.iter().map(|value| !value).collect()
|
||||
}
|
||||
binary @ Expression::Binary { left, right, .. } => {
|
||||
[
|
||||
vec![Some((binary, Self::resolve_expression(binary, truth_row)))],
|
||||
Self::generate_truth_table(truth_row, left),
|
||||
Self::generate_truth_table(truth_row, right)
|
||||
].concat()
|
||||
Expression::Binary { left, right, .. } => {
|
||||
let left_values = Self::resolve_expression(left, booleans);
|
||||
let right_values = Self::resolve_expression(right, booleans);
|
||||
left_values.iter()
|
||||
.zip(right_values.iter())
|
||||
.flat_map(|(left_value, right_value)| {
|
||||
[*left_value, *right_value, match expression {
|
||||
Expression::Binary { operator: BinaryOperator::And, .. } => *left_value && *right_value,
|
||||
Expression::Binary { operator: BinaryOperator::Or, .. } => *left_value || *right_value,
|
||||
Expression::Binary { operator: BinaryOperator::Implication, .. } => !*left_value || *right_value,
|
||||
_ => false,
|
||||
}]
|
||||
}).collect()
|
||||
}
|
||||
atomic @ Expression::Atomic(_) => {
|
||||
vec![Some((expression, Self::resolve_expression(atomic, truth_row)))]
|
||||
Expression::Atomic(_) => {
|
||||
if let Some(value) = booleans.next() {
|
||||
vec![*value]
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_expression(expression: &Expression, helper: &[bool]) -> bool {
|
||||
todo!("Resolve the expression with the given row of booleans")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::matrix;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_helper_matrix_3() {
|
||||
let helper = TruthTable::helper_matrix(3);
|
||||
assert_eq!(helper, matrix![
|
||||
true, true, true, true, false, false, false, false;
|
||||
true, true, false, false, true, true, false, false;
|
||||
true, false, true, false, true, false, true, false
|
||||
fn test_new_truth_table() {
|
||||
let expression = and!(atomic!("A"), atomic!("B"));
|
||||
let truth_table = TruthTable::new(&expression, Default::default());
|
||||
assert_eq!(truth_table.header, vec!["A", "B", "A ⋀ B"]);
|
||||
assert_eq!(truth_table.truth_matrix, matrix![
|
||||
true, true, true;
|
||||
true, false, false;
|
||||
false, true, false;
|
||||
false, false, false
|
||||
]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_helper_matrix_1() {
|
||||
let helper = TruthTable::helper_matrix(1);
|
||||
assert_eq!(helper, matrix![true, false]);
|
||||
fn test_truth_combinations() {
|
||||
let combinations = TruthTable::truth_combinations(3);
|
||||
assert_eq!(combinations, matrix![
|
||||
true, true, true;
|
||||
true, true, false;
|
||||
true, false, true;
|
||||
true, false, false;
|
||||
false, true, true;
|
||||
false, true, false;
|
||||
false, false, true;
|
||||
false, false, false
|
||||
]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolve_expression_and_all_true() {
|
||||
let expression = and!(atomic!("A"), atomic!("B"));
|
||||
let booleans = [true, true];
|
||||
let values = TruthTable::resolve_expression(&expression, &mut booleans.iter());
|
||||
assert_eq!(values, vec![true, true, true]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolve_expression_and_1_true_1_false() {
|
||||
let expression = and!(atomic!("A"), atomic!("B"));
|
||||
let booleans = [true, false];
|
||||
let values = TruthTable::resolve_expression(&expression, &mut booleans.iter());
|
||||
assert_eq!(values, vec![true, false, false]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolve_expression_or_1_true_1_false() {
|
||||
let expression = or!(atomic!("A"), atomic!("B"));
|
||||
let booleans = [true, false];
|
||||
let values = TruthTable::resolve_expression(&expression, &mut booleans.iter());
|
||||
assert_eq!(values, vec![true, false, true]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -48,44 +48,11 @@ impl<T: PartialEq + Clone> Distinct for Vec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn alternating_array(n: usize, mut skip: usize) -> Vec<bool> {
|
||||
skip = max(skip, 1);
|
||||
let mut array = vec![false; n];
|
||||
let mut cell_value = false;
|
||||
for (index, value) in array.iter_mut().enumerate() {
|
||||
if index % skip == 0 {
|
||||
cell_value = !cell_value;
|
||||
}
|
||||
*value = cell_value;
|
||||
}
|
||||
array
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_alternating_array() {
|
||||
assert_eq!(alternating_array(4, 2), vec![true, true, false, false]);
|
||||
assert_eq!(alternating_array(5, 1), vec![true, false, true, false, true]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_alternating_array_0_skip() {
|
||||
assert_eq!(alternating_array(4, 0), vec![true, false, true, false]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_alternating_array_0_length() {
|
||||
assert_eq!(alternating_array(0, 2), vec![] as Vec<bool>);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_alternating_array_skip_greater_than_length() {
|
||||
assert_eq!(alternating_array(4, 5), vec![true, true, true, true]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_distinct() {
|
||||
let mut vec = vec![1, 2, 3, 1, 2, 3];
|
||||
|
Loading…
x
Reference in New Issue
Block a user