1
0
mirror of https://github.com/ellmau/adf-obdd.git synced 2025-12-19 09:29:36 +01:00

first step towards issue 1

added strong typing to base-datatypes and ordered bdds

relates to #1

Signed-off-by: Stefan Ellmauthaler <stefan.ellmauthaler@tu-dresden.de>
This commit is contained in:
Stefan Ellmauthaler 2021-11-23 17:16:08 +01:00 committed by Stefan Ellmauthaler
parent 088d4fa092
commit 0ad6460d40
6 changed files with 478 additions and 1 deletions

133
Cargo.lock generated
View File

@ -7,6 +7,18 @@ name = "adf_bdd"
version = "0.1.1" version = "0.1.1"
dependencies = [ dependencies = [
"clap", "clap",
"env_logger",
"log",
"test-env-log",
]
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
] ]
[[package]] [[package]]
@ -35,6 +47,12 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "clap" name = "clap"
version = "2.33.3" version = "2.33.3"
@ -50,6 +68,19 @@ dependencies = [
"vec_map", "vec_map",
] ]
[[package]]
name = "env_logger"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.1.19" version = "0.1.19"
@ -59,18 +90,105 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.107" version = "0.2.107"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219" checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "proc-macro2"
version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.8.0" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "syn"
version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "termcolor"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
dependencies = [
"winapi-util",
]
[[package]]
name = "test-env-log"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877189d680101869f65ef94168105d6c188b3a143c13a2d42cf8a09c4c704f8a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "textwrap" name = "textwrap"
version = "0.11.0" version = "0.11.0"
@ -86,6 +204,12 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]] [[package]]
name = "vec_map" name = "vec_map"
version = "0.8.2" version = "0.8.2"
@ -108,6 +232,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "winapi-x86_64-pc-windows-gnu" name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"

View File

@ -12,3 +12,8 @@ description = "Solver for ADFs grounded semantics by utilising OBDDs - ordered b
[dependencies] [dependencies]
clap = "2.33.*" clap = "2.33.*"
log = "0.4"
[dev-dependencies]
env_logger = "*"
test-env-log = "0.2.*"

View File

@ -31,6 +31,7 @@
RUST_LOG = "debug"; RUST_LOG = "debug";
RUST_BACKTRACE = 1; RUST_BACKTRACE = 1;
buildInputs = [ buildInputs = [
pkgs.rust-bin.nightly.latest.rustfmt
pkgs.rust-bin.stable.latest.default pkgs.rust-bin.stable.latest.default
pkgs.rust-analyzer pkgs.rust-analyzer
pkgs.cargo-audit pkgs.cargo-audit

114
src/datatypes.rs Normal file
View File

@ -0,0 +1,114 @@
use std::{fmt::Display, ops::Deref};
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Copy, Clone)]
pub struct Term(pub usize);
impl Deref for Term {
type Target = usize;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<usize> for Term {
fn from(val: usize) -> Self {
Self(val)
}
}
impl Display for Term {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Term({})", self.0)
}
}
impl Term {
pub const BOT: Term = Term(0);
pub const TOP: Term = Term(1);
pub fn new(val: usize) -> Term {
Term(val)
}
pub fn value(self) -> usize {
self.0
}
}
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Clone, Copy)]
pub struct Var(pub usize);
impl Deref for Var {
type Target = usize;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<usize> for Var {
fn from(val: usize) -> Self {
Self(val)
}
}
impl Display for Var {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Var({})", self.0)
}
}
impl Var {
pub const TOP: Var = Var(usize::MAX);
pub const BOT: Var = Var(usize::MAX - 1);
pub fn value(self) -> usize {
self.0
}
}
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Clone, Copy)]
pub(crate) struct BddNode {
var: Var,
lo: Term,
hi: Term,
}
impl Display for BddNode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "BddNode: {}, lo: {}, hi: {}", self.var, self.lo, self.hi)
}
}
impl BddNode {
pub fn new(var: Var, lo: Term, hi: Term) -> Self {
Self { var, lo, hi }
}
pub fn var(self) -> Var {
self.var
}
pub fn lo(self) -> Term {
self.lo
}
pub fn hi(self) -> Term {
self.hi
}
pub fn bot_node() -> Self {
Self {
var: Var::BOT,
lo: Term::BOT,
hi: Term::BOT,
}
}
pub fn top_node() -> Self {
Self {
var: Var::TOP,
lo: Term::TOP,
hi: Term::TOP,
}
}
}

View File

@ -32,4 +32,6 @@
//! ac(d,d). //! ac(d,d).
//! ``` //! ```
pub mod adf; pub mod adf;
pub mod datatypes;
pub mod obdd; pub mod obdd;
pub mod obdd2;

222
src/obdd2.rs Normal file
View File

