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:
parent
2d52367368
commit
549753845e
34 changed files with 1480 additions and 854 deletions
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue