3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-26 21:16:02 +00:00

bv and gc of literals (#4692)

* bv and gc of literals

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* overload

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* diseq

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* diseq

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2020-09-17 14:24:07 -07:00 committed by GitHub
parent 2d52367368
commit 549753845e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 1480 additions and 854 deletions

View file

@ -84,6 +84,7 @@ namespace array {
}
sat::check_result solver::check() {
force_push();
// flet<bool> _is_redundant(m_is_redundant, true);
bool turn[2] = { false, false };
turn[s().rand()(2)] = true;
@ -96,14 +97,8 @@ namespace array {
return sat::check_result::CR_DONE;
}
void solver::push() {
th_euf_solver::lazy_push();
}
void solver::pop(unsigned n) {
n = lazy_pop(n);
if (n == 0)
return;
void solver::pop_core(unsigned n) {
th_euf_solver::pop_core(n);
m_var_data.resize(get_num_vars());
}
@ -111,9 +106,9 @@ namespace array {
for (unsigned i = 0; i < get_num_vars(); ++i) {
auto& d = get_var_data(i);
out << var2enode(i)->get_expr_id() << " " << mk_bounded_pp(var2expr(i), m, 2) << "\n";
display_info(out, "parent beta", d.m_parent_lambdas);
display_info(out, "parent lambdas", d.m_parent_lambdas);
display_info(out, "parent select", d.m_parent_selects);
display_info(out, "beta ", d.m_lambdas);
display_info(out, "b ", d.m_lambdas);
}
return out;
}
@ -159,12 +154,14 @@ namespace array {
}
void solver::new_eq_eh(euf::th_eq const& eq) {
m_find.merge(eq.m_v1, eq.m_v2);
force_push();
m_find.merge(eq.v1(), eq.v2());
}
bool solver::unit_propagate() {
if (m_qhead == m_axiom_trail.size())
return false;
force_push();
bool prop = false;
ctx.push(value_trail<euf::solver, unsigned>(m_qhead));
for (; m_qhead < m_axiom_trail.size() && !s().inconsistent(); ++m_qhead)

View file

@ -175,6 +175,8 @@ namespace array {
var_data& get_var_data(euf::enode* n) { return get_var_data(n->get_th_var(get_id())); }
var_data& get_var_data(theory_var v) { return *m_var_data[v]; }
var_data const& get_var_data(theory_var v) const { return *m_var_data[v]; }
void pop_core(unsigned n) override;
// models
bool have_different_model_values(theory_var v1, theory_var v2);
@ -191,8 +193,7 @@ namespace array {
void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector& r, bool probing) override {}
void asserted(literal l) override {}
sat::check_result check() override;
void push() override;
void pop(unsigned n) override;
std::ostream& display(std::ostream& out) const override;
std::ostream& display_justification(std::ostream& out, sat::ext_justification_idx idx) const override;
std::ostream& display_constraint(std::ostream& out, sat::ext_constraint_idx idx) const override;

View file

@ -55,6 +55,25 @@ namespace bv {
}
}
void ackerman::used_diseq_eh(euf::theory_var v1, euf::theory_var v2) {
if (v1 == v2)
return;
if (v1 > v2)
std::swap(v1, v2);
vv* n = m_tmp_vv;
n->v1 = v1;
n->v2 = v2;
vv* other = m_table.insert_if_not_there(n);
other->m_count++;
if (other->m_count > m_propagate_high_watermark || other->m_glue == 0)
s.s().set_should_simplify();
vv::push_to_front(m_queue, other);
if (other == n) {
new_tmp();
gc();
}
}
void ackerman::update_glue(vv& v) {
unsigned sz = s.m_bits[v.v1].size();
m_diff_levels.reserve(s.s().scope_lvl() + 1, false);

View file

@ -72,6 +72,8 @@ namespace bv {
void used_eq_eh(euf::theory_var v1, euf::theory_var v2);
void used_diseq_eh(euf::theory_var v1, euf::theory_var v2);
void propagate();
};

View file

@ -62,15 +62,17 @@ namespace bv {
m_zero_one_bits.push_back(zero_one_bits());
ctx.attach_th_var(n, this, r);
TRACE("bv", tout << "mk-var: " << r << " " << n->get_expr_id() << " " << mk_pp(n->get_expr(), m) << "\n";);
TRACE("bv", tout << "mk-var: " << r << " " << n->get_expr_id() << " " << mk_bounded_pp(n->get_expr(), m) << "\n";);
return r;
}
void solver::apply_sort_cnstr(euf::enode * n, sort * s) {
force_push();
get_var(n);
}
sat::literal solver::internalize(expr* e, bool sign, bool root, bool redundant) {
force_push();
SASSERT(m.is_bool(e));
if (!visit_rec(m, e, sign, root, redundant))
return sat::null_literal;
@ -81,6 +83,7 @@ namespace bv {
}
void solver::internalize(expr* e, bool redundant) {
force_push();
visit_rec(m, e, false, false, redundant);
}
@ -337,7 +340,7 @@ namespace bv {
for (expr* b : k_bits)
args.push_back(m.mk_ite(b, m_autil.mk_int(power2(i++)), zero));
expr_ref sum(m_autil.mk_add(sz, args.c_ptr()), m);
expr_ref eq(m.mk_eq(n, sum), m);
expr_ref eq = mk_eq(n, sum);
sat::literal lit = ctx.internalize(eq, false, false, m_is_redundant);
add_unit(lit);
}
@ -367,7 +370,7 @@ namespace bv {
unsigned sz = bv.get_bv_size(n);
numeral mod = power(numeral(2), sz);
rhs = m_autil.mk_mod(e, m_autil.mk_int(mod));
expr_ref eq(m.mk_eq(lhs, rhs), m);
expr_ref eq = mk_eq(lhs, rhs);
TRACE("bv", tout << eq << "\n";);
add_unit(ctx.internalize(eq, false, false, m_is_redundant));
@ -378,9 +381,9 @@ namespace bv {
numeral div = power2(i);
rhs = m_autil.mk_idiv(e, m_autil.mk_int(div));
rhs = m_autil.mk_mod(rhs, m_autil.mk_int(2));
rhs = m.mk_eq(rhs, m_autil.mk_int(1));
rhs = mk_eq(rhs, m_autil.mk_int(1));
lhs = n_bits.get(i);
expr_ref eq(m.mk_eq(lhs, rhs), m);
expr_ref eq = mk_eq(lhs, rhs);
TRACE("bv", tout << eq << "\n";);
add_unit(ctx.internalize(eq, false, false, m_is_redundant));
}
@ -403,10 +406,10 @@ namespace bv {
void solver::internalize_carry(app* n) {
SASSERT(n->get_num_args() == 3);
literal r = ctx.get_literal(n);
literal l1 = ctx.get_literal(n->get_arg(0));
literal l2 = ctx.get_literal(n->get_arg(1));
literal l3 = ctx.get_literal(n->get_arg(2));
literal r = expr2literal(n);
literal l1 = expr2literal(n->get_arg(0));
literal l2 = expr2literal(n->get_arg(1));
literal l3 = expr2literal(n->get_arg(2));
add_clause(~r, l1, l2);
add_clause(~r, l1, l3);
add_clause(~r, l2, l3);
@ -417,7 +420,7 @@ namespace bv {
void solver::internalize_xor3(app* n) {
SASSERT(n->get_num_args() == 3);
literal r = ctx.get_literal(n);
literal r = expr2literal(n);
literal l1 = expr2literal(n->get_arg(0));
literal l2 = expr2literal(n->get_arg(1));
literal l3 = expr2literal(n->get_arg(2));
@ -483,7 +486,7 @@ namespace bv {
expr_ref out(m);
fn(arg1_bits.size(), arg1_bits.c_ptr(), arg2_bits.c_ptr(), out);
sat::literal def = ctx.internalize(out, false, false, m_is_redundant);
add_def(def, ctx.get_literal(n));
add_def(def, expr2literal(n));
}
void solver::add_def(sat::literal def, sat::literal l) {
@ -568,14 +571,18 @@ namespace bv {
}
void solver::assert_ackerman(theory_var v1, theory_var v2) {
flet<bool> _red(m_is_redundant, true);
if (v1 == v2)
return;
if (v1 > v2)
std::swap(v1, v2);
flet<bool> _red(m_is_redundant, true);
++m_stats.m_ackerman;
expr* o1 = var2expr(v1);
expr* o2 = var2expr(v2);
expr_ref oe(m.mk_eq(o1, o2), m);
expr_ref oe = mk_var_eq(v1, v2);
literal oeq = ctx.internalize(oe, false, false, m_is_redundant);
unsigned sz = get_bv_size(v1);
TRACE("bv", tout << oe << "\n";);
unsigned sz = m_bits[v1].size();
TRACE("bv", tout << "ackerman-eq: " << s().scope_lvl() << " " << oe << "\n";);
literal_vector eqs;
for (unsigned i = 0; i < sz; ++i) {
literal l1 = m_bits[v1][i];
@ -583,7 +590,7 @@ namespace bv {
expr_ref e1(m), e2(m);
e1 = bv.mk_bit2bool(o1, i);
e2 = bv.mk_bit2bool(o2, i);
expr_ref e(m.mk_eq(e1, e2), m);
expr_ref e = mk_eq(e1, e2);
literal eq = ctx.internalize(e, false, false, m_is_redundant);
add_clause(l1, ~l2, ~eq);
add_clause(~l1, l2, ~eq);

View file

@ -37,15 +37,14 @@ namespace bv {
};
class solver::bit_occs_trail : public trail<euf::solver> {
solver& s;
bit_atom& a;
var_pos_occ* m_occs;
public:
bit_occs_trail(solver& s, bit_atom& a):s(s), a(a), m_occs(a.m_occs) {}
bit_occs_trail(solver& s, bit_atom& a): a(a), m_occs(a.m_occs) {}
virtual void undo(euf::solver& euf) {
std::cout << "add back occurrences " << & a << "\n";
IF_VERBOSE(1, verbose_stream() << "add back occurrences " << & a << "\n");
a.m_occs = m_occs;
}
};
@ -57,6 +56,7 @@ namespace bv {
m_ackerman(*this),
m_bb(m, get_config()),
m_find(*this) {
ctx.get_egraph().set_th_propagates_diseqs(id);
}
void solver::fixed_var_eh(theory_var v1) {
@ -194,9 +194,37 @@ namespace bv {
}
void solver::new_eq_eh(euf::th_eq const& eq) {
TRACE("bv", tout << "new eq " << eq.m_v1 << " == " << eq.m_v2 << "\n";);
if (is_bv(eq.m_v1))
m_find.merge(eq.m_v1, eq.m_v2);
force_push();
TRACE("bv", tout << "new eq " << eq.v1() << " == " << eq.v2() << "\n";);
if (is_bv(eq.v1()))
m_find.merge(eq.v1(), eq.v2());
}
void solver::new_diseq_eh(euf::th_eq const& ne) {
theory_var v1 = ne.v1(), v2 = ne.v2();
if (!is_bv(v1))
return;
if (!get_config().m_bv_eq_axioms)
return;
TRACE("bv", tout << "diff: " << v1 << " != " << v2 << "\n";);
unsigned sz = m_bits[v1].size();
for (unsigned i = 0; i < sz; ++i) {
sat::literal a = m_bits[v1][i];
sat::literal b = m_bits[v2][i];
if (a == ~b)
return;
auto va = s().value(a);
auto vb = s().value(b);
if (va != l_undef && vb != l_undef && va != vb)
return;
}
if (s().at_search_lvl()) {
force_push();
assert_ackerman(v1, v2);
}
else
m_ackerman.used_diseq_eh(v1, v2);
}
double solver::get_reward(literal l, sat::ext_constraint_idx idx, sat::literal_occs_fun& occs) const { return 0; }
@ -209,6 +237,7 @@ namespace bv {
TRACE("bv", display_constraint(tout, idx););
switch (c.m_kind) {
case bv_justification::kind_t::bv2bit:
SASSERT(s().value(c.m_antecedent) == l_true);
r.push_back(c.m_antecedent);
ctx.add_antecedent(var2enode(c.m_v1), var2enode(c.m_v2));
break;
@ -235,9 +264,16 @@ namespace bv {
}
void solver::log_drat(bv_justification const& c) {
// this has a side-effect so changes provability:
expr_ref eq(m.mk_eq(var2expr(c.m_v1), var2expr(c.m_v2)), m);
sat::literal leq = ctx.internalize(eq, false, false, false);
// introduce dummy literal for equality.
sat::literal leq(s().num_vars() + 1, false);
expr* e1 = var2expr(c.m_v1);
expr* e2 = var2expr(c.m_v2);
expr_ref eq(m.mk_eq(e1, e2), m);
ctx.get_drat().def_begin('e', eq->get_id(), std::string("="));
ctx.get_drat().def_add_arg(e1->get_id());
ctx.get_drat().def_add_arg(e2->get_id());
ctx.get_drat().def_end();
ctx.get_drat().bool_def(leq.var(), eq->get_id());
sat::literal_vector lits;
auto add_bit = [&](sat::literal lit) {
if (s().value(lit) == l_true)
@ -263,19 +299,24 @@ namespace bv {
break;
}
ctx.get_drat().add(lits, status());
ctx.get_drat().log_gc_var(leq.var());
}
void solver::asserted(literal l) {
atom* a = get_bv2a(l.var());
TRACE("bv", tout << "asserted: " << l << "\n";);
if (a && a->is_bit())
if (a && a->is_bit()) {
force_push();
for (auto vp : a->to_bit())
m_prop_queue.push_back(vp);
}
}
bool solver::unit_propagate() {
if (m_prop_queue_head == m_prop_queue.size())
return false;
force_push();
ctx.push(value_trail<euf::solver, unsigned>(m_prop_queue_head));
for (; m_prop_queue_head < m_prop_queue.size() && !s().inconsistent(); ++m_prop_queue_head)
propagate_bits(m_prop_queue[m_prop_queue_head]);
@ -311,26 +352,26 @@ namespace bv {
}
sat::check_result solver::check() {
force_push();
SASSERT(m_prop_queue.size() == m_prop_queue_head);
return sat::check_result::CR_DONE;
}
void solver::push() {
th_euf_solver::lazy_push();
void solver::push_core() {
th_euf_solver::push_core();
m_prop_queue_lim.push_back(m_prop_queue.size());
}
void solver::pop(unsigned n) {
void solver::pop_core(unsigned n) {
SASSERT(m_num_scopes == 0);
unsigned old_sz = m_prop_queue_lim.size() - n;
m_prop_queue.shrink(m_prop_queue_lim[old_sz]);
m_prop_queue_lim.shrink(old_sz);
n = lazy_pop(n);
if (n > 0) {
old_sz = get_num_vars();
m_bits.shrink(old_sz);
m_wpos.shrink(old_sz);
m_zero_one_bits.shrink(old_sz);
}
th_euf_solver::pop_core(n);
old_sz = get_num_vars();
m_bits.shrink(old_sz);
m_wpos.shrink(old_sz);
m_zero_one_bits.shrink(old_sz);
}
void solver::pre_simplify() {}
@ -559,8 +600,7 @@ namespace bv {
SASSERT(s().inconsistent());
}
else {
if (get_config().m_bv_eq_axioms && false) {
// TODO - enable when pop_reinit is available
if (false && get_config().m_bv_eq_axioms) {
expr_ref eq(m.mk_eq(var2expr(v1), var2expr(v2)), m);
flet<bool> _is_redundant(m_is_redundant, true);
literal eq_lit = ctx.internalize(eq, false, false, m_is_redundant);

View file

@ -246,8 +246,8 @@ namespace bv {
void get_antecedents(literal l, sat::ext_justification_idx idx, literal_vector & r, bool probing) override;
void asserted(literal l) override;
sat::check_result check() override;
void push() override;
void pop(unsigned n) override;
void push_core() override;
void pop_core(unsigned n) override;
void pre_simplify() override;
void simplify() override;
bool set_root(literal l, literal r) override;
@ -270,6 +270,8 @@ namespace bv {
unsigned max_var(unsigned w) const override;
void new_eq_eh(euf::th_eq const& eq) override;
void new_diseq_eh(euf::th_eq const& ne) override;
bool use_diseqs() const override { return true; }
bool unit_propagate() override;
void add_value(euf::enode* n, model& mdl, expr_ref_vector& values) override;

View file

@ -54,9 +54,11 @@ namespace euf {
if (is_app(e) && to_app(e)->get_num_args() > 0) {
m_stack.push_back(sat::eframe(e));
return false;
}
n = m_egraph.mk(e, 0, nullptr);
attach_node(n);
}
if (auto* s = expr2solver(e))
s->internalize(e, m_is_redundant);
else
attach_node(m_egraph.mk(e, 0, nullptr));
return true;
}
@ -67,12 +69,10 @@ namespace euf {
m_args.push_back(m_egraph.find(to_app(e)->get_arg(i)));
if (root && internalize_root(to_app(e), sign, m_args))
return false;
if (auto* s = expr2solver(e)) {
s->internalize(e, m_is_redundant);
return true;
}
enode* n = m_egraph.mk(e, num, m_args.c_ptr());
attach_node(n);
if (auto* s = expr2solver(e))
s->internalize(e, m_is_redundant);
else
attach_node(m_egraph.mk(e, num, m_args.c_ptr()));
return true;
}
@ -146,7 +146,7 @@ namespace euf {
sat::literal_vector lits;
for (unsigned i = 0; i < sz; ++i) {
for (unsigned j = i + 1; j < sz; ++j) {
expr_ref eq(m.mk_eq(args[i]->get_expr(), args[j]->get_expr()), m);
expr_ref eq = mk_eq(args[i]->get_expr(), args[j]->get_expr());
sat::literal lit = internalize(eq, false, false, m_is_redundant);
lits.push_back(lit);
}
@ -167,10 +167,10 @@ namespace euf {
for (expr* arg : *e) {
expr_ref fapp(m.mk_app(f, arg), m);
expr_ref gapp(m.mk_app(g, fapp.get()), m);
expr_ref eq(m.mk_eq(gapp, arg), m);
expr_ref eq = mk_eq(gapp, arg);
sat::literal lit = internalize(eq, false, false, m_is_redundant);
s().add_clause(1, &lit, st);
eqs.push_back(m.mk_eq(fapp, a));
eqs.push_back(mk_eq(fapp, a));
}
pb_util pb(m);
expr_ref at_least2(pb.mk_at_least_k(eqs.size(), eqs.c_ptr(), 2), m);
@ -191,7 +191,7 @@ namespace euf {
if (sz <= distinct_max_args) {
for (unsigned i = 0; i < sz; ++i) {
for (unsigned j = i + 1; j < sz; ++j) {
expr_ref eq(m.mk_eq(args[i]->get_expr(), args[j]->get_expr()), m);
expr_ref eq = mk_eq(args[i]->get_expr(), args[j]->get_expr());
sat::literal lit = internalize(eq, true, false, m_is_redundant);
s().add_clause(1, &lit, st);
}
@ -208,7 +208,7 @@ namespace euf {
expr_ref fresh(m.mk_fresh_const("dist-value", u), m);
enode* n = m_egraph.mk(fresh, 0, nullptr);
n->mark_interpreted();
expr_ref eq(m.mk_eq(fapp, fresh), m);
expr_ref eq = mk_eq(fapp, fresh);
sat::literal lit = internalize(eq, false, false, m_is_redundant);
s().add_clause(1, &lit, st);
}
@ -221,23 +221,30 @@ namespace euf {
expr* c = nullptr, * th = nullptr, * el = nullptr;
if (!m.is_bool(e) && m.is_ite(e, c, th, el)) {
app* a = to_app(e);
sat::bool_var v = si.to_bool_var(c);
SASSERT(v != sat::null_bool_var);
expr_ref eq_th(m.mk_eq(a, th), m);
expr_ref eq_el(m.mk_eq(a, el), m);
expr_ref eq_th = mk_eq(a, th);
sat::literal lit_th = internalize(eq_th, false, false, m_is_redundant);
sat::literal lit_el = internalize(eq_el, false, false, m_is_redundant);
literal lits1[2] = { literal(v, true), lit_th };
literal lits2[2] = { literal(v, false), lit_el };
s().add_clause(2, lits1, st);
s().add_clause(2, lits2, st);
if (th == el) {
s().add_clause(1, &lit_th, st);
}
else {
sat::bool_var v = si.to_bool_var(c);
SASSERT(v != sat::null_bool_var);
expr_ref eq_el = mk_eq(a, el);
sat::literal lit_el = internalize(eq_el, false, false, m_is_redundant);
literal lits1[2] = { literal(v, true), lit_th };
literal lits2[2] = { literal(v, false), lit_el };
s().add_clause(2, lits1, st);
s().add_clause(2, lits2, st);
}
}
else if (m.is_distinct(e)) {
expr_ref_vector eqs(m);
unsigned sz = n->num_args();
for (unsigned i = 0; i < sz; ++i) {
for (unsigned j = i + 1; j < sz; ++j) {
expr_ref eq(m.mk_eq(n->get_arg(i)->get_expr(), n->get_arg(j)->get_expr()), m);
expr_ref eq = mk_eq(n->get_arg(i)->get_expr(), n->get_arg(j)->get_expr());
eqs.push_back(eq);
}
}
@ -308,4 +315,13 @@ namespace euf {
// TODO
// return get_theory(th_id)->is_shared(l->get_var());
}
expr_ref solver::mk_eq(expr* e1, expr* e2) {
if (e1 == e2)
return expr_ref(m.mk_true(), m);
expr_ref r(m.mk_eq(e2, e1), m);
if (!m_egraph.find(r))
r = m.mk_eq(e1, e2);
return r;
}
}

View file

@ -27,19 +27,19 @@ namespace euf {
void solver::check_eqc_bool_assignment() const {
for (enode* n : m_egraph.nodes()) {
VERIFY(!m.is_bool(n->get_expr()) ||
s().value(get_literal(n)) == s().value(get_literal(n->get_root())));
s().value(enode2literal(n)) == s().value(enode2literal(n->get_root())));
}
}
void solver::check_missing_bool_enode_propagation() const {
for (enode* n : m_egraph.nodes())
if (m.is_bool(n->get_expr()) && l_undef == s().value(get_literal(n))) {
if (m.is_bool(n->get_expr()) && l_undef == s().value(enode2literal(n))) {
if (!n->is_root()) {
VERIFY(l_undef == s().value(get_literal(n->get_root())));
VERIFY(l_undef == s().value(enode2literal(n->get_root())));
}
else
for (enode* o : enode_class(n)) {
VERIFY(l_undef == s().value(get_literal(o)));
VERIFY(l_undef == s().value(enode2literal(o)));
}
}
}

View file

@ -42,8 +42,15 @@ namespace euf {
updt_params(p);
std::function<void(std::ostream&, void*)> disp =
[&](std::ostream& out, void* j) { display_justification_ptr(out, reinterpret_cast<size_t*>(j)); };
[&](std::ostream& out, void* j) {
display_justification_ptr(out, reinterpret_cast<size_t*>(j));
};
std::function<lbool(enode* n)> eval = [&](enode* n) {
sat::literal lit = expr2literal(n->get_expr());
return (lit == sat::null_literal) ? l_undef : s().value(lit);
};
m_egraph.set_display_justification(disp);
m_egraph.set_eval(eval);
}
void solver::updt_params(params_ref const& p) {
@ -140,8 +147,8 @@ namespace euf {
ext->get_antecedents(l, idx, r, probing);
for (unsigned qhead = 0; qhead < m_explain.size(); ++qhead) {
size_t* e = m_explain[qhead];
if (is_literal(e))
r.push_back(get_literal(e));
if (is_literal(e))
r.push_back(get_literal(e));
else {
size_t idx = get_justification(e);
auto* ext = sat::constraint_base::to_extension(idx);
@ -150,9 +157,14 @@ namespace euf {
ext->get_antecedents(lit, idx, r, probing);
}
}
m_egraph.end_explain();
m_egraph.end_explain();
unsigned j = 0;
for (sat::literal lit : r)
if (s().lvl(lit) > 0) r[j++] = lit;
r.shrink(j);
TRACE("euf", tout << "eplain " << l << " <- " << r << " " << probing << "\n";);
DEBUG_CODE(for (auto lit : r) SASSERT(s().value(lit) == l_true););
if (!probing)
log_antecedents(l, r);
}
@ -204,13 +216,13 @@ namespace euf {
void solver::asserted(literal l) {
expr* e = m_var2expr.get(l.var(), nullptr);
if (!e) {
return;
}
if (!e)
return;
bool sign = l.sign();
TRACE("euf", tout << "asserted: " << l << "@" << s().scope_lvl() << "\n";);
euf::enode* n = m_egraph.find(e);
TRACE("euf", tout << "asserted: " << l << "@" << s().scope_lvl() << "\n";);
if (!n)
return;
for (auto th : enode_th_vars(n))
@ -220,32 +232,17 @@ namespace euf {
size_t* c = to_ptr(l);
SASSERT(is_literal(c));
SASSERT(l == get_literal(c));
if (m.is_eq(e) && n->num_args() == 2) {
if (m.is_eq(e) && n->num_args() == 2 && !sign) {
euf::enode* na = n->get_arg(0);
euf::enode* nb = n->get_arg(1);
if (!sign) {
m_egraph.merge(na, nb, c);
return;
}
else
new_diseq(na, nb, l);
m_egraph.merge(na, nb, c);
}
else {
euf::enode* nb = sign ? mk_false() : mk_true();
m_egraph.merge(n, nb, c);
}
euf::enode* nb = sign ? mk_false() : mk_true();
m_egraph.merge(n, nb, c);
}
void solver::new_diseq(enode* n1, enode* n2, literal lit) {
enode * r1 = n1->get_root();
enode * r2 = n2->get_root();
if (r1 == r2)
return;
if (r1->has_one_th_var() && r2->has_one_th_var() && r1->get_first_th_id() == r2->get_first_th_id()) {
theory_id id = r1->get_first_th_id();
theory_var v1 = r1->get_th_var(id);
theory_var v2 = r2->get_th_var(id);
fid2solver(id)->new_diseq_eh(r1, r2);
}
}
bool solver::unit_propagate() {
bool propagated = false;
@ -284,7 +281,7 @@ namespace euf {
bool_var v = si.to_bool_var(e);
SASSERT(m.is_bool(e));
size_t cnstr;
literal lit;
literal lit;
if (is_eq) {
VERIFY(m.is_eq(e, a, b));
cnstr = eq_constraint().to_index();
@ -315,7 +312,10 @@ namespace euf {
void solver::propagate_th_eqs() {
for (; m_egraph.has_th_eq() && !s().inconsistent() && !m_egraph.inconsistent(); m_egraph.next_th_eq()) {
th_eq eq = m_egraph.get_th_eq();
m_id2solver[eq.m_id]->new_eq_eh(eq);
if (eq.is_eq())
m_id2solver[eq.id()]->new_eq_eh(eq);
else
m_id2solver[eq.id()]->new_diseq_eh(eq);
}
}
@ -379,6 +379,7 @@ namespace euf {
m_scopes.shrink(m_scopes.size() - n);
si.pop(n);
SASSERT(m_egraph.num_scopes() == m_scopes.size());
TRACE("euf", tout << "pop to: " << m_scopes.size() << "\n";);
}
void solver::start_reinit(unsigned n) {
@ -405,9 +406,19 @@ namespace euf {
if (expr2var_replay.empty())
return;
si.set_expr2var_replay(&expr2var_replay);
for (auto const& kv : expr2var_replay)
attach_lit(si.internalize(kv.m_key, true), kv.m_key);
si.set_expr2var_replay(nullptr);
TRACE("euf", for (auto const& kv : expr2var_replay) tout << "replay: " << kv.m_value << " " << mk_bounded_pp(kv.m_key, m) << "\n";);
for (auto const& kv : expr2var_replay) {
sat::literal lit;
expr* e = kv.m_key;
if (si.is_bool_op(e))
lit = literal(expr2var_replay[e], false);
else
lit = si.internalize(kv.m_key, true);
VERIFY(lit.var() == kv.m_value);
attach_lit(lit, kv.m_key);
}
si.set_expr2var_replay(nullptr);
TRACE("euf", tout << "replay done\n";);
}
void solver::pre_simplify() {

View file

@ -49,8 +49,6 @@ namespace euf {
size_t to_index() const { return sat::constraint_base::mem2base(this); }
};
class solver : public sat::extension, public th_internalizer, public th_decompile {
typedef top_sort<euf::enode> deps_t;
friend class ackerman;
@ -194,10 +192,11 @@ namespace euf {
sat::sat_internalizer& get_si() { return si; }
ast_manager& get_manager() { return m; }
enode* get_enode(expr* e) { return m_egraph.find(e); }
sat::literal get_literal(expr* e) const { return literal(si.to_bool_var(e), false); }
sat::literal get_literal(enode* e) const { return get_literal(e->get_expr()); }
sat::literal expr2literal(expr* e) const { return literal(si.to_bool_var(e), false); }
sat::literal enode2literal(enode* e) const { return expr2literal(e->get_expr()); }
smt_params const& get_config() { return m_config; }
region& get_region() { return m_trail.get_region(); }
egraph& get_egraph() { return m_egraph; }
template <typename C>
void push(C const& c) { m_trail.push(c); }
euf_trail_stack& get_trail_stack() { return m_trail; }
@ -254,6 +253,8 @@ namespace euf {
void internalize(expr* e, bool learned) override;
void attach_th_var(enode* n, th_solver* th, theory_var v) { m_egraph.add_th_var(n, v, th->get_id()); }
void attach_node(euf::enode* n);
expr_ref mk_eq(expr* e1, expr* e2);
expr_ref mk_eq(euf::enode* n1, euf::enode* n2) { return mk_eq(n1->get_expr(), n2->get_expr()); }
euf::enode* mk_enode(expr* e, unsigned n, enode* const* args) { return m_egraph.mk(e, n, args); }
expr* bool_var2expr(sat::bool_var v) { return m_var2expr.get(v, nullptr); }
void unhandled_function(func_decl* f);

View file

@ -74,7 +74,7 @@ namespace euf {
}
sat::literal th_euf_solver::expr2literal(expr* e) const {
return ctx.get_literal(e);
return ctx.expr2literal(e);
}
expr* th_euf_solver::bool_var2expr(sat::bool_var v) const {
@ -98,26 +98,23 @@ namespace euf {
return get_th_var(ctx.get_enode(e));
}
void th_euf_solver::push() {
void th_euf_solver::push_core() {
TRACE("euf", tout << "push-core\n";);
m_var2enode_lim.push_back(m_var2enode.size());
}
void th_euf_solver::pop(unsigned num_scopes) {
void th_euf_solver::pop_core(unsigned num_scopes) {
unsigned new_lvl = m_var2enode_lim.size() - num_scopes;
m_var2enode.shrink(m_var2enode_lim[new_lvl]);
m_var2enode_lim.shrink(new_lvl);
}
unsigned th_euf_solver::lazy_pop(unsigned n) {
if (n <= m_num_scopes) {
m_num_scopes -= n;
return 0;
}
else {
n -= m_num_scopes;
pop(n);
return n;
}
void th_euf_solver::pop(unsigned n) {
unsigned k = std::min(m_num_scopes, n);
m_num_scopes -= k;
n -= k;
if (n > 0)
pop_core(n);
}
bool th_euf_solver::add_unit(sat::literal lit) {
@ -154,4 +151,9 @@ namespace euf {
void th_euf_solver::rewrite(expr_ref& a) {
ctx.get_rewriter()(a);
}
expr_ref th_euf_solver::mk_eq(expr* e1, expr* e2) {
return ctx.mk_eq(e1, e2);
}
}

View file

@ -95,13 +95,15 @@ namespace euf {
virtual bool use_diseqs() const { return false; }
virtual void new_diseq_eh(euf::enode* a, euf::enode* b) {}
virtual void new_diseq_eh(euf::th_eq const& eq) {}
/**
\brief Parametric theories (e.g. Arrays) should implement this method.
*/
virtual bool is_shared(theory_var v) const { return false; }
};
class th_euf_solver : public th_solver {
@ -129,9 +131,15 @@ namespace euf {
euf::enode* e_internalize(expr* e) { internalize(e, m_is_redundant); return expr2enode(e); }
euf::enode* mk_enode(expr* e, bool suppress_args);
expr_ref mk_eq(expr* e1, expr* e2);
expr_ref mk_var_eq(theory_var v1, theory_var v2) { return mk_eq(var2expr(v1), var2expr(v2)); }
void rewrite(expr_ref& a);
virtual void push_core();
virtual void pop_core(unsigned n);
void force_push() { for (; m_num_scopes > 0; --m_num_scopes) push_core(); }
public:
th_euf_solver(euf::solver& ctx, euf::theory_id id);
virtual ~th_euf_solver() {}
@ -147,12 +155,9 @@ namespace euf {
trail_stack<euf::solver> & get_trail_stack();
bool is_attached_to_var(enode* n) const;
bool is_root(theory_var v) const { return var2enode(v)->is_root(); }
void push() override;
void pop(unsigned n) override;
void push() override { m_num_scopes++; }
void pop(unsigned n) override;
void lazy_push() { ++m_num_scopes; }
void force_push() { for (; m_num_scopes > 0; --m_num_scopes) push(); }
unsigned lazy_pop(unsigned n);
};