mirror of
https://github.com/Z3Prover/z3
synced 2025-04-12 04:03:39 +00:00
updates to handle bugs exposed by qf-abv for local search
- ctx.is_true(e) - changed to work with expressions that are not literals, but come from top-level assertions - set fixed in sls_bv_fixed to work with non-zero low order bits - array plugin to deal with cases where e-graph is inconsistent after a merge.
This commit is contained in:
parent
7ffed8613a
commit
b6e7b80704
|
@ -36,7 +36,36 @@ namespace sls {
|
||||||
m_kv = nullptr;
|
m_kv = nullptr;
|
||||||
init_egraph(*m_g);
|
init_egraph(*m_g);
|
||||||
saturate(*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<size_t> explain;
|
||||||
|
g.begin_explain();
|
||||||
|
g.explain<size_t>(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]
|
// b ~ a[i -> v]
|
||||||
|
@ -45,9 +74,9 @@ namespace sls {
|
||||||
|
|
||||||
void array_plugin::saturate(euf::egraph& g) {
|
void array_plugin::saturate(euf::egraph& g) {
|
||||||
unsigned sz = 0;
|
unsigned sz = 0;
|
||||||
while (sz < g.nodes().size()) {
|
while (sz < g.nodes().size() && !g.inconsistent()) {
|
||||||
sz = g.nodes().size();
|
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];
|
auto n = g.nodes()[i];
|
||||||
if (a.is_store(n->get_expr()))
|
if (a.is_store(n->get_expr()))
|
||||||
saturate_store(g, n);
|
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) {
|
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) {
|
void array_plugin::add_map_axiom(euf::egraph& g, euf::enode * n, euf::enode* sel) {
|
||||||
|
if (g.inconsistent())
|
||||||
|
return;
|
||||||
func_decl* f = nullptr;
|
func_decl* f = nullptr;
|
||||||
SASSERT(a.is_map(n->get_expr()));
|
SASSERT(a.is_map(n->get_expr()));
|
||||||
VERIFY(a.is_map(n->get_decl(), f));
|
VERIFY(a.is_map(n->get_decl(), f));
|
||||||
|
@ -109,15 +140,14 @@ namespace sls {
|
||||||
nmap = g.mk(f_map, 0, eargs.size(), eargs.data());
|
nmap = g.mk(f_map, 0, eargs.size(), eargs.data());
|
||||||
if (nmap->get_root() == nsel->get_root())
|
if (nmap->get_root() == nsel->get_root())
|
||||||
return;
|
return;
|
||||||
if (are_distinct(nsel, nmap)) {
|
if (!are_distinct(nsel, nmap)) {
|
||||||
expr_ref eq(m.mk_eq(nmap->get_expr(), nsel->get_expr()), m);
|
|
||||||
ctx.add_theory_axiom(eq);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
g.merge(nmap, nsel, nullptr);
|
g.merge(nmap, nsel, nullptr);
|
||||||
g.propagate();
|
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) {
|
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
|
// ensure a[i->v][i] = v exists in the e-graph
|
||||||
void array_plugin::force_store_axiom1(euf::egraph& g, euf::enode* n) {
|
void array_plugin::force_store_axiom1(euf::egraph& g, euf::enode* n) {
|
||||||
|
if (g.inconsistent())
|
||||||
|
return;
|
||||||
SASSERT(a.is_store(n->get_expr()));
|
SASSERT(a.is_store(n->get_expr()));
|
||||||
auto val = n->get_arg(n->num_args() - 1);
|
auto val = n->get_arg(n->num_args() - 1);
|
||||||
auto nsel = mk_select(g, n, n);
|
auto nsel = mk_select(g, n, n);
|
||||||
if (are_distinct(nsel, val))
|
VERIFY(!g.inconsistent());
|
||||||
add_store_axiom1(n->get_app());
|
if (!are_distinct(nsel, val)) {
|
||||||
else {
|
g.merge(nsel, val, nullptr);
|
||||||
g.merge(nsel, val, nullptr);
|
|
||||||
g.propagate();
|
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]
|
// 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) {
|
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_store(sto->get_expr()));
|
||||||
SASSERT(a.is_select(sel->get_expr()));
|
SASSERT(a.is_select(sel->get_expr()));
|
||||||
if (sel->get_arg(0)->get_root() != sto->get_root())
|
if (sel->get_arg(0)->get_root() != sto->get_root())
|
||||||
|
@ -159,17 +194,19 @@ namespace sls {
|
||||||
if (eq_args(sto, sel))
|
if (eq_args(sto, sel))
|
||||||
return;
|
return;
|
||||||
auto nsel = mk_select(g, sto->get_arg(0), sel);
|
auto nsel = mk_select(g, sto->get_arg(0), sel);
|
||||||
if (are_distinct(nsel, sel))
|
if (!are_distinct(nsel, sel)) {
|
||||||
add_store_axiom2(sto->get_app(), sel->get_app());
|
|
||||||
else {
|
|
||||||
g.merge(nsel, sel, nullptr);
|
g.merge(nsel, sel, nullptr);
|
||||||
g.propagate();
|
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]
|
// 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) {
|
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_store(sto->get_expr()));
|
||||||
SASSERT(a.is_select(sel->get_expr()));
|
SASSERT(a.is_select(sel->get_expr()));
|
||||||
if (sel->get_arg(0)->get_root() != sto->get_arg(0)->get_root())
|
if (sel->get_arg(0)->get_root() != sto->get_arg(0)->get_root())
|
||||||
|
@ -177,32 +214,33 @@ namespace sls {
|
||||||
if (eq_args(sto, sel))
|
if (eq_args(sto, sel))
|
||||||
return;
|
return;
|
||||||
auto nsel = mk_select(g, sto, sel);
|
auto nsel = mk_select(g, sto, sel);
|
||||||
if (are_distinct(nsel, sel))
|
if (!are_distinct(nsel, sel)) {
|
||||||
add_store_axiom2(sto->get_app(), sel->get_app());
|
|
||||||
else {
|
|
||||||
g.merge(nsel, sel, nullptr);
|
g.merge(nsel, sel, nullptr);
|
||||||
g.propagate();
|
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]
|
// 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) {
|
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_const(cn->get_expr()));
|
||||||
SASSERT(a.is_select(sel->get_expr()));
|
SASSERT(a.is_select(sel->get_expr()));
|
||||||
if (sel->get_arg(0)->get_root() != cn->get_root())
|
if (sel->get_arg(0)->get_root() != cn->get_root())
|
||||||
return;
|
return;
|
||||||
auto val = cn->get_arg(0);
|
auto val = cn->get_arg(0);
|
||||||
auto nsel = mk_select(g, cn, sel);
|
auto nsel = mk_select(g, cn, sel);
|
||||||
if (are_distinct(nsel, 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 {
|
|
||||||
g.merge(nsel, sel, nullptr);
|
g.merge(nsel, sel, nullptr);
|
||||||
g.propagate();
|
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) {
|
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");
|
IF_VERBOSE(3, verbose_stream() << "init " << mk_bounded_pp(t, m) << " := " << mk_bounded_pp(v, m) << " " << g.inconsistent() << "\n");
|
||||||
n2 = g.find(v);
|
n2 = g.find(v);
|
||||||
n2 = n2 ? n2: g.mk(v, 0, 0, nullptr);
|
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()) {
|
for (auto lit : ctx.root_literals()) {
|
||||||
if (!ctx.is_true(lit) || lit.sign())
|
if (!ctx.is_true(lit) || lit.sign())
|
||||||
|
@ -281,7 +319,7 @@ namespace sls {
|
||||||
auto e = ctx.atom(lit.var());
|
auto e = ctx.atom(lit.var());
|
||||||
expr* x = nullptr, * y = nullptr;
|
expr* x = nullptr, * y = nullptr;
|
||||||
if (e && m.is_eq(e, x, y))
|
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));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,13 @@ namespace sls {
|
||||||
bool are_distinct(euf::enode* a, euf::enode* b);
|
bool are_distinct(euf::enode* a, euf::enode* b);
|
||||||
bool eq_args(euf::enode* sto, euf::enode* sel);
|
bool eq_args(euf::enode* sto, euf::enode* sel);
|
||||||
euf::enode* mk_select(euf::egraph& g, euf::enode* b, 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*>((size_t)(l.index() << 4)); };
|
||||||
|
size_t* to_ptr(expr* t) { return reinterpret_cast<size_t*>((reinterpret_cast<size_t>(t) << 4) + 1); }
|
||||||
|
bool is_literal(size_t* p) { return (reinterpret_cast<size_t>(p) & 1) == 0; }
|
||||||
|
sat::literal to_literal(size_t* p) { return sat::to_literal(static_cast<unsigned>(reinterpret_cast<size_t>(p) >> 4)); };
|
||||||
|
expr* to_expr(size_t* p) { return reinterpret_cast<expr*>(reinterpret_cast<size_t>(p) >> 4); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
array_plugin(context& ctx);
|
array_plugin(context& ctx);
|
||||||
|
|
|
@ -108,7 +108,7 @@ namespace sls {
|
||||||
|
|
||||||
bool basic_plugin::bval0(expr* e) const {
|
bool basic_plugin::bval0(expr* e) const {
|
||||||
SASSERT(m.is_bool(e));
|
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) {
|
bool basic_plugin::try_repair(app* e, unsigned i) {
|
||||||
|
|
|
@ -413,10 +413,8 @@ namespace sls {
|
||||||
|
|
||||||
|
|
||||||
if (j > 0 && k > 0) {
|
if (j > 0 && k > 0) {
|
||||||
for (unsigned i = 0; i < std::min(k, j); ++i) {
|
for (unsigned i = 0; i < std::min(k, j); ++i)
|
||||||
SASSERT(!v.get_bit(i));
|
v.set_fixed_bit(i, v.get_bit(i));
|
||||||
v.set_fixed_bit(i, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// lower zj + jk bits are 0
|
// lower zj + jk bits are 0
|
||||||
if (zk > 0 || zj > 0) {
|
if (zk > 0 || zj > 0) {
|
||||||
|
|
|
@ -288,9 +288,20 @@ namespace sls {
|
||||||
SASSERT(m.is_bool(e));
|
SASSERT(m.is_bool(e));
|
||||||
auto v = m_atom2bool_var.get(e->get_id(), sat::null_bool_var);
|
auto v = m_atom2bool_var.get(e->get_id(), sat::null_bool_var);
|
||||||
if (v != 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);
|
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) {
|
bool context::is_fixed(expr* e) {
|
||||||
|
|
Loading…
Reference in a new issue