Skip to content

Commit

Permalink
feat(bool fn trait): implemented iterator structs for Expression
Browse files Browse the repository at this point in the history
This satisfies BooleanFunctions's types DomainIterator, RangeIterator, RelationIterator, SupportIterator.
  • Loading branch information
AurumTheEnd committed Apr 25, 2024
1 parent 5053114 commit 68c68f7
Show file tree
Hide file tree
Showing 6 changed files with 431 additions and 0 deletions.
115 changes: 115 additions & 0 deletions src/expressions/iterators/domain.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use crate::expressions::Expression;
use crate::traits::{BooleanPoint, GatherLiterals};
use crate::utils::{boolean_point_to_valuation, row_index_to_bool_point};
use std::collections::BTreeMap;
use std::fmt::Debug;

pub struct ExpressionDomainIterator {
variable_count: usize,
index: usize,
}

impl<T: Debug + Clone + Ord> From<&Expression<T>> for ExpressionDomainIterator {
fn from(value: &Expression<T>) -> Self {
Self {
variable_count: value.gather_literals().len(),
index: 0,
}
}
}

impl Iterator for ExpressionDomainIterator {
type Item = Vec<bool>;

fn next(&mut self) -> Option<Self::Item> {
if self.index >= 2_usize.pow(self.variable_count as u32) {
return None;
}

let result = row_index_to_bool_point(self.index, self.variable_count);
self.index += 1;

Some(result)
}
}

impl<T: Debug + Clone + Eq + Ord> Expression<T> {
pub fn boolean_point_to_valuation(&self, point: BooleanPoint) -> Option<BTreeMap<T, bool>> {
boolean_point_to_valuation(self.gather_literals(), point)
}
}

#[cfg(test)]
mod tests {
use crate::expressions::var;
use crate::traits::BooleanFunction;
use std::collections::BTreeMap;

#[test]
fn test_domain_ends() {
let input = var("a") | var("b");
let mut iterator = input.domain();

assert!(iterator.next().is_some());
assert!(iterator.next().is_some());
assert!(iterator.next().is_some());
assert!(iterator.next().is_some());
assert!(iterator.next().is_none());
assert!(iterator.next().is_none());
}

#[test]
fn test_domain_ok() {
let input = var("d") & var("b") | var("a");

let actual = input.domain().collect::<Vec<_>>();

let expected = vec![
vec![false, false, false],
vec![false, false, true],
vec![false, true, false],
vec![false, true, true],
vec![true, false, false],
vec![true, false, true],
vec![true, true, false],
vec![true, true, true],
];

assert_eq!(actual, expected);
}

#[test]
fn test_point_to_valuation_ok() -> Result<(), String> {
let input = var("d") & var("b") | var("a");

let actual = input
.domain()
.map(|point| input.boolean_point_to_valuation(point))
.collect::<Option<Vec<_>>>()
.ok_or("Failed to translate".to_string())?;

let expected = vec![
vec![false, false, false],
vec![false, false, true],
vec![false, true, false],
vec![false, true, true],
vec![true, false, false],
vec![true, false, true],
vec![true, true, false],
vec![true, true, true],
]
.into_iter()
.map(|point| {
BTreeMap::from_iter(vec![
("a".to_string(), point[0]),
("b".to_string(), point[1]),
("d".to_string(), point[2]),
])
})
.collect::<Vec<_>>();

assert_eq!(actual, expected);

Ok(())
}
}
108 changes: 108 additions & 0 deletions src/expressions/iterators/image.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
use crate::expressions::Expression;
use crate::traits::{Evaluate, GatherLiterals};
use crate::utils::{boolean_point_to_valuation, row_index_to_bool_point};
use std::collections::BTreeSet;
use std::fmt::Debug;

pub struct ExpressionImageIterator<T: Debug + Clone + Ord> {
variables: BTreeSet<T>,
expression: Expression<T>,
index: usize,
}

impl<T: Debug + Clone + Ord> From<&Expression<T>> for ExpressionImageIterator<T> {
fn from(value: &Expression<T>) -> Self {
Self {
variables: value.gather_literals(),
expression: value.clone(),
index: 0,
}
}
}

