3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-02 01:13:18 +00:00

add EUF plugin framework.

plugin setting allows adding equality saturation within the E-graph propagation without involving externalizing theory solver dispatch. It makes equality saturation independent of SAT integration.
Add a special relation operator to support ad-hoc AC symbols.
This commit is contained in:
Nikolaj Bjorner 2023-11-30 13:58:24 -08:00
parent 5784c2da79
commit b52fd8d954
28 changed files with 3063 additions and 68 deletions

View file

@ -29,8 +29,10 @@ Notes:
#include "util/statistics.h"
#include "util/trail.h"
#include "util/lbool.h"
#include "util/scoped_ptr_vector.h"
#include "ast/euf/euf_enode.h"
#include "ast/euf/euf_etable.h"
#include "ast/euf/euf_plugin.h"
#include "ast/ast_ll_pp.h"
#include <vector>
@ -82,14 +84,18 @@ namespace euf {
class egraph {
friend class plugin;
typedef ptr_vector<trail> trail_stack;
enum to_merge_t { to_merge_plain, to_merge_comm, to_add_literal };
enum to_merge_t { to_merge_plain, to_merge_comm, to_justified, to_add_literal };
struct to_merge {
enode* a, * b;
to_merge_t t;
justification j;
bool commutativity() const { return t == to_merge_comm; }
to_merge(enode* a, enode* b, bool c) : a(a), b(b), t(c ? to_merge_comm : to_merge_plain) {}
to_merge(enode* a, enode* b, justification j): a(a), b(b), t(to_justified), j(j) {}
to_merge(enode* p, enode* ante): a(p), b(ante), t(to_add_literal) {}
};
@ -116,10 +122,12 @@ namespace euf {
struct lbl_set {};
struct update_children {};
struct set_relevant {};
struct plugin_undo {};
enum class tag_t { is_set_parent, is_add_node, is_toggle_cgc, is_toggle_merge_tf, is_update_children,
is_add_th_var, is_replace_th_var, is_new_th_eq,
is_lbl_hash, is_new_th_eq_qhead,
is_inconsistent, is_value_assignment, is_lbl_set, is_set_relevant };
is_inconsistent, is_value_assignment, is_lbl_set, is_set_relevant,
is_plugin_undo };
tag_t tag;
enode* r1;
enode* n1;
@ -162,11 +170,14 @@ namespace euf {
tag(tag_t::is_update_children), r1(n), n1(nullptr), r2_num_parents(UINT_MAX) {}
update_record(enode* n, set_relevant) :
tag(tag_t::is_set_relevant), r1(n), n1(nullptr), r2_num_parents(UINT_MAX) {}
update_record(unsigned th_id, plugin_undo) :
tag(tag_t::is_plugin_undo), r1(nullptr), n1(nullptr), m_th_id(th_id) {}
};
ast_manager& m;
svector<to_merge> m_to_merge;
etable m_table;
region m_region;
scoped_ptr_vector<plugin> m_plugins;
svector<update_record> m_updates;
unsigned_vector m_scopes;
enode_vector m_expr2enode;
@ -205,6 +216,12 @@ namespace euf {
}
void push_node(enode* n) { m_updates.push_back(update_record(n)); }
// plugin related methods
void push_plugin_undo(unsigned th_id) { m_updates.push_back(update_record(th_id, update_record::plugin_undo())); }
void push_merge(enode* a, enode* b, justification j) { m_to_merge.push_back({ a, b, j }); }
void push_merge(enode* a, enode* b, bool comm) { m_to_merge.push_back({ a, b, comm }); }
void propagate_plugins();
void add_th_eq(theory_id id, theory_var v1, theory_var v2, enode* c, enode* r);
void add_th_diseqs(theory_id id, theory_var v1, enode* r);
@ -245,11 +262,15 @@ namespace euf {
public:
egraph(ast_manager& m);
~egraph();
void add_plugin(plugin* p);
plugin* get_plugin(family_id fid) const { return m_plugins.get(fid, nullptr); }
enode* find(expr* f) const { return m_expr2enode.get(f->get_id(), nullptr); }
enode* find(expr* f, unsigned n, enode* const* args);
enode* mk(expr* f, unsigned generation, unsigned n, enode *const* args);
enode_vector const& enodes_of(func_decl* f);
void push() { if (!m_to_merge.empty()) propagate(); ++m_num_scopes; }
void push() { if (can_propagate()) propagate(); ++m_num_scopes; }
void pop(unsigned num_scopes);
/**
@ -269,6 +290,7 @@ namespace euf {
of new equalities.
*/
bool propagate();
bool can_propagate() const { return !m_to_merge.empty(); }
bool inconsistent() const { return m_inconsistent; }
/**
@ -286,7 +308,7 @@ namespace euf {
where \c n is an enode and \c is_eq indicates whether the enode
is an equality consequence.
*/
void add_th_diseq(theory_id id, theory_var v1, theory_var v2, expr* eq);
void add_th_diseq(theory_id id, theory_var v1, theory_var v2, enode* eq);
bool has_th_eq() const { return m_new_th_eqs_qhead < m_new_th_eqs.size(); }
th_eq get_th_eq() const { return m_new_th_eqs[m_new_th_eqs_qhead]; }
void next_th_eq() { force_push(); SASSERT(m_new_th_eqs_qhead < m_new_th_eqs.size()); m_new_th_eqs_qhead++; }