diff --git a/src/bdd/mod.rs b/src/bdd/mod.rs index 90207cf..2ea37ba 100644 --- a/src/bdd/mod.rs +++ b/src/bdd/mod.rs @@ -102,7 +102,7 @@ impl Bdd { Ok(BddVariableSet::new_anonymous(num_vars)) } - pub(crate) fn inner(&self) -> &InnerBdd { + pub fn inner(&self) -> &InnerBdd { &self.bdd } diff --git a/src/bindings/bdd.rs b/src/bindings/bdd.rs index 7b267f3..7ae9f92 100644 --- a/src/bindings/bdd.rs +++ b/src/bindings/bdd.rs @@ -10,7 +10,9 @@ use crate::bindings::iterators::{ PythonBddRangeIterator, PythonBddRelationIterator, PythonBddSupportIterator, PythonDomainIterator, }; +use crate::bindings::table::PythonTruthTable; use crate::expressions::Expression; +use crate::table::TruthTable; use crate::traits::{BooleanFunction, BooleanPoint, BooleanValuation, Evaluate}; #[pyclass(frozen, name = "Bdd")] @@ -25,19 +27,20 @@ impl From> for PythonBdd { } } -#[pymethods] -impl PythonBdd { - #[staticmethod] - pub fn from_expression(expression: &PythonExpression) -> PyResult { - let native: Expression = expression.into(); - match Bdd::try_from(native) { - Ok(bdd) => Ok(Self::new(bdd)), - Err(_e) => Err(PyRuntimeError::new_err( - "Conversion failed. Too many variables.", - )), - } +impl From for Bdd { + fn from(value: PythonBdd) -> Self { + (&value).into() } +} +impl From<&PythonBdd> for Bdd { + fn from(value: &PythonBdd) -> Self { + value.root.clone() + } +} + +#[pymethods] +impl PythonBdd { #[staticmethod] pub fn mk_not(inner: &PythonBdd) -> PythonBdd { PythonBdd::new(!(&inner.root)) @@ -293,6 +296,36 @@ impl PythonBdd { fn is_implied_by(&self, other: &Self) -> bool { self.root.is_implied_by(&other.root) } + + #[staticmethod] + pub fn from_expression(expression: &PythonExpression) -> PyResult { + let native: Expression = expression.into(); + match Bdd::try_from(native) { + Ok(bdd) => Ok(Self::new(bdd)), + Err(_e) => Err(PyRuntimeError::new_err( + "Conversion failed. Too many variables.", + )), + } + } + + #[staticmethod] + pub fn from_table(table: &PythonTruthTable) -> PyResult { + let native: TruthTable = table.into(); + match Bdd::try_from(native) { + Ok(bdd) => Ok(Self::new(bdd)), + Err(_e) => Err(PyRuntimeError::new_err( + "Conversion failed. Too many variables.", + )), + } + } + + pub fn to_expression(&self) -> PythonExpression { + PythonExpression::from_bdd(self) + } + + pub fn to_table(&self) -> PythonTruthTable { + PythonTruthTable::from_bdd(self) + } } impl PythonBdd { diff --git a/src/bindings/expression.rs b/src/bindings/expression.rs index 21d6d2a..d97c5ef 100644 --- a/src/bindings/expression.rs +++ b/src/bindings/expression.rs @@ -2,6 +2,8 @@ use num_bigint::BigUint; use std::collections::{BTreeMap, BTreeSet}; use std::str::FromStr; +use crate::bdd::Bdd; +use crate::bindings::bdd::PythonBdd; use pyo3::prelude::{pyclass, pyfunction, pymethods, PyAny, PyAnyMethods, PyResult}; use pyo3::Bound; @@ -11,7 +13,9 @@ use crate::bindings::iterators::{ PythonDomainIterator, PythonExpressionRangeIterator, PythonExpressionRelationIterator, PythonExpressionSupportIterator, }; +use crate::bindings::table::PythonTruthTable; use crate::expressions::{Expression as RustExpression, Expression, ExpressionNode}; +use crate::table::TruthTable; use crate::traits::{ BooleanFunction, BooleanPoint, BooleanValuation, Evaluate, GatherLiterals, SemanticEq, }; @@ -152,6 +156,18 @@ impl PythonExpression { Self::new(RustExpression::negate(&expression.root)) } + fn __invert__(&self) -> PythonExpression { + Self::mk_not(self) + } + + fn __and__(&self, other: &PythonExpression) -> PythonExpression { + Self::mk_and_binary(self, other) + } + + fn __or__(&self, other: &PythonExpression) -> PythonExpression { + Self::mk_or_binary(self, other) + } + #[staticmethod] pub fn mk_and_binary(left: &PythonExpression, right: &PythonExpression) -> PythonExpression { Self::new(RustExpression::binary_and(&left.root, &right.root)) @@ -373,6 +389,30 @@ impl PythonExpression { fn is_implied_by(&self, other: &Self) -> bool { self.root.is_implied_by(&other.root) } + + #[staticmethod] + pub fn from_table(table: &PythonTruthTable) -> Self { + let rust_table: TruthTable = table.into(); + let rust_expression: Expression = rust_table.to_expression_trivial(); + + Self::new(rust_expression) + } + + #[staticmethod] + pub fn from_bdd(bdd: &PythonBdd) -> Self { + let rust_table: Bdd = bdd.into(); + let rust_expression: Expression = rust_table.into(); + + Self::new(rust_expression) + } + + fn to_table(&self) -> PythonTruthTable { + PythonTruthTable::from_expression(self) + } + + fn to_bdd(&self) -> PyResult { + PythonBdd::from_expression(self) + } } impl PythonExpression { diff --git a/src/bindings/mod.rs b/src/bindings/mod.rs index bbb6e44..631602f 100644 --- a/src/bindings/mod.rs +++ b/src/bindings/mod.rs @@ -7,6 +7,7 @@ mod table; use crate::bindings::bdd::PythonBdd; use crate::bindings::expression::PythonExpression; use crate::bindings::table::PythonTruthTable; +use crate::table::display_formatted::{TableBooleanFormatting, TableStyle}; use pyo3::prelude::*; /// A Python module implemented in Rust. The name of this function must match @@ -18,6 +19,9 @@ fn biodivine_boolean_functions(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_function(wrap_pyfunction!(crate::bindings::expression::var, m)?)?; m.add_function(wrap_pyfunction!(crate::bindings::expression::vars, m)?)?; m.add_function(wrap_pyfunction!(crate::bindings::expression::bool, m)?)?; diff --git a/src/bindings/table.rs b/src/bindings/table.rs index da50500..0d5cb3b 100644 --- a/src/bindings/table.rs +++ b/src/bindings/table.rs @@ -1,6 +1,8 @@ use num_bigint::BigUint; use std::collections::{BTreeMap, BTreeSet}; +use crate::bdd::Bdd; +use crate::bindings::bdd::PythonBdd; use pyo3::PyResult; use crate::bindings::error::PythonExpressionError::UnknownVariableWhileEvaluating; @@ -28,20 +30,20 @@ impl From> for PythonTruthTable { } } -#[pyo3::pymethods] -impl PythonTruthTable { - #[staticmethod] - pub fn from_expression(expression: &PythonExpression) -> Self { - let rust_expression: RustExpression = expression.into(); - let rust_table: TruthTable = rust_expression.into(); - - Self::new(rust_table) +impl From for TruthTable { + fn from(value: PythonTruthTable) -> Self { + (&value).into() } +} - pub fn to_expression_trivial(&self) -> PythonExpression { - self.root.to_expression_trivial().into() +impl From<&PythonTruthTable> for TruthTable { + fn from(value: &PythonTruthTable) -> Self { + value.root.clone() } +} +#[pyo3::pymethods] +impl PythonTruthTable { pub fn to_string_formatted( &self, style: TableStyle, @@ -321,6 +323,30 @@ impl PythonTruthTable { fn is_implied_by(&self, other: &Self) -> bool { self.root.is_implied_by(&other.root) } + + #[staticmethod] + pub fn from_expression(expression: &PythonExpression) -> Self { + let rust_expression: RustExpression = expression.into(); + let rust_table: TruthTable = rust_expression.into(); + + rust_table.into() + } + + #[staticmethod] + pub fn from_bdd(expression: &PythonBdd) -> Self { + let rust_expression: Bdd = expression.into(); + let rust_table: TruthTable = rust_expression.into(); + + rust_table.into() + } + + pub fn to_expression(&self) -> PythonExpression { + PythonExpression::from_table(self) + } + + pub fn to_bdd(&self) -> PyResult { + PythonBdd::from_table(self) + } } impl PythonTruthTable {