impl<T: Debug + Clone + Ord> Iterator for ExpressionImageIterator<T> {
type Item = bool;

fn next(&mut self) -> Option<Self::Item> {
if self.index >= 2_usize.pow(self.variables.len() as u32) {
return None;
}

let boolean_point = row_index_to_bool_point(self.index, self.variables.len());
let valuation = boolean_point_to_valuation(self.variables.clone(), boolean_point)?;
let result = self.expression.evaluate(&valuation);

self.index += 1;

Some(result)
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::expressions::var;
use crate::traits::BooleanFunction;
use std::collections::BTreeMap;

#[test]
fn test_image_ok() {
let input = var("d") & var("b") | var("a");

let mut actual = input.image();
let expected = [
Some(input.evaluate(&BTreeMap::from([
("a".to_string(), false),
("b".to_string(), false),
("d".to_string(), false),
]))),
Some(input.evaluate(&BTreeMap::from([
("a".to_string(), false),
("b".to_string(), false),
("d".to_string(), true),
]))),
Some(input.evaluate(&BTreeMap::from([
("a".to_string(), false),
("b".to_string(), true),
("d".to_string(), false),
]))),
Some(input.evaluate(&BTreeMap::from([
("a".to_string(), false),
("b".to_string(), true),
("d".to_string(), true),
]))),
Some(input.evaluate(&BTreeMap::from([
("a".to_string(), true),
("b".to_string(), false),
("d".to_string(), false),
]))),
Some(input.evaluate(&BTreeMap::from([
("a".to_string(), true),
("b".to_string(), false),
("d".to_string(), true),
]))),
Some(input.evaluate(&BTreeMap::from([
("a".to_string(), true),
("b".to_string(), true),
("d".to_string(), false),
]))),
Some(input.evaluate(&BTreeMap::from([
("a".to_string(), true),
("b".to_string(), true),
("d".to_string(), true),
]))),
];

assert_eq!(actual.next(), expected[0]);
assert_eq!(actual.next(), expected[1]);
assert_eq!(actual.next(), expected[2]);
assert_eq!(actual.next(), expected[3]);
assert_eq!(actual.next(), expected[4]);
assert_eq!(actual.next(), expected[5]);
assert_eq!(actual.next(), expected[6]);
assert_eq!(actual.next(), expected[7]);

assert_eq!(actual.next(), None);
assert_eq!(actual.next(), None);
}
}
9 changes: 9 additions & 0 deletions src/expressions/iterators/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
pub use domain::ExpressionDomainIterator;
pub use image::ExpressionImageIterator;
pub use relation::ExpressionRelationIterator;
pub use support::ExpressionSupportIterator;

mod domain;
mod image;
mod relation;
mod support;
88 changes: 88 additions & 0 deletions src/expressions/iterators/relation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use crate::expressions::Expression;
use crate::traits::{BooleanPoint, Evaluate, GatherLiterals};
use crate::utils::{boolean_point_to_valuation, row_index_to_bool_point};
use std::collections::BTreeSet;
use std::fmt::Debug;

pub struct ExpressionRelationIterator<T: Debug + Clone + Ord> {
variables: BTreeSet<T>,
expression: Expression<T>,
index: usize,
}

impl<T: Debug + Clone + Ord> From<&Expression<T>> for ExpressionRelationIterator<T> {
fn from(value: &Expression<T>) -> Self {
Self {
variables: value.gather_literals(),
expression: value.clone(),
index: 0,
}
}
}

impl<T: Debug + Clone + Ord> Iterator for ExpressionRelationIterator<T> {
type Item = (BooleanPoint, bool);

fn next(&mut self) -> Option<Self::Item> {
if self.index >= 2_usize.pow(self.variables.len() as u32) {
return None;
}

let boolean_point = row_index_to_bool_point(self.index, self.variables.len());
let valuation = boolean_point_to_valuation(self.variables.clone(), boolean_point.clone())?;
let result = self.expression.evaluate(&valuation);

self.index += 1;

Some((boolean_point, result))
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::expressions::var;
use crate::traits::BooleanFunction;
use std::collections::BTreeMap;

#[test]
fn test_relation_ok() {
let input = var("d") & var("b") | var("a");

let mut actual = input.relation();
let expected = vec![
vec![false, false, false],
vec![false, false, true],
vec![false, true, false],
vec![false, true, true],
vec![true, false, false],
vec![true, false, true],
vec![true, true, false],
vec![true, true, true],
]
.into_iter()
.map(|point| {
Some((
point.clone(),
input.evaluate(&BTreeMap::from_iter(vec![
("a".to_string(), point[0]),
("b".to_string(), point[1]),
("d".to_string(), point[2]),
])),
))
})
.collect::<Vec<_>>();

assert_eq!(actual.next(), expected[0]);
assert_eq!(actual.next(), expected[1]);
assert_eq!(actual.next(), expected[2]);
assert_eq!(actual.next(), expected[3]);
assert_eq!(actual.next(), expected[4]);
assert_eq!(actual.next(), expected[5]);
assert_eq!(actual.next(), expected[6]);
assert_eq!(actual.next(), expected[7]);

assert_eq!(actual.next(), None);
assert_eq!(actual.next(), None);
}
}
Loading

0 comments on commit 68c68f7

Please sign in to comment.