3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-06 14:13:23 +00:00

initial working version

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2018-06-09 20:58:41 -07:00 committed by Arie Gurfinkel
parent da18f0e0b7
commit 008f003aa0
3 changed files with 438 additions and 404 deletions

View file

@ -503,4 +503,5 @@ void install_dbg_cmds(cmd_context & ctx) {
ctx.insert(alloc(set_next_id)); ctx.insert(alloc(set_next_id));
ctx.insert(alloc(mbp_cmd)); ctx.insert(alloc(mbp_cmd));
ctx.insert(alloc(mbi_cmd)); ctx.insert(alloc(mbi_cmd));
ctx.insert(alloc(euf_project_cmd));
} }

View file

@ -89,20 +89,17 @@ public:
// Congruence table hash function is based on // Congruence table hash function is based on
// roots of children and function declaration. // roots of children and function declaration.
struct cg_hash { unsigned get_hash() const {
unsigned operator()(term const* t) const {
unsigned a, b, c; unsigned a, b, c;
a = b = c = t->get_decl_id(); a = b = c = get_decl_id();
for (term * ch : children(t)) { for (term * ch : children(this)) {
a = ch->get_root().get_id(); a = ch->get_root().get_id();
mix(a, b, c); mix(a, b, c);
} }
return c; return c;
} }
};
struct cg_eq { static bool cg_eq(term const * t1, term const * t2) {
bool operator()(term * t1, term * t2) const {
if (t1->get_decl_id() != t2->get_decl_id()) return false; if (t1->get_decl_id() != t2->get_decl_id()) return false;
if (t1->m_children.size() != t2->m_children.size()) return false; if (t1->m_children.size() != t2->m_children.size()) return false;
for (unsigned i = 0, sz = t1->m_children.size(); i < sz; ++ i) { for (unsigned i = 0, sz = t1->m_children.size(); i < sz; ++ i) {
@ -110,7 +107,6 @@ public:
} }
return true; return true;
} }
};
unsigned get_id() const { return m_app->get_id();} unsigned get_id() const { return m_app->get_id();}
@ -130,6 +126,7 @@ public:
bool is_root() const {return m_root == this;} bool is_root() const {return m_root == this;}
void set_root(term &r) {m_root = &r;} void set_root(term &r) {m_root = &r;}
term &get_next() const {return *m_next;} term &get_next() const {return *m_next;}
void add_parent(term* p) { m_parents.push_back(p); }
unsigned get_class_size() const {return m_class_size;} unsigned get_class_size() const {return m_class_size;}
@ -304,6 +301,10 @@ public:
} }
}; };
unsigned term_graph::term_hash::operator()(term const* t) const { return t->get_hash(); }
bool term_graph::term_eq::operator()(term const* a, term const* b) const { return term::cg_eq(a, b); }
term_graph::term_graph(ast_manager &man) : m(man), m_lits(m), m_pinned(m) { term_graph::term_graph(ast_manager &man) : m(man), m_lits(m), m_pinned(m) {
m_plugins.register_plugin (alloc(arith_term_graph_plugin, *this)); m_plugins.register_plugin (alloc(arith_term_graph_plugin, *this));
} }
@ -366,13 +367,12 @@ term *term_graph::mk_term(expr *a) {
} }
term* term_graph::internalize_term(expr *t) { term* term_graph::internalize_term(expr *t) {
term* res = get_term(t); term* res = get_term(t);
if (res) return res; if (res) return res;
ptr_buffer<expr> todo; ptr_buffer<expr> todo;
todo.push_back(t); todo.push_back(t);
while (!todo.empty()) { while (!todo.empty()) {
term* res = get_term(t); res = get_term(t);
if (res) { if (res) {
todo.pop_back(); todo.pop_back();
continue; continue;
@ -388,11 +388,15 @@ term* term_graph::internalize_term(expr *t) {
todo.pop_back(); todo.pop_back();
res = mk_term(t); res = mk_term(t);
} }
SASSERT(res);
return res; return res;
} }
void term_graph::internalize_eq(expr *a1, expr* a2) { void term_graph::internalize_eq(expr *a1, expr* a2) {
SASSERT(m_merge.empty());
merge(internalize_term(a1)->get_root(), internalize_term(a2)->get_root()); merge(internalize_term(a1)->get_root(), internalize_term(a2)->get_root());
merge_flush();
SASSERT(m_merge.empty());
} }
void term_graph::internalize_lit(expr* lit) { void term_graph::internalize_lit(expr* lit) {
@ -405,7 +409,20 @@ void term_graph::internalize_lit(expr* lit) {
} }
} }
void term_graph::merge_flush() {
while (!m_merge.empty()) {
term* t1 = m_merge.back().first;
term* t2 = m_merge.back().second;
m_merge.pop_back();
merge(*t1, *t2);
}
}
void term_graph::merge(term &t1, term &t2) { void term_graph::merge(term &t1, term &t2) {
// -- merge might invalidate term2map cache
m_term2app.reset();
m_pinned.reset();
SASSERT(t1.is_root()); SASSERT(t1.is_root());
SASSERT(t2.is_root()); SASSERT(t2.is_root());
@ -417,24 +434,34 @@ void term_graph::merge (term &t1, term &t2) {
std::swap(a, b); std::swap(a, b);
} }
// Remove parents of it from the cg table.
for (term* p : term::parents(b)) {
if (!p->is_marked()) {
p->set_mark(true);
m_cg_table.erase(p);
}
}
// make 'a' be the root of the equivalence class of 'b' // make 'a' be the root of the equivalence class of 'b'
b->set_root(*a); b->set_root(*a);
for (term *it = &b->get_next(); it != b; it = &it->get_next()) { for (term *it = &b->get_next(); it != b; it = &it->get_next()) {
// TBD: remove parents of it from the cg table.
it->set_root(*a); it->set_root(*a);
} }
// merge equivalence classes // merge equivalence classes
a->merge_eq_class(*b); a->merge_eq_class(*b);
// TBD: insert parents of b's old equilvalence class into the cg table // Insert parents of b's old equilvalence class into the cg table
// and propagate equalities. for (term* p : term::parents(a)) {
if (p->is_marked()) {
// -- merge might have invalidated term2map cache term* p_old = m_cg_table.insert_if_not_there(p);
p->set_mark(false);
// NSB: ??? what is ownership model of pinned in m_terms? a->add_parent(p);
m_term2app.reset(); // propagate new equalities.
m_pinned.reset(); if (p->get_root().get_id() != p_old->get_root().get_id()) {
m_merge.push_back(std::make_pair(p, p_old));
}
}
}
} }
expr* term_graph::mk_app_core (expr *e) { expr* term_graph::mk_app_core (expr *e) {
@ -598,6 +625,7 @@ void term_graph::reset() {
std::for_each(m_terms.begin(), m_terms.end(), delete_proc<term>()); std::for_each(m_terms.begin(), m_terms.end(), delete_proc<term>());
m_terms.reset(); m_terms.reset();
m_lits.reset(); m_lits.reset();
m_cg_table.reset();
} }
expr_ref term_graph::mk_pure(term& t) { expr_ref term_graph::mk_pure(term& t) {
@ -631,7 +659,7 @@ expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool excl
if (t->get_root().is_marked()) continue; if (t->get_root().is_marked()) continue;
// if exclude = true, but t in decls, then skip // if exclude = true, but t in decls, then skip
// if exclude = false, but t not in decls, then skip // if exclude = false, but t not in decls, then skip
if (exclude != _decls.contains(t->get_decl_id())) { if (exclude == _decls.contains(t->get_decl_id())) {
continue; continue;
} }
// //
@ -662,7 +690,7 @@ expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool excl
// walk each root. Then traverse each term in the equivalence class // walk each root. Then traverse each term in the equivalence class
// create pure variant of the terms (if possible) // create pure variant of the terms (if possible)
// equate t0 (that comes from the root, which can be purified) // equate t0 (that comes from the root, which can be purified)
// with any other t1. // with any other purifiable t1.
expr_ref_vector result(m); expr_ref_vector result(m);
m_term2app.reset(); m_term2app.reset();
m_pinned.reset(); m_pinned.reset();
@ -675,7 +703,7 @@ expr_ref_vector term_graph::project(func_decl_ref_vector const& decls, bool excl
roots.insert(t0); roots.insert(t0);
for (term* r = &t->get_next(); r != t; r = &r->get_next()) { for (term* r = &t->get_next(); r != t; r = &r->get_next()) {
// main symbol of term must be consistent with what is included/excluded // main symbol of term must be consistent with what is included/excluded
if (exclude != _decls.contains(r->get_decl_id())) { if (exclude == _decls.contains(r->get_decl_id())) {
continue; continue;
} }
expr_ref t1 = mk_pure(*r); expr_ref t1 = mk_pure(*r);

View file

@ -38,17 +38,22 @@ namespace qe {
virtual app_ref process_lit (app *lit) = 0; virtual app_ref process_lit (app *lit) = 0;
}; };
class term_graph { class term_graph {
struct term_hash { unsigned operator()(term const* t) const; };
struct term_eq { bool operator()(term const* a, term const* b) const; };
ast_manager & m; ast_manager & m;
ptr_vector<term> m_terms; ptr_vector<term> m_terms;
app_ref_vector m_lits; // NSB: expr_ref_vector? app_ref_vector m_lits; // NSB: expr_ref_vector?
u_map<term* > m_app2term; u_map<term* > m_app2term;
ast_ref_vector m_pinned; ast_ref_vector m_pinned;
u_map<expr*> m_term2app; u_map<expr*> m_term2app;
plugin_manager<term_graph_plugin> m_plugins; plugin_manager<term_graph_plugin> m_plugins;
ptr_hashtable<term, term_hash, term_eq> m_cg_table;
vector<std::pair<term*,term*>> m_merge;
void merge(term &t1, term &t2); void merge(term &t1, term &t2);
void merge_flush();
term *mk_term(expr *t); term *mk_term(expr *t);
term *get_term(expr *t); term *get_term(expr *t);