@ -0,0 +1,222 @@
use crate::datatypes::*;
use std::{cmp::min, collections::HashMap, fmt::Display, ops::Index};
#[derive(Debug)]
pub(crate) struct Bdd {
nodes: Vec<BddNode>,
cache: HashMap<BddNode, Term>,
}
impl Display for Bdd {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "");
for (idx, elem) in self.nodes.iter().enumerate() {
writeln!(f, "{} {}", idx, *elem)?;
}
Ok(())
}
}
impl Bdd {
pub fn new() -> Self {
Self {
nodes: vec![BddNode::bot_node(), BddNode::top_node()],
cache: HashMap::new(),
}
}
pub fn variable(&mut self, var: Var) -> Term {
self.node(var, Term::BOT, Term::TOP)
}
pub fn constant(val: bool) -> Term {
if val {
Term::TOP
} else {
Term::BOT
}
}
pub fn not(&mut self, term: Term) -> Term {
self.if_then_else(term, Term::BOT, Term::TOP)
}
pub fn and(&mut self, term_a: Term, term_b: Term) -> Term {
self.if_then_else(term_a, term_b, Term::BOT)
}
pub fn or(&mut self, term_a: Term, term_b: Term) -> Term {
self.if_then_else(term_a, Term::TOP, term_b)
}
pub fn imp(&mut self, term_a: Term, term_b: Term) -> Term {
self.if_then_else(term_a, term_b, Term::TOP)
}
pub fn iff(&mut self, term_a: Term, term_b: Term) -> Term {
let not_b = self.not(term_b);
self.if_then_else(term_a, term_b, not_b)
}
pub fn xor(&mut self, term_a: Term, term_b: Term) -> Term {
let not_b = self.not(term_b);
self.if_then_else(term_a, not_b, term_b)
}
pub fn restrict(&mut self, tree: Term, var: Var, val: bool) -> Term {
let node = self.nodes[tree.0];
if node.var() > var || node.var() >= Var::BOT {
tree
} else if node.var() < var {
let lonode = self.restrict(node.lo(), var, val);
let hinode = self.restrict(node.hi(), var, val);
self.node(node.var(), lonode, hinode)
} else {
if val {
self.restrict(node.hi(), var, val)
} else {
self.restrict(node.lo(), var, val)
}
}
}
fn if_then_else(&mut self, i: Term, t: Term, e: Term) -> Term {
if i == Term::TOP {
t
} else if i == Term::BOT {
e
} else if t == e {
t
} else if t == Term::TOP && e == Term::BOT {
i
} else {
let minvar = Var(min(
self.nodes[i.value()].var().value(),
min(
self.nodes[t.value()].var().value(),
self.nodes[e.value()].var().value(),
),
));
let itop = self.restrict(i, minvar, true);
let ttop = self.restrict(t, minvar, true);
let etop = self.restrict(e, minvar, true);
let ibot = self.restrict(i, minvar, false);
let tbot = self.restrict(t, minvar, false);
let ebot = self.restrict(e, minvar, false);
let top_ite = self.if_then_else(itop, ttop, etop);
let bot_ite = self.if_then_else(ibot, tbot, ebot);
self.node(minvar, bot_ite, top_ite)
}
}
fn node(&mut self, var: Var, lo: Term, hi: Term) -> Term {
if lo == hi {
lo
} else {
let node = BddNode::new(var, lo, hi);
match self.cache.get(&node) {
Some(t) => *t,
None => {
let new_term = Term(self.nodes.len());
self.nodes.push(node);
self.cache.insert(node, new_term);
new_term
}
}
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn newbdd() {
let bdd = Bdd::new();
assert_eq!(bdd.nodes.len(), 2);
}
#[test]
fn addconst() {
let bdd = Bdd::new();
assert_eq!(Bdd::constant(true), Term::TOP);
assert_eq!(Bdd::constant(false), Term::BOT);
assert_eq!(bdd.nodes.len(), 2);
}
#[test]
fn addvar() {
let mut bdd = Bdd::new();
assert_eq!(bdd.variable(Var(0)), Term(2));
assert_eq!(bdd.variable(Var(1)), Term(3));
assert_eq!(Var(1), Var(1));
bdd.variable(Var(0));
assert_eq!(bdd.variable(Var(0)), Term(2));
}
#[test]
fn use_negation() {
let mut bdd = Bdd::new();
let v1 = bdd.variable(Var(0));
assert_eq!(v1, 2.into());
assert_eq!(bdd.not(v1), Term(3));
}
#[test]
fn use_add() {
let mut bdd = Bdd::new();
let v1 = bdd.variable(Var(0));
let v2 = bdd.variable(Var(1));
let v3 = bdd.variable(Var(2));
let a1 = bdd.and(v1, v2);
let a2 = bdd.and(a1, v3);
assert_eq!(a2, Term(7));
}
#[test]
fn use_or() {
let mut bdd = Bdd::new();
let v1 = bdd.variable(Var(0));
let v2 = bdd.variable(Var(1));
let v3 = bdd.variable(Var(2));
let a1 = bdd.and(v1, v2);
let a2 = bdd.or(a1, v3);
assert_eq!(a2, Term(7));
}
#[test]
fn produce_different_conversions() {
let mut bdd = Bdd::new();
let v1 = bdd.variable(Var(0));
let v2 = bdd.variable(Var(1));
let t1 = bdd.and(v1, v2);
let nt1 = bdd.not(t1);
let ft = bdd.or(v1, nt1);
assert_eq!(ft, Term::TOP);
let v3 = bdd.variable(Var(2));
let nv3 = bdd.not(v3);
assert_eq!(bdd.and(v3, nv3), Term::BOT);
let conj = bdd.and(v1, v2);
assert_eq!(bdd.restrict(conj, Var(0), false), Term::BOT);
assert_eq!(bdd.restrict(conj, Var(0), true), v2);
let a = bdd.and(v3, v2);
let b = bdd.or(v2, v1);
let con1 = bdd.and(a, conj);
let end = bdd.or(con1, b);
let x = bdd.restrict(end, Var(1), false);
assert_eq!(x, Term(2));
}
}