1
0
mirror of https://github.com/ellmau/adf-obdd.git synced 2026-02-03 17:09:04 +01:00

Refactor bdd to use rc refcell

This commit is contained in:
Stefan Ellmauthaler 2022-06-01 13:07:56 +02:00
parent 78949b18e5
commit be68af7d05
Failed to extract signature
4 changed files with 113 additions and 122 deletions

17
Cargo.lock generated
View File

@ -19,26 +19,11 @@ dependencies = [
"test-log", "test-log",
] ]
[[package]]
name = "adf_bdd"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e781519ea5434514f014476c02ccee777b28e600ad58fadca195715acb194c69"
dependencies = [
"biodivine-lib-bdd",
"derivative",
"lexical-sort",
"log",
"nom",
"serde",
"serde_json",
]
[[package]] [[package]]
name = "adf_bdd-solver" name = "adf_bdd-solver"
version = "0.2.4" version = "0.2.4"
dependencies = [ dependencies = [
"adf_bdd 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "adf_bdd",
"assert_cmd", "assert_cmd",
"assert_fs", "assert_fs",
"clap", "clap",

View File

@ -14,7 +14,7 @@ name = "adf-bdd"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
adf_bdd = { version="0.2.4", default-features = false } adf_bdd = { version="0.2.4", path="../lib", default-features = false }
clap = {version = "3.1.14", features = [ "derive", "cargo", "env" ]} clap = {version = "3.1.14", features = [ "derive", "cargo", "env" ]}
log = { version = "0.4", features = [ "max_level_trace", "release_max_level_info" ] } log = { version = "0.4", features = [ "max_level_trace", "release_max_level_info" ] }
serde = { version = "1.0", features = ["derive","rc"] } serde = { version = "1.0", features = ["derive","rc"] }

View File

@ -946,7 +946,7 @@ mod test {
"s(a). s(b). s(c). s(d). ac(a,c(v)). ac(b,b). ac(c,and(a,b)). ac(d,neg(b)).", "s(a). s(b). s(c). s(d). ac(a,c(v)). ac(b,b). ac(c,and(a,b)). ac(d,neg(b)).",
) )
.unwrap(); .unwrap();
let mut adf = Adf::from_parser(&parser); let adf = Adf::from_parser(&parser);
let mut v = adf.ac.clone(); let mut v = adf.ac.clone();
let mut fcs = adf.facet_count(&v); let mut fcs = adf.facet_count(&v);

View File

@ -4,6 +4,7 @@ pub mod vectorize;
use crate::datatypes::*; use crate::datatypes::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashSet; use std::collections::HashSet;
use std::rc::Rc;
use std::{cell::RefCell, cmp::min, collections::HashMap, fmt::Display}; use std::{cell::RefCell, cmp::min, collections::HashMap, fmt::Display};
/// Contains the data of (possibly) multiple roBDDs, managed over one collection of nodes. /// Contains the data of (possibly) multiple roBDDs, managed over one collection of nodes.
@ -11,20 +12,21 @@ use std::{cell::RefCell, cmp::min, collections::HashMap, fmt::Display};
/// Each roBDD is identified by its corresponding [`Term`], which implicitly identifies the root node of a roBDD. /// Each roBDD is identified by its corresponding [`Term`], which implicitly identifies the root node of a roBDD.
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct Bdd { pub struct Bdd {
pub(crate) nodes: Vec<BddNode>, nodes: Rc<RefCell<Vec<BddNode>>>,
#[cfg(feature = "variablelist")] #[cfg(feature = "variablelist")]
#[serde(skip)] #[serde(skip)]
var_deps: Vec<HashSet<Var>>, var_deps: Rc<RefCell<Vec<HashSet<Var>>>>,
#[serde(with = "vectorize")] //#[serde(with = "vectorize")]
cache: HashMap<BddNode, Term>, #[serde(skip)]
cache: Rc<RefCell<HashMap<BddNode, Term>>>,
#[serde(skip, default = "Bdd::default_count_cache")] #[serde(skip, default = "Bdd::default_count_cache")]
count_cache: RefCell<HashMap<Term, CountNode>>, count_cache: Rc<RefCell<HashMap<Term, CountNode>>>,
} }
impl Display for Bdd { impl Display for Bdd {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, " ")?; writeln!(f, " ")?;
for (idx, elem) in self.nodes.iter().enumerate() { for (idx, elem) in self.nodes.borrow().iter().enumerate() {
writeln!(f, "{} {}", idx, *elem)?; writeln!(f, "{} {}", idx, *elem)?;
} }
Ok(()) Ok(())
@ -47,18 +49,18 @@ impl Bdd {
nodes: vec![BddNode::bot_node(), BddNode::top_node()], nodes: vec![BddNode::bot_node(), BddNode::top_node()],
#[cfg(feature = "variablelist")] #[cfg(feature = "variablelist")]
var_deps: vec![HashSet::new(), HashSet::new()], var_deps: vec![HashSet::new(), HashSet::new()],
cache: HashMap::new(), cache: Rc::new(RefCell::new(HashMap::new())),
count_cache: RefCell::new(HashMap::new()), count_cache: RefCell::new(HashMap::new()),
} }
} }
#[cfg(feature = "adhoccounting")] #[cfg(feature = "adhoccounting")]
{ {
let result = Self { let result = Self {
nodes: vec![BddNode::bot_node(), BddNode::top_node()], nodes: Rc::new(RefCell::new(vec![BddNode::bot_node(), BddNode::top_node()])),
#[cfg(feature = "variablelist")] #[cfg(feature = "variablelist")]
var_deps: vec![HashSet::new(), HashSet::new()], var_deps: Rc::new(RefCell::new(vec![HashSet::new(), HashSet::new()])),
cache: HashMap::new(), cache: Rc::new(RefCell::new(HashMap::new())),
count_cache: RefCell::new(HashMap::new()), count_cache: Rc::new(RefCell::new(HashMap::new())),
}; };
result result
.count_cache .count_cache
@ -72,8 +74,8 @@ impl Bdd {
} }
} }
fn default_count_cache() -> RefCell<HashMap<Term, CountNode>> { fn default_count_cache() -> Rc<RefCell<HashMap<Term, CountNode>>> {
RefCell::new(HashMap::new()) Rc::new(RefCell::new(HashMap::new()))
} }
/// Instantiates a [variable][crate::datatypes::Var] and returns the representing roBDD as a [`Term`][crate::datatypes::Term]. /// Instantiates a [variable][crate::datatypes::Var] and returns the representing roBDD as a [`Term`][crate::datatypes::Term].
@ -134,7 +136,7 @@ impl Bdd {
positive: &[Var], positive: &[Var],
) -> Vec<(Vec<Var>, Vec<Var>)> { ) -> Vec<(Vec<Var>, Vec<Var>)> {
let mut result = Vec::new(); let mut result = Vec::new();
let node = self.nodes[tree.value()]; let node = self.nodes.borrow()[tree.value()];
let var = node.var(); let var = node.var();
if tree.is_truth_value() { if tree.is_truth_value() {
return Vec::new(); return Vec::new();
@ -175,11 +177,11 @@ impl Bdd {
} }
/// Restrict the value of a given [variable][crate::datatypes::Var] to **val**. /// Restrict the value of a given [variable][crate::datatypes::Var] to **val**.
pub fn restrict(&mut self, tree: Term, var: Var, val: bool) -> Term { pub fn restrict(&self, tree: Term, var: Var, val: bool) -> Term {
let node = self.nodes[tree.0]; let node = self.nodes.borrow()[tree.0];
#[cfg(feature = "variablelist")] #[cfg(feature = "variablelist")]
{ {
if !self.var_deps[tree.value()].contains(&var) { if !self.var_deps.borrow()[tree.value()].contains(&var) {
return tree; return tree;
} }
} }
@ -201,7 +203,7 @@ impl Bdd {
} }
/// Creates an roBDD, based on the relation of three roBDDs, which are in an `if-then-else` relation. /// Creates an roBDD, based on the relation of three roBDDs, which are in an `if-then-else` relation.
fn if_then_else(&mut self, i: Term, t: Term, e: Term) -> Term { fn if_then_else(&self, i: Term, t: Term, e: Term) -> Term {
if i == Term::TOP { if i == Term::TOP {
t t
} else if i == Term::BOT { } else if i == Term::BOT {
@ -212,10 +214,10 @@ impl Bdd {
i i
} else { } else {
let minvar = Var(min( let minvar = Var(min(
self.nodes[i.value()].var().value(), self.nodes.borrow()[i.value()].var().value(),
min( min(
self.nodes[t.value()].var().value(), self.nodes.borrow()[t.value()].var().value(),
self.nodes[e.value()].var().value(), self.nodes.borrow()[e.value()].var().value(),
), ),
)); ));
let itop = self.restrict(i, minvar, true); let itop = self.restrict(i, minvar, true);
@ -233,25 +235,25 @@ impl Bdd {
/// Creates a new node in the roBDD. /// Creates a new node in the roBDD.
/// It will not create duplicate nodes and uses already existing nodes, if applicable. /// It will not create duplicate nodes and uses already existing nodes, if applicable.
pub fn node(&mut self, var: Var, lo: Term, hi: Term) -> Term { pub fn node(&self, var: Var, lo: Term, hi: Term) -> Term {
if lo == hi { if lo == hi {
lo lo
} else { } else {
let node = BddNode::new(var, lo, hi); let node = BddNode::new(var, lo, hi);
match self.cache.get(&node) { if let Some(t) = self.cache.borrow().get(&node) {
Some(t) => *t, return *t;
None => { }
let new_term = Term(self.nodes.len()); let new_term = Term(self.nodes.borrow().len());
self.nodes.push(node); self.nodes.borrow_mut().push(node);
self.cache.insert(node, new_term); self.cache.borrow_mut().insert(node, new_term);
#[cfg(feature = "variablelist")] #[cfg(feature = "variablelist")]
{ {
let mut var_set: HashSet<Var> = self.var_deps[lo.value()] let mut var_set: HashSet<Var> = self.var_deps.borrow()[lo.value()]
.union(&self.var_deps[hi.value()]) .union(&self.var_deps.borrow()[hi.value()])
.copied() .copied()
.collect(); .collect();
var_set.insert(var); var_set.insert(var);
self.var_deps.push(var_set); self.var_deps.borrow_mut().push(var_set);
} }
log::debug!("newterm: {} as {:?}", new_term, node); log::debug!("newterm: {} as {:?}", new_term, node);
#[cfg(feature = "adhoccounting")] #[cfg(feature = "adhoccounting")]
@ -303,8 +305,6 @@ impl Bdd {
new_term new_term
} }
} }
}
}
/// Computes the number of counter-models and models for a given roBDD. /// Computes the number of counter-models and models for a given roBDD.
/// ///
@ -369,7 +369,7 @@ impl Bdd {
} else if term == Term::BOT { } else if term == Term::BOT {
(ModelCounts::bot(), ModelCounts::bot(), 0) (ModelCounts::bot(), ModelCounts::bot(), 0)
} else { } else {
let node = &self.nodes[term.0]; let node = &self.nodes.borrow()[term.0];
let mut lo_exp = 0u32; let mut lo_exp = 0u32;
let mut hi_exp = 0u32; let mut hi_exp = 0u32;
let (lo_counts, lo_paths, lodepth) = self.modelcount_naive(node.lo()); let (lo_counts, lo_paths, lodepth) = self.modelcount_naive(node.lo());
@ -405,7 +405,7 @@ impl Bdd {
return *result; return *result;
} }
let result = { let result = {
let node = &self.nodes[term.0]; let node = &self.nodes.borrow()[term.0];
let mut lo_exp = 0u32; let mut lo_exp = 0u32;
let mut hi_exp = 0u32; let mut hi_exp = 0u32;
let (lo_counts, lo_paths, lodepth) = self.modelcount_memoization(node.lo()); let (lo_counts, lo_paths, lodepth) = self.modelcount_memoization(node.lo());
@ -437,7 +437,7 @@ impl Bdd {
} }
/// Repairs the internal structures after an import. /// Repairs the internal structures after an import.
pub fn fix_import(&mut self) { pub fn fix_import(&self) {
self.generate_var_dependencies(); self.generate_var_dependencies();
#[cfg(feature = "adhoccounting")] #[cfg(feature = "adhoccounting")]
{ {
@ -447,25 +447,25 @@ impl Bdd {
self.count_cache self.count_cache
.borrow_mut() .borrow_mut()
.insert(Term::BOT, (ModelCounts::bot(), ModelCounts::bot(), 0)); .insert(Term::BOT, (ModelCounts::bot(), ModelCounts::bot(), 0));
for i in 0..self.nodes.len() { for i in 0..self.nodes.borrow().len() {
log::debug!("fixing Term({})", i); log::debug!("fixing Term({})", i);
self.modelcount_memoization(Term(i)); self.modelcount_memoization(Term(i));
} }
} }
} }
fn generate_var_dependencies(&mut self) { fn generate_var_dependencies(&self) {
#[cfg(feature = "variablelist")] #[cfg(feature = "variablelist")]
self.nodes.iter().for_each(|node| { self.nodes.borrow().iter().for_each(|node| {
if node.var() >= Var::BOT { if node.var() >= Var::BOT {
self.var_deps.push(HashSet::new()); self.var_deps.borrow_mut().push(HashSet::new());
} else { } else {
let mut var_set: HashSet<Var> = self.var_deps[node.lo().value()] let mut var_set: HashSet<Var> = self.var_deps.borrow()[node.lo().value()]
.union(&self.var_deps[node.hi().value()]) .union(&self.var_deps.borrow()[node.hi().value()])
.copied() .copied()
.collect(); .collect();
var_set.insert(node.var()); var_set.insert(node.var());
self.var_deps.push(var_set); self.var_deps.borrow_mut().push(var_set);
} }
}); });
} }
@ -474,7 +474,7 @@ impl Bdd {
pub fn var_dependencies(&self, tree: Term) -> HashSet<Var> { pub fn var_dependencies(&self, tree: Term) -> HashSet<Var> {
#[cfg(feature = "variablelist")] #[cfg(feature = "variablelist")]
{ {
self.var_deps[tree.value()].clone() self.var_deps.borrow()[tree.value()].clone()
} }
#[cfg(not(feature = "variablelist"))] #[cfg(not(feature = "variablelist"))]
{ {
@ -525,7 +525,7 @@ mod test {
#[test] #[test]
fn newbdd() { fn newbdd() {
let bdd = Bdd::new(); let bdd = Bdd::new();
assert_eq!(bdd.nodes.len(), 2); assert_eq!(bdd.nodes.borrow().len(), 2);
} }
#[test] #[test]
@ -534,7 +534,7 @@ mod test {
assert_eq!(Bdd::constant(true), Term::TOP); assert_eq!(Bdd::constant(true), Term::TOP);
assert_eq!(Bdd::constant(false), Term::BOT); assert_eq!(Bdd::constant(false), Term::BOT);
assert_eq!(bdd.nodes.len(), 2); assert_eq!(bdd.nodes.borrow().len(), 2);
} }
#[test] #[test]
@ -643,10 +643,15 @@ mod test {
let formula4 = bdd.and(v3, formula2); let formula4 = bdd.and(v3, formula2);
assert_eq!(bdd.models(v1, false), (1, 1).into()); assert_eq!(bdd.models(v1, false), (1, 1).into());
let mut x = bdd.count_cache.get_mut().iter().collect::<Vec<_>>(); let mut x = bdd
.count_cache
.borrow_mut()
.iter()
.map(|(x, y)| (*x, *y))
.collect::<Vec<_>>();
x.sort(); x.sort();
log::debug!("{:?}", formula1); log::debug!("{:?}", formula1);
for x in bdd.nodes.iter().enumerate() { for x in bdd.nodes.borrow().iter().enumerate() {
log::debug!("{:?}", x); log::debug!("{:?}", x);
} }
log::debug!("{:?}", x); log::debug!("{:?}", x);
@ -757,14 +762,15 @@ mod test {
bdd.not(formula4); bdd.not(formula4);
let constructed = bdd.var_deps.clone(); let constructed = bdd.var_deps.clone();
bdd.var_deps = Vec::new(); bdd.var_deps = Rc::new(RefCell::new(Vec::new()));
bdd.generate_var_dependencies(); bdd.generate_var_dependencies();
constructed constructed
.borrow()
.iter() .iter()
.zip(bdd.var_deps.iter()) .zip(bdd.var_deps.borrow().iter())
.for_each(|(left, right)| { .for_each(|(left, right)| {
assert!(left == right); assert!(*left == *right);
}); });
assert_eq!( assert_eq!(