mirror of
https://github.com/Z3Prover/z3
synced 2025-04-15 21:38:44 +00:00
adding bdd package
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
d7b6373601
commit
09fdfcc963
|
@ -24,15 +24,16 @@ namespace sat {
|
|||
bdd_manager::bdd_manager(unsigned num_vars, unsigned cache_size) {
|
||||
for (BDD a = 0; a < 2; ++a) {
|
||||
for (BDD b = 0; b < 2; ++b) {
|
||||
for (unsigned op = bdd_and_op; op < bdd_no_op; ++op) {
|
||||
for (unsigned op = bdd_and_op; op < bdd_not_op; ++op) {
|
||||
unsigned index = a + 2*b + 4*op;
|
||||
m_apply_const.reserve(index+1);
|
||||
m_apply_const[index] = apply_const(a, b, static_cast<bdd_op>(op));
|
||||
}
|
||||
}
|
||||
}
|
||||
// add two dummy nodes for true_bdd and false_bdd
|
||||
for (unsigned i = 0; i <= bdd_no_op; ++i) {
|
||||
|
||||
// add dummy nodes for operations, and true, false bdds.
|
||||
for (unsigned i = 0; i <= bdd_no_op + 2; ++i) {
|
||||
m_nodes.push_back(bdd_node(0,0,0));
|
||||
m_nodes.back().m_refcount = max_rc;
|
||||
m_nodes.back().m_index = m_nodes.size()-1;
|
||||
|
@ -41,7 +42,7 @@ namespace sat {
|
|||
m_spare_entry = nullptr;
|
||||
m_max_num_bdd_nodes = 1 << 24; // up to 16M nodes
|
||||
m_mark_level = 0;
|
||||
alloc_free_nodes(1024);
|
||||
alloc_free_nodes(1024 + num_vars);
|
||||
|
||||
// add variables
|
||||
for (unsigned i = 0; i < num_vars; ++i) {
|
||||
|
@ -91,6 +92,20 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
|
||||
bool bdd_manager::check_result(op_entry*& e1, op_entry const* e2, BDD a, BDD b, BDD c) {
|
||||
if (e1 != e2) {
|
||||
if (e2->m_bdd1 == a && e2->m_bdd2 == b && e2->m_op == c) {
|
||||
push_entry(e1);
|
||||
return true;
|
||||
}
|
||||
e1 = const_cast<op_entry*>(e2);
|
||||
}
|
||||
e1->m_bdd1 = a;
|
||||
e1->m_bdd2 = b;
|
||||
e1->m_op = c;
|
||||
return false;
|
||||
}
|
||||
|
||||
bdd_manager::BDD bdd_manager::apply_rec(BDD a, BDD b, bdd_op op) {
|
||||
switch (op) {
|
||||
case bdd_and_op:
|
||||
|
@ -119,15 +134,8 @@ namespace sat {
|
|||
}
|
||||
op_entry * e1 = pop_entry(a, b, op);
|
||||
op_entry const* e2 = m_op_cache.insert_if_not_there(e1);
|
||||
if (e2 != e1) {
|
||||
if (e2->m_bdd1 == a && e2->m_bdd2 == b && e2->m_op == op) {
|
||||
push_entry(e1);
|
||||
return e2->m_result;
|
||||
}
|
||||
e1 = const_cast<op_entry*>(e2);
|
||||
e1->m_bdd1 = a;
|
||||
e1->m_bdd2 = b;
|
||||
e1->m_op = op;
|
||||
if (check_result(e1, e2, a, b, op)) {
|
||||
return e2->m_result;
|
||||
}
|
||||
BDD r;
|
||||
if (level(a) == level(b)) {
|
||||
|
@ -221,7 +229,7 @@ namespace sat {
|
|||
}
|
||||
|
||||
bdd bdd_manager::mk_var(unsigned i) {
|
||||
return bdd(m_var2bdd[2*i+1], this);
|
||||
return bdd(m_var2bdd[2*i], this);
|
||||
}
|
||||
|
||||
bdd bdd_manager::mk_nvar(unsigned i) {
|
||||
|
@ -247,16 +255,8 @@ namespace sat {
|
|||
if (is_false(b)) return true_bdd;
|
||||
op_entry* e1 = pop_entry(b, b, bdd_not_op);
|
||||
op_entry const* e2 = m_op_cache.insert_if_not_there(e1);
|
||||
if (e2 != e1) {
|
||||
if (e2->m_bdd1 == b && e2->m_bdd2 == b && e2->m_op == bdd_not_op) {
|
||||
push_entry(e1);
|
||||
return e2->m_result;
|
||||
}
|
||||
e1 = const_cast<op_entry*>(e2);
|
||||
e1->m_bdd1 = b;
|
||||
e1->m_bdd2 = b;
|
||||
e1->m_op = bdd_not_op;
|
||||
}
|
||||
if (check_result(e1, e2, b, b, bdd_not_op))
|
||||
return e2->m_result;
|
||||
push(mk_not_rec(lo(b)));
|
||||
push(mk_not_rec(hi(b)));
|
||||
BDD r = make_node(level(b), read(2), read(1));
|
||||
|
@ -264,8 +264,8 @@ namespace sat {
|
|||
e1->m_result = r;
|
||||
return r;
|
||||
}
|
||||
|
||||
bdd bdd_manager::mk_ite(bdd const& c, bdd const& t, bdd const& e) {
|
||||
|
||||
bdd bdd_manager::mk_ite(bdd const& c, bdd const& t, bdd const& e) {
|
||||
bool first = true;
|
||||
while (true) {
|
||||
try {
|
||||
|
@ -290,16 +290,8 @@ namespace sat {
|
|||
SASSERT(!is_const(a) && !is_const(b) && !is_const(c));
|
||||
op_entry * e1 = pop_entry(a, b, c);
|
||||
op_entry const* e2 = m_op_cache.insert_if_not_there(e1);
|
||||
if (e2 != e1) {
|
||||
if (e2->m_bdd1 == a && e2->m_bdd2 == b && e2->m_op == c) {
|
||||
push_entry(e1);
|
||||
return e2->m_result;
|
||||
}
|
||||
e1 = const_cast<op_entry*>(e2);
|
||||
e1->m_bdd1 = a;
|
||||
e1->m_bdd2 = b;
|
||||
e1->m_op = c;
|
||||
}
|
||||
if (check_result(e1, e2, a, b, c))
|
||||
return e2->m_result;
|
||||
unsigned la = level(a), lb = level(b), lc = level(c);
|
||||
BDD r;
|
||||
BDD a1, b1, c1, a2, b2, c2;
|
||||
|
@ -363,16 +355,8 @@ namespace sat {
|
|||
bdd_op q_op = op == bdd_and_op ? bdd_and_proj_op : bdd_or_proj_op;
|
||||
op_entry * e1 = pop_entry(a, b, q_op);
|
||||
op_entry const* e2 = m_op_cache.insert_if_not_there(e1);
|
||||
if (e1 != e2) {
|
||||
if (e2->m_bdd1 == a && e2->m_bdd2 == b && e2->m_op == q_op) {
|
||||
push_entry(e1);
|
||||
return e2->m_result;
|
||||
}
|
||||
e1 = const_cast<op_entry*>(e2);
|
||||
e1->m_bdd1 = a;
|
||||
e1->m_bdd2 = b;
|
||||
e1->m_op = q_op;
|
||||
}
|
||||
if (check_result(e1, e2, a, b, q_op))
|
||||
return e2->m_result;
|
||||
push(mk_quant_rec(l, lo(b), op));
|
||||
push(mk_quant_rec(l, hi(b), op));
|
||||
BDD r = make_node(lvl, read(2), read(1));
|
||||
|
@ -382,11 +366,11 @@ namespace sat {
|
|||
}
|
||||
}
|
||||
|
||||
double bdd_manager::path_count(bdd const& b) {
|
||||
double bdd_manager::count(bdd const& b, unsigned z) {
|
||||
init_mark();
|
||||
m_path_count.resize(m_nodes.size());
|
||||
m_path_count[0] = 0;
|
||||
m_path_count[1] = 1;
|
||||
m_count.resize(m_nodes.size());
|
||||
m_count[0] = z;
|
||||
m_count[1] = 1-z;
|
||||
set_mark(0);
|
||||
set_mark(1);
|
||||
m_todo.push_back(b.root);
|
||||
|
@ -402,13 +386,12 @@ namespace sat {
|
|||
m_todo.push_back(hi(r));
|
||||
}
|
||||
else {
|
||||
m_path_count[r] = m_path_count[lo(r)] + m_path_count[hi(r)];
|
||||
m_count[r] = m_count[lo(r)] + m_count[hi(r)];
|
||||
set_mark(r);
|
||||
m_todo.pop_back();
|
||||
}
|
||||
}
|
||||
return m_path_count[b.root];
|
||||
|
||||
return m_count[b.root];
|
||||
}
|
||||
|
||||
void bdd_manager::alloc_free_nodes(unsigned n) {
|
||||
|
@ -472,6 +455,7 @@ namespace sat {
|
|||
++m_mark_level;
|
||||
if (m_mark_level == 0) {
|
||||
m_mark.fill(0);
|
||||
++m_mark_level;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -514,15 +498,15 @@ namespace sat {
|
|||
bdd::bdd(int root, bdd_manager* m): root(root), m(m) { m->inc_ref(root); }
|
||||
bdd::bdd(bdd & other): root(other.root), m(other.m) { m->inc_ref(root); }
|
||||
bdd::~bdd() { m->dec_ref(root); }
|
||||
bdd bdd::lo() const { return bdd(m->lo(root), m); }
|
||||
bdd bdd::hi() const { return bdd(m->hi(root), m); }
|
||||
unsigned bdd::var() const { return m->var(root); }
|
||||
bool bdd::is_true() const { return root == bdd_manager::true_bdd; }
|
||||
bool bdd::is_false() const { return root == bdd_manager::false_bdd; }
|
||||
bdd bdd::operator!() { return m->mk_not(*this); }
|
||||
bdd bdd::operator&&(bdd const& other) { return m->mk_and(*this, other); }
|
||||
bdd bdd::operator||(bdd const& other) { return m->mk_or(*this, other); }
|
||||
std::ostream& bdd::display(std::ostream& out) const { return m->display(out, *this); }
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, bdd const& b) {
|
||||
return b.display(out);
|
||||
}
|
||||
|
||||
|
||||
std::ostream& bdd::display(std::ostream& out) const { return m->display(out, *this); }
|
||||
std::ostream& operator<<(std::ostream& out, bdd const& b) { return b.display(out); }
|
||||
|
||||
}
|
||||
|
|
|
@ -25,13 +25,6 @@ Revision History:
|
|||
|
||||
namespace sat {
|
||||
|
||||
struct bdd_pair {
|
||||
int* m_bdd;
|
||||
int m_last;
|
||||
int m_id;
|
||||
bdd_pair* m_next;
|
||||
};
|
||||
|
||||
class bdd_manager;
|
||||
|
||||
class bdd {
|
||||
|
@ -42,6 +35,12 @@ namespace sat {
|
|||
public:
|
||||
bdd(bdd & other);
|
||||
~bdd();
|
||||
bdd lo() const;
|
||||
bdd hi() const;
|
||||
unsigned var() const;
|
||||
bool is_true() const;
|
||||
bool is_false() const;
|
||||
|
||||
bdd operator!();
|
||||
bdd operator&&(bdd const& other);
|
||||
bdd operator||(bdd const& other);
|
||||
|
@ -123,22 +122,21 @@ namespace sat {
|
|||
|
||||
typedef ptr_hashtable<op_entry, hash_entry, eq_entry> op_table;
|
||||
|
||||
svector<bdd_node> m_nodes;
|
||||
op_table m_op_cache;
|
||||
node_table m_node_table;
|
||||
unsigned_vector m_apply_const;
|
||||
svector<BDD> m_bdd_stack;
|
||||
op_entry* m_spare_entry;
|
||||
svector<BDD> m_var2bdd;
|
||||
unsigned_vector m_var2level, m_level2var;
|
||||
unsigned_vector m_free_nodes;
|
||||
small_object_allocator m_alloc;
|
||||
svector<bdd_node> m_nodes;
|
||||
op_table m_op_cache;
|
||||
node_table m_node_table;
|
||||
unsigned_vector m_apply_const;
|
||||
svector<BDD> m_bdd_stack;
|
||||
op_entry* m_spare_entry;
|
||||
svector<BDD> m_var2bdd;
|
||||
unsigned_vector m_var2level, m_level2var;
|
||||
unsigned_vector m_free_nodes;
|
||||
small_object_allocator m_alloc;
|
||||
mutable svector<unsigned> m_mark;
|
||||
mutable unsigned m_mark_level;
|
||||
mutable svector<double> m_path_count;
|
||||
mutable svector<double> m_count;
|
||||
mutable svector<BDD> m_todo;
|
||||
|
||||
unsigned m_max_num_bdd_nodes;
|
||||
unsigned m_max_num_bdd_nodes;
|
||||
|
||||
BDD make_node(unsigned level, BDD l, BDD r);
|
||||
|
||||
|
@ -157,7 +155,10 @@ namespace sat {
|
|||
|
||||
op_entry* pop_entry(BDD l, BDD r, BDD op);
|
||||
void push_entry(op_entry* e);
|
||||
bool check_result(op_entry*& e1, op_entry const* e2, BDD a, BDD b, BDD c);
|
||||
|
||||
double count(bdd const& b, unsigned z);
|
||||
|
||||
void gc();
|
||||
void alloc_free_nodes(unsigned n);
|
||||
void init_mark();
|
||||
|
@ -197,7 +198,8 @@ namespace sat {
|
|||
bdd mk_iff(bdd const& a, bdd const& b) { return bdd(apply(a.root, b.root, bdd_iff_op), this); }
|
||||
bdd mk_ite(bdd const& c, bdd const& t, bdd const& e);
|
||||
|
||||
double path_count(bdd const& b);
|
||||
double dnf_size(bdd const& b) { return count(b, 0); }
|
||||
double cnf_size(bdd const& b) { return count(b, 1); }
|
||||
|
||||
std::ostream& display(std::ostream& out, bdd const& b);
|
||||
std::ostream& display(std::ostream& out);
|
||||
|
|
|
@ -10,12 +10,13 @@ namespace sat {
|
|||
bdd c2 = v2 && v0 && v1;
|
||||
std::cout << c1 << "\n";
|
||||
SASSERT(c1 == c2);
|
||||
std::cout << "cnf size: " << m.cnf_size(c1) << "\n";
|
||||
|
||||
c1 = v0 || v1 || v2;
|
||||
c2 = v2 || v1 || v0;
|
||||
std::cout << c1 << "\n";
|
||||
std::cout << c2 << "\n";
|
||||
SASSERT(c1 == c2);
|
||||
std::cout << "cnf size: " << m.cnf_size(c1) << "\n";
|
||||
}
|
||||
|
||||
static void test2() {
|
||||
|
|
Loading…
Reference in a new issue