diff --git a/src/ast/sls/sls_array_plugin.cpp b/src/ast/sls/sls_array_plugin.cpp index a9c8f802d..e5b83913c 100644 --- a/src/ast/sls/sls_array_plugin.cpp +++ b/src/ast/sls/sls_array_plugin.cpp @@ -36,7 +36,36 @@ namespace sls { m_kv = nullptr; init_egraph(*m_g); saturate(*m_g); - return true; +#if 0 + if (m_g->inconsistent()) { + resolve_conflict(); + return false; + } + return !m_g->inconsistent(); +#endif + } + + + void array_plugin::resolve_conflict() { + auto& g = *m_g; + SASSERT(g.inconsistent()); + unsigned n = 0; + sat::literal_vector lits; + ptr_vector explain; + g.begin_explain(); + g.explain(explain, nullptr); + g.end_explain(); + + verbose_stream() << "conflict\n"; + for (auto p : explain) { + if (is_literal(p)) { + sat::literal l = to_literal(p); + verbose_stream() << l << " " << mk_bounded_pp(ctx.atom(l.var()), m) << " " << ctx.is_unit(l) << "\n"; + } + else { + verbose_stream() << mk_bounded_pp(to_expr(p), m) << " == " << mk_bounded_pp(ctx.get_value(to_expr(p)), m) << "\n"; + } + } } // b ~ a[i -> v] @@ -45,9 +74,9 @@ namespace sls { void array_plugin::saturate(euf::egraph& g) { unsigned sz = 0; - while (sz < g.nodes().size()) { + while (sz < g.nodes().size() && !g.inconsistent()) { sz = g.nodes().size(); - for (unsigned i = 0; i < sz; ++i) { + for (unsigned i = 0; i < sz && !g.inconsistent(); ++i) { auto n = g.nodes()[i]; if (a.is_store(n->get_expr())) saturate_store(g, n); @@ -58,7 +87,7 @@ namespace sls { } } - IF_VERBOSE(2, display(verbose_stream() << "saturated\n")); + IF_VERBOSE(10, display(verbose_stream() << "saturated\n")); } void array_plugin::saturate_store(euf::egraph& g, euf::enode* n) { @@ -91,6 +120,8 @@ namespace sls { } void array_plugin::add_map_axiom(euf::egraph& g, euf::enode * n, euf::enode* sel) { + if (g.inconsistent()) + return; func_decl* f = nullptr; SASSERT(a.is_map(n->get_expr())); VERIFY(a.is_map(n->get_decl(), f)); @@ -109,15 +140,14 @@ namespace sls { nmap = g.mk(f_map, 0, eargs.size(), eargs.data()); if (nmap->get_root() == nsel->get_root()) return; - if (are_distinct(nsel, nmap)) { - expr_ref eq(m.mk_eq(nmap->get_expr(), nsel->get_expr()), m); - ctx.add_theory_axiom(eq); - } - else { + if (!are_distinct(nsel, nmap)) { g.merge(nmap, nsel, nullptr); g.propagate(); - VERIFY(!g.inconsistent()); + if (!g.inconsistent()) + return; } + expr_ref eq(m.mk_eq(nmap->get_expr(), nsel->get_expr()), m); + ctx.add_theory_axiom(eq); } euf::enode* array_plugin::mk_select(euf::egraph& g, euf::enode* b, euf::enode* sel) { @@ -138,20 +168,25 @@ namespace sls { // ensure a[i->v][i] = v exists in the e-graph void array_plugin::force_store_axiom1(euf::egraph& g, euf::enode* n) { + if (g.inconsistent()) + return; SASSERT(a.is_store(n->get_expr())); auto val = n->get_arg(n->num_args() - 1); auto nsel = mk_select(g, n, n); - if (are_distinct(nsel, val)) - add_store_axiom1(n->get_app()); - else { - g.merge(nsel, val, nullptr); + VERIFY(!g.inconsistent()); + if (!are_distinct(nsel, val)) { + g.merge(nsel, val, nullptr); g.propagate(); - VERIFY(!g.inconsistent()); + if (!g.inconsistent()) + return; } + add_store_axiom1(n->get_app()); } // i /~ j, b ~ a[i->v], b[j] occurs -> a[j] = b[j] void array_plugin::force_store_axiom2_down(euf::egraph& g, euf::enode* sto, euf::enode* sel) { + if (g.inconsistent()) + return; SASSERT(a.is_store(sto->get_expr())); SASSERT(a.is_select(sel->get_expr())); if (sel->get_arg(0)->get_root() != sto->get_root()) @@ -159,17 +194,19 @@ namespace sls { if (eq_args(sto, sel)) return; auto nsel = mk_select(g, sto->get_arg(0), sel); - if (are_distinct(nsel, sel)) - add_store_axiom2(sto->get_app(), sel->get_app()); - else { + if (!are_distinct(nsel, sel)) { g.merge(nsel, sel, nullptr); g.propagate(); - VERIFY(!g.inconsistent()); + if (!g.inconsistent()) + return; } + add_store_axiom2(sto->get_app(), sel->get_app()); } // a ~ b, i /~ j, b[j] occurs -> a[i -> v][j] = b[j] void array_plugin::force_store_axiom2_up(euf::egraph& g, euf::enode* sto, euf::enode* sel) { + if (g.inconsistent()) + return; SASSERT(a.is_store(sto->get_expr())); SASSERT(a.is_select(sel->get_expr())); if (sel->get_arg(0)->get_root() != sto->get_arg(0)->get_root()) @@ -177,32 +214,33 @@ namespace sls { if (eq_args(sto, sel)) return; auto nsel = mk_select(g, sto, sel); - if (are_distinct(nsel, sel)) - add_store_axiom2(sto->get_app(), sel->get_app()); - else { + if (!are_distinct(nsel, sel)) { g.merge(nsel, sel, nullptr); g.propagate(); - VERIFY(!g.inconsistent()); + if (!g.inconsistent()) + return; } + add_store_axiom2(sto->get_app(), sel->get_app()); } // const(v) ~ b, b[j] occurs -> v = (const v)[j] void array_plugin::force_const_axiom(euf::egraph& g, euf::enode* cn, euf::enode* sel) { + if (g.inconsistent()) + return; SASSERT(a.is_const(cn->get_expr())); SASSERT(a.is_select(sel->get_expr())); if (sel->get_arg(0)->get_root() != cn->get_root()) return; auto val = cn->get_arg(0); auto nsel = mk_select(g, cn, sel); - if (are_distinct(nsel, sel)) { - expr_ref eq(m.mk_eq(val->get_expr(), nsel->get_expr()), m); - ctx.add_theory_axiom(eq); - } - else { + if (!are_distinct(nsel, sel)) { g.merge(nsel, sel, nullptr); g.propagate(); - VERIFY(!g.inconsistent()); + if (!g.inconsistent()) + return; } + expr_ref eq(m.mk_eq(val->get_expr(), nsel->get_expr()), m); + ctx.add_theory_axiom(eq); } bool array_plugin::are_distinct(euf::enode* a, euf::enode* b) { @@ -273,7 +311,7 @@ namespace sls { IF_VERBOSE(3, verbose_stream() << "init " << mk_bounded_pp(t, m) << " := " << mk_bounded_pp(v, m) << " " << g.inconsistent() << "\n"); n2 = g.find(v); n2 = n2 ? n2: g.mk(v, 0, 0, nullptr); - g.merge(n1, n2, nullptr); + g.merge(n1, n2, to_ptr(t)); } for (auto lit : ctx.root_literals()) { if (!ctx.is_true(lit) || lit.sign()) @@ -281,7 +319,7 @@ namespace sls { auto e = ctx.atom(lit.var()); expr* x = nullptr, * y = nullptr; if (e && m.is_eq(e, x, y)) - g.merge(g.find(x), g.find(y), nullptr); + g.merge(g.find(x), g.find(y), to_ptr(lit)); } diff --git a/src/ast/sls/sls_array_plugin.h b/src/ast/sls/sls_array_plugin.h index 01d177f4c..3c76cc4e5 100644 --- a/src/ast/sls/sls_array_plugin.h +++ b/src/ast/sls/sls_array_plugin.h @@ -70,6 +70,13 @@ namespace sls { bool are_distinct(euf::enode* a, euf::enode* b); bool eq_args(euf::enode* sto, euf::enode* sel); euf::enode* mk_select(euf::egraph& g, euf::enode* b, euf::enode* sel); + + void resolve_conflict(); + size_t* to_ptr(sat::literal l) { return reinterpret_cast((size_t)(l.index() << 4)); }; + size_t* to_ptr(expr* t) { return reinterpret_cast((reinterpret_cast(t) << 4) + 1); } + bool is_literal(size_t* p) { return (reinterpret_cast(p) & 1) == 0; } + sat::literal to_literal(size_t* p) { return sat::to_literal(static_cast(reinterpret_cast(p) >> 4)); }; + expr* to_expr(size_t* p) { return reinterpret_cast(reinterpret_cast(p) >> 4); } public: array_plugin(context& ctx); diff --git a/src/ast/sls/sls_basic_plugin.cpp b/src/ast/sls/sls_basic_plugin.cpp index 1a836a511..9dd410fbe 100644 --- a/src/ast/sls/sls_basic_plugin.cpp +++ b/src/ast/sls/sls_basic_plugin.cpp @@ -108,7 +108,7 @@ namespace sls { bool basic_plugin::bval0(expr* e) const { SASSERT(m.is_bool(e)); - return ctx.is_true(ctx.mk_literal(e)); + return ctx.is_true(e); } bool basic_plugin::try_repair(app* e, unsigned i) { diff --git a/src/ast/sls/sls_bv_fixed.cpp b/src/ast/sls/sls_bv_fixed.cpp index d8854a9d9..993b79c41 100644 --- a/src/ast/sls/sls_bv_fixed.cpp +++ b/src/ast/sls/sls_bv_fixed.cpp @@ -413,10 +413,8 @@ namespace sls { if (j > 0 && k > 0) { - for (unsigned i = 0; i < std::min(k, j); ++i) { - SASSERT(!v.get_bit(i)); - v.set_fixed_bit(i, false); - } + for (unsigned i = 0; i < std::min(k, j); ++i) + v.set_fixed_bit(i, v.get_bit(i)); } // lower zj + jk bits are 0 if (zk > 0 || zj > 0) { diff --git a/src/ast/sls/sls_context.cpp b/src/ast/sls/sls_context.cpp index 86c4900df..dc3d5c30f 100644 --- a/src/ast/sls/sls_context.cpp +++ b/src/ast/sls/sls_context.cpp @@ -288,9 +288,20 @@ namespace sls { SASSERT(m.is_bool(e)); auto v = m_atom2bool_var.get(e->get_id(), sat::null_bool_var); if (v != sat::null_bool_var) - return m.is_true(m_plugins[basic_family_id]->get_value(e)); - else return is_true(v); + if (m.is_and(e)) + return all_of(*to_app(e), [&](expr* arg) { return is_true(arg); }); + if (m.is_or(e)) + return any_of(*to_app(e), [&](expr* arg) { return is_true(arg); }); + if (m.is_not(e)) + return !is_true(to_app(e)->get_arg(0)); + if (m.is_implies(e)) + return !is_true(to_app(e)->get_arg(0)) || is_true(to_app(e)->get_arg(1)); + if (m.is_iff(e)) + return is_true(to_app(e)->get_arg(0)) == is_true(to_app(e)->get_arg(1)); + if (m.is_ite(e)) + return is_true(to_app(e)->get_arg(0)) ? is_true(to_app(e)->get_arg(1)) : is_true(to_app(e)->get_arg(2)); + return is_true(mk_literal(e)); } bool context::is_fixed(expr* e) {