Skip to content

Commit 955c80e

Browse files
committedJan 11, 2024
import updates from poly branch
Signed-off-by: Nikolaj Bjorner <[email protected]>
1 parent 2ca1187 commit 955c80e

8 files changed

+408
-217
lines changed
 

Diff for: ‎src/ast/arith_decl_plugin.h

+1
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ class arith_util : public arith_recognizers {
401401

402402
// return true if \c n is a term of the form (* -1 r)
403403
bool is_zero(expr const* n) const { rational val; return is_numeral(n, val) && val.is_zero(); }
404+
bool is_one(expr const* n) const{ rational val; return is_numeral(n, val) && val.is_one(); }
404405
bool is_minus_one(expr* n) const { rational tmp; return is_numeral(n, tmp) && tmp.is_minus_one(); }
405406
bool is_times_minus_one(expr* n, expr*& r) const {
406407
if (is_mul(n) && to_app(n)->get_num_args() == 2 && is_minus_one(to_app(n)->get_arg(0))) {

Diff for: ‎src/ast/euf/euf_bv_plugin.cpp

+111-51
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,15 @@ The formal properties of saturation have to be established.
6969
- Saturation does not complete with respect to associativity.
7070
Instead the claim is along the lines that the resulting E-graph can be used as a canonizer.
7171
If given a set of equations E that are saturated, and terms t1, t2 that are
72-
both simplified with respect to left-associativity of concatenation, and t1, t2 belong to the E-graph,
72+
both simplified with respect to left-associativity of concatentation, and t1, t2 belong to the E-graph,
7373
then t1 = t2 iff t1 ~ t2 in the E-graph.
7474
7575
TODO: Is saturation for (7) overkill for the purpose of canonization?
7676
77-
TODO: revisit re-entrancy during register_node. It can be called when creating internal extract terms.
78-
Instead of allowing re-entrancy we can accumulate nodes that are registered during recursive calls
79-
and have the main call perform recursive slicing.
80-
8177
--*/
8278

8379

80+
#include "ast/ast_pp.h"
8481
#include "ast/euf/euf_bv_plugin.h"
8582
#include "ast/euf/euf_egraph.h"
8683

@@ -91,19 +88,22 @@ namespace euf {
9188
bv(g.get_manager())
9289
{}
9390

94-
enode* bv_plugin::mk_value_concat(enode* a, enode* b) {
95-
auto v1 = get_value(a);
96-
auto v2 = get_value(b);
97-
auto v3 = v1 + v2 * power(rational(2), width(a));
98-
return mk_value(v3, width(a) + width(b));
91+
enode* bv_plugin::mk_value_concat(enode* hi, enode* lo) {
92+
auto v1 = get_value(hi);
93+
auto v2 = get_value(lo);
94+
auto v3 = v2 + v1 * rational::power_of_two(width(lo));
95+
return mk_value(v3, width(lo) + width(hi));
9996
}
10097

10198
enode* bv_plugin::mk_value(rational const& v, unsigned sz) {
10299
auto e = bv.mk_numeral(v, sz);
103-
return mk(e, 0, nullptr);
100+
auto n = mk(e, 0, nullptr);
101+
if (m_ensure_th_var)
102+
m_ensure_th_var(n);
103+
return n;
104104
}
105105

106-
void bv_plugin::merge_eh(enode* x, enode* y) {
106+
void bv_plugin::propagate_merge(enode* x, enode* y) {
107107
if (!bv.is_bv(x->get_expr()))
108108
return;
109109

@@ -128,7 +128,36 @@ namespace euf {
128128
propagate_extract(n);
129129
}
130130

131-
// enforce concat(v1, v2) = v2*2^|v1| + v1
131+
void bv_plugin::register_node(enode* n) {
132+
m_queue.push_back(n);
133+
m_trail.push_back(new (get_region()) push_back_vector(m_queue));
134+
push_plugin_undo(bv.get_family_id());
135+
}
136+
137+
void bv_plugin::merge_eh(enode* n1, enode* n2) {
138+
m_queue.push_back(enode_pair(n1, n2));
139+
m_trail.push_back(new (get_region()) push_back_vector(m_queue));
140+
push_plugin_undo(bv.get_family_id());
141+
}
142+
143+
void bv_plugin::propagate() {
144+
if (m_qhead == m_queue.size())
145+
return;
146+
m_trail.push_back(new (get_region()) value_trail(m_qhead));
147+
push_plugin_undo(bv.get_family_id());
148+
for (; m_qhead < m_queue.size(); ++m_qhead) {
149+
if (std::holds_alternative<enode*>(m_queue[m_qhead])) {
150+
auto n = *std::get_if<enode*>(&m_queue[m_qhead]);
151+
propagate_register_node(n);
152+
}
153+
else {
154+
auto [a, b] = *std::get_if<enode_pair>(&m_queue[m_qhead]);
155+
propagate_merge(a, b);
156+
}
157+
}
158+
}
159+
160+
// enforce concat(v1, v2) = v1*2^|v2| + v2
132161
void bv_plugin::propagate_values(enode* x) {
133162
if (!is_value(x))
134163
return;
@@ -142,9 +171,9 @@ namespace euf {
142171
if (is_concat(sib, a, b)) {
143172
if (!is_value(a) || !is_value(b)) {
144173
auto val = get_value(x);
145-
auto v1 = mod2k(val, width(a));
146-
auto v2 = machine_div2k(val, width(a));
147-
push_merge(mk_concat(mk_value(v1, width(a)), mk_value(v2, width(b))), x->get_interpreted());
174+
auto val_a = machine_div2k(val, width(b));
175+
auto val_b = mod2k(val, width(b));
176+
push_merge(mk_concat(mk_value(val_a, width(a)), mk_value(val_b, width(b))), x->get_interpreted());
148177
}
149178
}
150179
}
@@ -176,18 +205,18 @@ namespace euf {
176205
if (is_extract(p1, lo_, hi_) && lo_ == lo && hi_ == hi && p1->get_arg(0)->get_root() == arg_r)
177206
return;
178207
// add the axiom instead of merge(p, mk_extract(arg, lo, hi)), which would require tracking justifications
179-
push_merge(mk_concat(mk_extract(arg, lo, mid), mk_extract(arg, mid + 1, hi)), mk_extract(arg, lo, hi));
208+
push_merge(mk_concat(mk_extract(arg, mid + 1, hi), mk_extract(arg, lo, mid)), mk_extract(arg, lo, hi));
180209
};
181210

182-
auto propagate_left = [&](enode* b) {
183-
TRACE("bv", tout << "propagate-left " << g.bpp(b) << "\n");
211+
auto propagate_above = [&](enode* b) {
212+
TRACE("bv", tout << "propagate-above " << g.bpp(b) << "\n");
184213
for (enode* sib : enode_class(b))
185214
if (is_extract(sib, lo2, hi2) && sib->get_arg(0)->get_root() == arg_r && hi1 + 1 == lo2)
186215
ensure_concat(lo1, hi1, hi2);
187216
};
188217

189-
auto propagate_right = [&](enode* a) {
190-
TRACE("bv", tout << "propagate-right " << g.bpp(a) << "\n");
218+
auto propagate_below = [&](enode* a) {
219+
TRACE("bv", tout << "propagate-below " << g.bpp(a) << "\n");
191220
for (enode* sib : enode_class(a))
192221
if (is_extract(sib, lo2, hi2) && sib->get_arg(0)->get_root() == arg_r && hi2 + 1 == lo1)
193222
ensure_concat(lo2, hi2, hi1);
@@ -196,46 +225,65 @@ namespace euf {
196225
for (enode* p : enode_parents(n)) {
197226
if (is_concat(p, a, b)) {
198227
if (a->get_root() == n_r)
199-
propagate_left(b);
228+
propagate_below(b);
200229
if (b->get_root() == n_r)
201-
propagate_right(a);
230+
propagate_above(a);
202231
}
203232
}
204233
}
205234

206-
void bv_plugin::push_undo_split(enode* n) {
207-
m_undo_split.push_back(n);
235+
class bv_plugin::undo_split : public trail {
236+
bv_plugin& p;
237+
enode* n;
238+
public:
239+
undo_split(bv_plugin& p, enode* n): p(p), n(n) {}
240+
void undo() override {
241+
auto& i = p.info(n);
242+
i.value = nullptr;
243+
i.lo = nullptr;
244+
i.hi = nullptr;
245+
i.cut = null_cut;
246+
}
247+
};
248+
249+
void bv_plugin::push_undo_split(enode* n) {
250+
m_trail.push_back(new (get_region()) undo_split(*this, n));
208251
push_plugin_undo(bv.get_family_id());
209252
}
210253

211254
void bv_plugin::undo() {
212-
enode* n = m_undo_split.back();
213-
m_undo_split.pop_back();
214-
auto& i = info(n);
215-
i.lo = nullptr;
216-
i.hi = nullptr;
217-
i.cut = null_cut;
255+
m_trail.back()->undo();
256+
m_trail.pop_back();
218257
}
258+
219259

220-
void bv_plugin::register_node(enode* n) {
260+
void bv_plugin::propagate_register_node(enode* n) {
221261
TRACE("bv", tout << "register " << g.bpp(n) << "\n");
222-
auto& i = info(n);
223-
i.value = n;
224262
enode* a, * b;
263+
unsigned lo, hi;
225264
if (is_concat(n, a, b)) {
226-
i.lo = a;
227-
i.hi = b;
228-
i.cut = width(a);
265+
auto& i = info(n);
266+
i.value = n;
267+
i.hi = a;
268+
i.lo = b;
269+
i.cut = width(b);
229270
push_undo_split(n);
230271
}
231-
unsigned lo, hi;
232-
if (is_extract(n, lo, hi) && (lo != 0 || hi + 1 != width(n->get_arg(0)))) {
272+
else if (is_concat(n) && n->num_args() != 2) {
273+
SASSERT(n->num_args() != 0);
274+
auto last = n->get_arg(n->num_args() - 1);
275+
for (unsigned i = n->num_args() - 1; i-- > 0;)
276+
last = mk_concat(n->get_arg(i), last);
277+
push_merge(last, n);
278+
}
279+
else if (is_extract(n, lo, hi) && (lo != 0 || hi + 1 != width(n->get_arg(0)))) {
233280
enode* arg = n->get_arg(0);
234281
unsigned w = width(arg);
235282
if (all_of(enode_parents(arg), [&](enode* p) { unsigned _lo, _hi; return !is_extract(p, _lo, _hi) || _lo != 0 || _hi + 1 != w; }))
236283
push_merge(mk_extract(arg, 0, w - 1), arg);
237284
ensure_slice(arg, lo, hi);
238285
}
286+
TRACE("bv", tout << "done register " << g.bpp(n) << "\n");
239287
}
240288

241289
//
@@ -250,7 +298,8 @@ namespace euf {
250298
SASSERT(ub - lb + 1 == width(r));
251299
if (lb == lo && ub == hi)
252300
return;
253-
slice_info& i = info(r);
301+
slice_info const& i = info(r);
302+
254303
if (!i.lo) {
255304
if (lo > lb) {
256305
split(r, lo - lb);
@@ -287,19 +336,28 @@ namespace euf {
287336
hi += lo1;
288337
n = n->get_arg(0);
289338
}
339+
if (n->interpreted()) {
340+
auto v = get_value(n);
341+
if (lo > 0)
342+
v = div(v, rational::power_of_two(lo));
343+
if (hi + 1 != width(n))
344+
v = mod(v, rational::power_of_two(hi + 1));
345+
return mk_value(v, hi - lo + 1);
346+
}
290347
return mk(bv.mk_extract(hi, lo, n->get_expr()), 1, &n);
291348
}
292349

293-
enode* bv_plugin::mk_concat(enode* lo, enode* hi) {
294-
enode* args[2] = { lo, hi };
295-
return mk(bv.mk_concat(lo->get_expr(), hi->get_expr()), 2, args);
350+
enode* bv_plugin::mk_concat(enode* hi, enode* lo) {
351+
enode* args[2] = { hi, lo };
352+
return mk(bv.mk_concat(hi->get_expr(), lo->get_expr()), 2, args);
296353
}
297354

298355
void bv_plugin::merge(enode_vector& xs, enode_vector& ys, justification dep) {
299356
while (!xs.empty()) {
300357
SASSERT(!ys.empty());
301358
auto x = xs.back();
302359
auto y = ys.back();
360+
TRACE("bv", tout << "merge " << g.bpp(x) << " " << g.bpp(y) << "\n");
303361
if (unfold_sub(x, xs))
304362
continue;
305363
else if (unfold_sub(y, ys))
@@ -342,14 +400,13 @@ namespace euf {
342400
SASSERT(0 < cut && cut < w);
343401
enode* hi = mk_extract(n, cut, w - 1);
344402
enode* lo = mk_extract(n, 0, cut - 1);
345-
auto& i = info(n);
346-
if (!i.value)
347-
i.value = n;
403+
auto& i = info(n);
404+
i.value = n;
348405
i.hi = hi;
349406
i.lo = lo;
350407
i.cut = cut;
351408
push_undo_split(n);
352-
push_merge(mk_concat(lo, hi), n);
409+
push_merge(mk_concat(hi, lo), n);
353410
}
354411

355412
void bv_plugin::sub_slices(enode* n, std::function<bool(enode*, unsigned)>& consumer) {
@@ -442,9 +499,12 @@ namespace euf {
442499
continue;
443500
offsets.push_back(offs);
444501
if (n->get_root() == b->get_root() && offs == offset) {
502+
if (n != b)
503+
consumer(n, b);
445504
while (j != UINT_MAX) {
446505
auto [x, y, j2] = just[j];
447-
consumer(x, y);
506+
if (x != y)
507+
consumer(x, y);
448508
j = j2;
449509
}
450510
for (auto const& [n, offset, j] : m_jtodo) {
@@ -487,10 +547,10 @@ namespace euf {
487547
}
488548

489549
std::ostream& bv_plugin::display(std::ostream& out) const {
490-
out << "bv\n";
550+
out << "bv\n";
491551
for (auto const& i : m_info)
492-
if (i.lo)
493-
out << g.bpp(i.value) << " cut " << i.cut << " lo " << g.bpp(i.lo) << " hi " << g.bpp(i.hi) << "\n";
552+
if (i.lo)
553+
out << g.bpp(i.value) << " cut " << i.cut << " lo " << g.bpp(i.lo) << " hi " << g.bpp(i.hi) << "\n";
494554
return out;
495555
}
496556
}

Diff for: ‎src/ast/euf/euf_bv_plugin.h

+18-9
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Module Name:
1919

2020
#pragma once
2121

22+
#include "util/trail.h"
2223
#include "ast/bv_decl_plugin.h"
2324
#include "ast/euf/euf_plugin.h"
2425

@@ -40,26 +41,24 @@ namespace euf {
4041

4142
bv_util bv;
4243
slice_info_vector m_info; // indexed by enode::get_id()
43-
44-
45-
4644
enode_vector m_xs, m_ys;
4745

46+
std::function<void(enode*)> m_ensure_th_var;
47+
4848
bool is_concat(enode* n) const { return bv.is_concat(n->get_expr()); }
49-
bool is_concat(enode* n, enode*& a, enode*& b) { return is_concat(n) && (a = n->get_arg(0), b = n->get_arg(1), true); }
49+
bool is_concat(enode* n, enode*& a, enode*& b) { return is_concat(n) && n->num_args() == 2 && (a = n->get_arg(0), b = n->get_arg(1), true); }
5050
bool is_extract(enode* n, unsigned& lo, unsigned& hi) { expr* body; return bv.is_extract(n->get_expr(), lo, hi, body); }
5151
bool is_extract(enode* n) const { return bv.is_extract(n->get_expr()); }
5252
unsigned width(enode* n) const { return bv.get_bv_size(n->get_expr()); }
5353

5454
enode* mk_extract(enode* n, unsigned lo, unsigned hi);
55-
enode* mk_concat(enode* lo, enode* hi);
56-
enode* mk_value_concat(enode* lo, enode* hi);
55+
enode* mk_concat(enode* hi, enode* lo);
56+
enode* mk_value_concat(enode* hi, enode* lo);
5757
enode* mk_value(rational const& v, unsigned sz);
5858
unsigned width(enode* n) { return bv.get_bv_size(n->get_expr()); }
5959
bool is_value(enode* n) { return n->get_root()->interpreted(); }
6060
rational get_value(enode* n) { rational val; VERIFY(bv.is_numeral(n->get_interpreted()->get_expr(), val)); return val; }
6161
slice_info& info(enode* n) { unsigned id = n->get_id(); m_info.reserve(id + 1); return m_info[id]; }
62-
slice_info& root_info(enode* n) { unsigned id = n->get_root_id(); m_info.reserve(id + 1); return m_info[id]; }
6362
bool has_sub(enode* n) { return !!info(n).lo; }
6463
enode* sub_lo(enode* n) { return info(n).lo; }
6564
enode* sub_hi(enode* n) { return info(n).hi; }
@@ -81,8 +80,16 @@ namespace euf {
8180
svector<std::tuple<enode*, unsigned, unsigned>> m_jtodo;
8281
void clear_offsets();
8382

84-
enode_vector m_undo_split;
83+
84+
ptr_vector<trail> m_trail;
85+
86+
class undo_split;
8587
void push_undo_split(enode* n);
88+
89+
vector<std::variant<enode*, enode_pair>> m_queue;
90+
unsigned m_qhead = 0;
91+
void propagate_register_node(enode* n);
92+
void propagate_merge(enode* a, enode* b);
8693

8794
public:
8895
bv_plugin(egraph& g);
@@ -97,9 +104,11 @@ namespace euf {
97104

98105
void diseq_eh(enode* eq) override {}
99106

100-
void propagate() override {}
107+
void propagate() override;
101108

102109
void undo() override;
110+
111+
void set_ensure_th_var(std::function<void(enode*)>& f) { m_ensure_th_var = f; }
103112

104113
std::ostream& display(std::ostream& out) const override;
105114

0 commit comments

Comments
 (0)
Please sign in to comment.