Skip to content

Commit dbcbc6c

Browse files
revamp ac plugin and plugin propagation
1 parent b983524 commit dbcbc6c

File tree

14 files changed

+626
-211
lines changed

14 files changed

+626
-211
lines changed

src/ast/euf/euf_ac_plugin.cpp

Lines changed: 344 additions & 139 deletions
Large diffs are not rendered by default.

src/ast/euf/euf_ac_plugin.h

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -36,46 +36,28 @@ namespace euf {
3636

3737
class ac_plugin : public plugin {
3838

39+
struct stats {
40+
unsigned m_num_superpositions = 0;// number of superpositions
41+
};
42+
3943
// enode structure for AC equivalences
4044
struct node {
41-
enode* n; // associated enode
42-
node* root; // path compressed root
43-
node* next; // next in equivalence class
44-
justification j; // justification for equality
45-
node* target = nullptr; // justified next
45+
enode* n; // associated enode
4646
unsigned_vector shared; // shared occurrences
4747
unsigned_vector eqs; // equality occurrences
48+
bool is_zero = false;
4849

49-
unsigned id() const { return root->n->get_id(); }
50+
unsigned id() const { return n->get_id(); }
5051
static node* mk(region& r, enode* n);
5152
};
5253

53-
class equiv {
54-
node& n;
55-
public:
56-
class iterator {
57-
node* m_first;
58-
node* m_last;
59-
public:
60-
iterator(node* n, node* m) : m_first(n), m_last(m) {}
61-
node* operator*() { return m_first; }
62-
iterator& operator++() { if (!m_last) m_last = m_first; m_first = m_first->next; return *this; }
63-
iterator operator++(int) { iterator tmp = *this; ++*this; return tmp; }
64-
bool operator!=(iterator const& other) const { return m_last != other.m_last || m_first != other.m_first; }
65-
};
66-
equiv(node& _n) :n(_n) {}
67-
equiv(node* _n) :n(*_n) {}
68-
iterator begin() const { return iterator(&n, nullptr); }
69-
iterator end() const { return iterator(&n, &n); }
70-
};
71-
7254
struct bloom {
7355
uint64_t m_tick = 0;
7456
uint64_t m_filter = 0;
7557
};
7658

7759
enum eq_status {
78-
processed, to_simplify, is_dead
60+
processed, to_simplify, is_reducing_eq, is_dead
7961
};
8062

8163
// represent equalities added by merge_eh and by superposition
@@ -150,6 +132,10 @@ namespace euf {
150132
tracked_uint_set m_shared_todo;
151133
uint64_t m_tick = 1;
152134
symbol m_name;
135+
unsigned m_fuel = 0;
136+
unsigned m_fuel_inc = 3;
137+
stats m_stats;
138+
mutable symbol m_superposition_stats, m_eqs_stats;
153139

154140

155141

@@ -163,7 +149,6 @@ namespace euf {
163149
is_add_eq,
164150
is_add_monomial,
165151
is_add_node,
166-
is_merge_node,
167152
is_update_eq,
168153
is_add_shared_index,
169154
is_add_eq_index,
@@ -200,14 +185,35 @@ namespace euf {
200185
bool can_be_subset(monomial_t& subset, ptr_vector<node> const& m, bloom& b);
201186
bool are_equal(ptr_vector<node> const& a, ptr_vector<node> const& b);
202187
bool are_equal(monomial_t& a, monomial_t& b);
188+
bool are_equal(eq const& a, eq const& b) {
189+
return are_equal(monomial(a.l), monomial(b.l)) && are_equal(monomial(a.r), monomial(b.r));
190+
}
191+
bool well_formed(eq const& e) const;
192+
bool is_reducing(eq const& e) const;
193+
void forward_reduce(unsigned eq_id);
194+
void forward_reduce(eq const& src, unsigned dst);
195+
bool forward_reduce_monomial(eq const& eq, monomial_t& m);
196+
void backward_subsume_new_eqs();
197+
bool is_backward_subsumed(unsigned dst_eq);
203198
bool backward_subsumes(unsigned src_eq, unsigned dst_eq);
204199
bool forward_subsumes(unsigned src_eq, unsigned dst_eq);
205200

206-
void init_equation(eq const& e);
201+
enode_vector m_units;
202+
enode* get_unit(enode* n) const {
203+
for (auto u : m_units) {
204+
if (u->get_sort() == n->get_sort())
205+
return u;
206+
}
207+
UNREACHABLE();
208+
return nullptr;
209+
}
210+
211+
bool init_equation(eq const& e);
207212
bool orient_equation(eq& e);
208213
void set_status(unsigned eq_id, eq_status s);
209214
unsigned pick_next_eq();
210215

216+
unsigned_vector m_new_eqs;
211217
void forward_simplify(unsigned eq_id, unsigned using_eq);
212218
bool backward_simplify(unsigned eq_id, unsigned using_eq);
213219
bool superpose(unsigned src_eq, unsigned dst_eq);
@@ -249,6 +255,7 @@ namespace euf {
249255

250256
bool is_to_simplify(unsigned eq) const { return m_eqs[eq].status == eq_status::to_simplify; }
251257
bool is_processed(unsigned eq) const { return m_eqs[eq].status == eq_status::processed; }
258+
bool is_reducing(unsigned eq) const { return m_eqs[eq].status == eq_status::is_reducing_eq; }
252259
bool is_alive(unsigned eq) const { return m_eqs[eq].status != eq_status::is_dead; }
253260

254261
justification justify_rewrite(unsigned eq1, unsigned eq2);
@@ -279,6 +286,10 @@ namespace euf {
279286
ac_plugin(egraph& g, func_decl* f);
280287

281288
void set_injective() { m_is_injective = true; }
289+
290+
void add_unit(enode*);
291+
292+
void add_zero(enode*);
282293

283294
theory_id get_id() const override { return m_fid; }
284295

@@ -294,6 +305,8 @@ namespace euf {
294305

295306
std::ostream& display(std::ostream& out) const override;
296307

308+
void collect_statistics(statistics& st) const override;
309+
297310
void set_undo(std::function<void(void)> u) { m_undo_notify = u; }
298311

299312
struct eq_pp {

src/ast/euf/euf_arith_plugin.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,25 @@ namespace euf {
3131
std::function<void(void)> umul = [&]() { m_undo.push_back(undo_t::undo_mul); };
3232
m_mul.set_undo(umul);
3333
m_add.set_injective();
34+
auto e = a.mk_int(0);
35+
auto n = g.find(e) ? g.find(e) : g.mk(e, 0, 0, nullptr);
36+
m_add.add_unit(n);
37+
m_mul.add_zero(n);
38+
39+
e = a.mk_real(0);
40+
n = g.find(e) ? g.find(e) : g.mk(e, 0, 0, nullptr);
41+
m_add.add_unit(n);
42+
m_mul.add_zero(n);
43+
44+
e = a.mk_int(1);
45+
n = g.find(e) ? g.find(e) : g.mk(e, 0, 0, nullptr);
46+
m_mul.add_unit(n);
47+
48+
e = a.mk_real(1);
49+
n = g.find(e) ? g.find(e) : g.mk(e, 0, 0, nullptr);
50+
m_mul.add_unit(n);
51+
52+
3453
}
3554

3655
void arith_plugin::register_node(enode* n) {

src/ast/euf/euf_arith_plugin.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ namespace euf {
4646
void propagate() override;
4747

4848
std::ostream& display(std::ostream& out) const override;
49+
50+
void collect_statistics(statistics& st) const override {
51+
m_add.collect_statistics(st);
52+
m_mul.collect_statistics(st);
53+
}
4954

5055
};
5156
}

src/ast/euf/euf_egraph.cpp

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ namespace euf {
117117

118118
enode* egraph::mk(expr* f, unsigned generation, unsigned num_args, enode *const* args) {
119119
SASSERT(!find(f));
120+
TRACE(euf, tout << "mk: " << mk_bounded_pp(f, m) << " generation: " << generation << " num_args: " << num_args << "\n";);
120121
force_push();
121122
enode *n = mk_enode(f, generation, num_args, args);
122123

@@ -157,6 +158,21 @@ namespace euf {
157158
}
158159

159160
void egraph::propagate_plugins() {
161+
if (m_plugins.empty())
162+
return;
163+
if (m_plugin_qhead < m_new_th_eqs.size())
164+
m_updates.push_back(update_record(m_plugin_qhead, update_record::plugin_qhead()));
165+
166+
for (; m_plugin_qhead < m_new_th_eqs.size(); ++m_plugin_qhead) {
167+
auto const& eq = m_new_th_eqs[m_plugin_qhead];
168+
auto* p = get_plugin(eq.id());
169+
if (!p)
170+
continue;
171+
if (eq.is_eq())
172+
p->merge_eh(eq.child(), eq.root());
173+
else
174+
p->diseq_eh(eq.eq());
175+
}
160176
for (auto* p : m_plugins)
161177
if (p)
162178
p->propagate();
@@ -167,23 +183,18 @@ namespace euf {
167183
m_new_th_eqs.push_back(th_eq(id, v1, v2, c, r));
168184
m_updates.push_back(update_record(update_record::new_th_eq()));
169185
++m_stats.m_num_th_eqs;
170-
auto* p = get_plugin(id);
171-
if (p)
172-
p->merge_eh(c, r);
173186
}
174187

175188
void egraph::add_th_diseq(theory_id id, theory_var v1, theory_var v2, enode* eq) {
176189
if (!th_propagates_diseqs(id))
177190
return;
178191
TRACE(euf_verbose, tout << "eq: " << v1 << " != " << v2 << "\n";);
179-
m_new_th_eqs.push_back(th_eq(id, v1, v2, eq->get_expr()));
192+
m_new_th_eqs.push_back(th_eq(id, v1, v2, eq));
180193
m_updates.push_back(update_record(update_record::new_th_eq()));
181-
auto* p = get_plugin(id);
182-
if (p)
183-
p->diseq_eh(eq);
194+
184195
++m_stats.m_num_th_diseqs;
185196
}
186-
197+
187198
void egraph::add_literal(enode* n, enode* ante) {
188199
TRACE(euf, tout << "propagate " << bpp(n) << " " << bpp(ante) << "\n");
189200
if (!m_on_propagate_literal)
@@ -447,6 +458,9 @@ namespace euf {
447458
case update_record::tag_t::is_new_th_eq_qhead:
448459
m_new_th_eqs_qhead = p.qhead;
449460
break;
461+
case update_record::tag_t::is_plugin_qhead:
462+
m_plugin_qhead = p.qhead;
463+
break;
450464
case update_record::tag_t::is_inconsistent:
451465
m_inconsistent = p.m_inconsistent;
452466
break;
@@ -546,16 +560,18 @@ namespace euf {
546560
void egraph::remove_parents(enode* r) {
547561
TRACE(euf_verbose, tout << bpp(r) << "\n");
548562
SASSERT(all_of(enode_parents(r), [&](enode* p) { return !p->is_marked1(); }));
563+
TRACE(euf, tout << "remove_parents " << bpp(r) << "\n");
549564
for (enode* p : enode_parents(r)) {
550565
if (p->is_marked1())
551566
continue;
552567
if (p->cgc_enabled()) {
553568
if (!p->is_cgr())
554569
continue;
570+
TRACE(euf, tout << "removing " << m_table.contains_ptr(p) << " " << bpp(p) << "\n");
555571
SASSERT(m_table.contains_ptr(p));
556572
p->mark1();
557573
erase_from_table(p);
558-
CTRACE(euf_verbose, m_table.contains_ptr(p), tout << bpp(p) << "\n"; display(tout));
574+
CTRACE(euf, m_table.contains_ptr(p), tout << bpp(p) << "\n"; display(tout));
559575
SASSERT(!m_table.contains_ptr(p));
560576
}
561577
else if (p->is_equality())
@@ -564,15 +580,16 @@ namespace euf {
564580
}
565581

566582
void egraph::reinsert_parents(enode* r1, enode* r2) {
583+
TRACE(euf, tout << "reinsert_parents " << bpp(r1) << " " << bpp(r2) << "\n";);
567584
for (enode* p : enode_parents(r1)) {
568585
if (!p->is_marked1())
569586
continue;
570587
p->unmark1();
571-
TRACE(euf_verbose, tout << "reinsert " << bpp(r1) << " " << bpp(r2) << " " << bpp(p) << " " << p->cgc_enabled() << "\n";);
588+
TRACE(euf, tout << "reinsert " << bpp(r1) << " " << bpp(r2) << " " << bpp(p) << " " << p->cgc_enabled() << "\n";);
572589
if (p->cgc_enabled()) {
573590
auto [p_other, comm] = insert_table(p);
574591
SASSERT(m_table.contains_ptr(p) == (p_other == p));
575-
CTRACE(euf_verbose, p_other != p, tout << "reinsert " << bpp(p) << " == " << bpp(p_other) << " " << p->value() << " " << p_other->value() << "\n");
592+
CTRACE(euf, p_other != p, tout << "reinsert " << bpp(p) << " == " << bpp(p_other) << " " << p->value() << " " << p_other->value() << "\n");
576593
if (p_other != p)
577594
m_to_merge.push_back(to_merge(p_other, p, comm));
578595
else
@@ -957,6 +974,9 @@ namespace euf {
957974
st.update("euf propagations theory eqs", m_stats.m_num_th_eqs);
958975
st.update("euf propagations theory diseqs", m_stats.m_num_th_diseqs);
959976
st.update("euf propagations literal", m_stats.m_num_lits);
977+
for (auto p : m_plugins)
978+
if (p)
979+
p->collect_statistics(st);
960980
}
961981

962982
void egraph::copy_from(egraph const& src, std::function<void*(void*)>& copy_justification) {

src/ast/euf/euf_egraph.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ namespace euf {
5858
theory_var m_v2;
5959
union {
6060
enode* m_child;
61-
expr* m_eq;
61+
enode* m_eq;
6262
};
6363
enode* m_root;
6464
public:
@@ -68,10 +68,10 @@ namespace euf {
6868
theory_var v2() const { return m_v2; }
6969
enode* child() const { SASSERT(is_eq()); return m_child; }
7070
enode* root() const { SASSERT(is_eq()); return m_root; }
71-
expr* eq() const { SASSERT(!is_eq()); return m_eq; }
71+
enode* eq() const { SASSERT(!is_eq()); return m_eq; }
7272
th_eq(theory_id id, theory_var v1, theory_var v2, enode* c, enode* r) :
7373
m_id(id), m_v1(v1), m_v2(v2), m_child(c), m_root(r) {}
74-
th_eq(theory_id id, theory_var v1, theory_var v2, expr* eq) :
74+
th_eq(theory_id id, theory_var v1, theory_var v2, enode* eq) :
7575
m_id(id), m_v1(v1), m_v2(v2), m_eq(eq), m_root(nullptr) {}
7676
};
7777

@@ -116,6 +116,7 @@ namespace euf {
116116
struct replace_th_var {};
117117
struct new_th_eq {};
118118
struct new_th_eq_qhead {};
119+
struct plugin_qhead {};
119120
struct inconsistent {};
120121
struct value_assignment {};
121122
struct lbl_hash {};
@@ -125,7 +126,7 @@ namespace euf {
125126
struct plugin_undo {};
126127
enum class tag_t { is_set_parent, is_add_node, is_toggle_cgc, is_toggle_merge_tf, is_update_children,
127128
is_add_th_var, is_replace_th_var, is_new_th_eq,
128-
is_lbl_hash, is_new_th_eq_qhead,
129+
is_lbl_hash, is_new_th_eq_qhead, is_plugin_qhead,
129130
is_inconsistent, is_value_assignment, is_lbl_set, is_set_relevant,
130131
is_plugin_undo };
131132
tag_t tag;
@@ -158,6 +159,8 @@ namespace euf {
158159
tag(tag_t::is_new_th_eq), r1(nullptr), n1(nullptr), r2_num_parents(0) {}
159160
update_record(unsigned qh, new_th_eq_qhead):
160161
tag(tag_t::is_new_th_eq_qhead), r1(nullptr), n1(nullptr), qhead(qh) {}
162+
update_record(unsigned qh, plugin_qhead) :
163+
tag(tag_t::is_plugin_qhead), r1(nullptr), n1(nullptr), qhead(qh) {}
161164
update_record(bool inc, inconsistent) :
162165
tag(tag_t::is_inconsistent), r1(nullptr), n1(nullptr), m_inconsistent(inc) {}
163166
update_record(enode* n, value_assignment) :
@@ -196,6 +199,7 @@ namespace euf {
196199
enode *m_n2 = nullptr;
197200
justification m_justification;
198201
unsigned m_new_th_eqs_qhead = 0;
202+
unsigned m_plugin_qhead = 0;
199203
svector<th_eq> m_new_th_eqs;
200204
bool_vector m_th_propagates_diseqs;
201205
enode_vector m_todo;

src/ast/euf/euf_plugin.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ namespace euf {
3535
void plugin::push_merge(enode* a, enode* b) {
3636
if (a->get_root() == b->get_root())
3737
return; // already merged
38-
TRACE(plugin, tout << g.bpp(a) << " == " << g.bpp(b) << "\n");
38+
TRACE(plugin, tout << "push-merge " << g.bpp(a) << " == " << g.bpp(b) << "\n");
3939
g.push_merge(a, b, justification::axiom(get_id()));
4040
}
4141

src/ast/euf/euf_plugin.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Module Name:
1919

2020
#pragma once
2121

22+
#include "util/statistics.h"
2223
#include "ast/euf/euf_enode.h"
2324
#include "ast/euf/euf_justification.h"
2425

@@ -53,6 +54,8 @@ namespace euf {
5354
virtual void undo() = 0;
5455

5556
virtual std::ostream& display(std::ostream& out) const = 0;
57+
58+
virtual void collect_statistics(statistics& st) const {}
5659

5760
};
5861
}

0 commit comments

Comments
 (0)