3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-12 12:08:18 +00:00

better behavior on disequality and branch selection (#4605)

* better behavior on disequality and branch selection

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

* fix loop

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2020-07-31 01:14:11 -07:00 committed by GitHub
parent e0d4669116
commit 3f862cb2ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 52 additions and 80 deletions

View file

@ -670,8 +670,8 @@ bool theory_seq::branch_binary_variable(eq const& e) {
if (lenX <= rational(ys.size())) { if (lenX <= rational(ys.size())) {
expr_ref_vector Ys(m); expr_ref_vector Ys(m);
Ys.append(ys.size(), ys.c_ptr()); Ys.append(ys.size(), ys.c_ptr());
branch_unit_variable(e.dep(), x, Ys); if (branch_unit_variable(e.dep(), x, Ys))
return true; return true;
} }
expr_ref le(m_autil.mk_le(mk_len(x), m_autil.mk_int(ys.size())), m); expr_ref le(m_autil.mk_le(mk_len(x), m_autil.mk_int(ys.size())), m);
literal lit = mk_literal(le); literal lit = mk_literal(le);
@ -698,13 +698,13 @@ bool theory_seq::branch_binary_variable(eq const& e) {
bool theory_seq::branch_unit_variable() { bool theory_seq::branch_unit_variable() {
bool result = false; bool result = false;
for (auto const& e : m_eqs) { for (auto const& e : m_eqs) {
if (is_unit_eq(e.ls(), e.rs())) { if (is_unit_eq(e.ls(), e.rs()) &&
branch_unit_variable(e.dep(), e.ls()[0], e.rs()); branch_unit_variable(e.dep(), e.ls()[0], e.rs())) {
result = true; result = true;
break; break;
} }
else if (is_unit_eq(e.rs(), e.ls())) { if (is_unit_eq(e.rs(), e.ls()) &&
branch_unit_variable(e.dep(), e.rs()[0], e.ls()); branch_unit_variable(e.dep(), e.rs()[0], e.ls())) {
result = true; result = true;
break; break;
} }
@ -713,38 +713,41 @@ bool theory_seq::branch_unit_variable() {
return result; return result;
} }
void theory_seq::branch_unit_variable(dependency* dep, expr* X, expr_ref_vector const& units) { bool theory_seq::branch_unit_variable(dependency* dep, expr* X, expr_ref_vector const& units) {
SASSERT(is_var(X)); SASSERT(is_var(X));
rational lenX; rational lenX;
if (!get_length(X, lenX)) { if (!get_length(X, lenX)) {
TRACE("seq", tout << "enforce length on " << mk_bounded_pp(X, m, 2) << "\n";); TRACE("seq", tout << "enforce length on " << mk_bounded_pp(X, m, 2) << "\n";);
add_length_to_eqc(X); add_length_to_eqc(X);
return; return true;
} }
if (lenX > rational(units.size())) { if (lenX > rational(units.size())) {
expr_ref le(m_autil.mk_le(mk_len(X), m_autil.mk_int(units.size())), m); expr_ref le(m_autil.mk_le(mk_len(X), m_autil.mk_int(units.size())), m);
TRACE("seq", tout << "propagate length on " << mk_bounded_pp(X, m, 2) << "\n";); TRACE("seq", tout << "propagate length on " << mk_bounded_pp(X, m, 2) << "\n";);
propagate_lit(dep, 0, nullptr, mk_literal(le)); propagate_lit(dep, 0, nullptr, mk_literal(le));
return; return true;
} }
SASSERT(lenX.is_unsigned()); SASSERT(lenX.is_unsigned());
unsigned lX = lenX.get_unsigned(); unsigned lX = lenX.get_unsigned();
if (lX == 0) { if (lX == 0) {
TRACE("seq", tout << "set empty length " << mk_bounded_pp(X, m, 2) << "\n";); TRACE("seq", tout << "set empty length " << mk_bounded_pp(X, m, 2) << "\n";);
set_empty(X); set_empty(X);
return true;
} }
else {
literal lit = mk_eq(m_autil.mk_int(lX), mk_len(X), false); literal lit = mk_eq(m_autil.mk_int(lX), mk_len(X), false);
if (l_true == ctx.get_assignment(lit)) { switch (ctx.get_assignment(lit)) {
expr_ref R = mk_concat(lX, units.c_ptr(), m.get_sort(X)); case l_true: {
propagate_eq(dep, lit, X, R); expr_ref R = mk_concat(lX, units.c_ptr(), m.get_sort(X));
TRACE("seq", tout << "propagate " << mk_pp(X, m) << " " << R << "\n";); return propagate_eq(dep, lit, X, R);
} }
else { case l_undef:
TRACE("seq", tout << "set phase " << mk_pp(X, m) << "\n";); TRACE("seq", tout << "set phase " << mk_pp(X, m) << "\n";);
ctx.mark_as_relevant(lit); ctx.mark_as_relevant(lit);
ctx.force_phase(lit); ctx.force_phase(lit);
} return true;
default:
return false;
} }
} }
@ -1135,13 +1138,11 @@ bool theory_seq::branch_variable_eq(eq const& e) {
TRACE("seq", tout << s << " " << id << ": " << e.ls() << " = " << e.rs() << "\n";); TRACE("seq", tout << s << " " << id << ": " << e.ls() << " = " << e.rs() << "\n";);
bool found = find_branch_candidate(s, e.dep(), e.ls(), e.rs()); bool found = find_branch_candidate(s, e.dep(), e.ls(), e.rs());
insert_branch_start(2*id, s); insert_branch_start(2*id, s);
if (found) { if (!found) {
return true; s = find_branch_start(2*id + 1);
found = find_branch_candidate(s, e.dep(), e.rs(), e.ls());
insert_branch_start(2*id + 1, s);
} }
s = find_branch_start(2*id + 1);
found = find_branch_candidate(s, e.dep(), e.rs(), e.ls());
insert_branch_start(2*id + 1, s);
return found; return found;
} }
@ -1173,7 +1174,7 @@ bool theory_seq::find_branch_candidate(unsigned& start, dependency* dep, expr_re
expr_ref v0(m); expr_ref v0(m);
v0 = m_util.str.mk_empty(m.get_sort(l)); v0 = m_util.str.mk_empty(m.get_sort(l));
if (can_be_equal(ls.size() - 1, ls.c_ptr() + 1, rs.size(), rs.c_ptr())) { if (can_be_equal(ls.size() - 1, ls.c_ptr() + 1, rs.size(), rs.c_ptr())) {
if (l_false != assume_equality(l, v0)) { if (assume_equality(l, v0)) {
TRACE("seq", tout << mk_pp(l, m) << " " << v0 << "\n";); TRACE("seq", tout << mk_pp(l, m) << " " << v0 << "\n";);
return true; return true;
} }
@ -1189,7 +1190,7 @@ bool theory_seq::find_branch_candidate(unsigned& start, dependency* dep, expr_re
continue; continue;
} }
v0 = mk_concat(j + 1, rs.c_ptr()); v0 = mk_concat(j + 1, rs.c_ptr());
if (l_false != assume_equality(l, v0)) { if (assume_equality(l, v0)) {
TRACE("seq", tout << mk_pp(l, m) << " " << v0 << "\n";); TRACE("seq", tout << mk_pp(l, m) << " " << v0 << "\n";);
++start; ++start;
return true; return true;
@ -1212,7 +1213,7 @@ bool theory_seq::find_branch_candidate(unsigned& start, dependency* dep, expr_re
for (literal lit : lits) { for (literal lit : lits) {
switch (ctx.get_assignment(lit)) { switch (ctx.get_assignment(lit)) {
case l_true: break; case l_true: break;
case l_false: start = 0; return true; case l_false: start = 0; return false;
case l_undef: ctx.mark_as_relevant(lit); ctx.force_phase(~lit); start = 0; return true; case l_undef: ctx.mark_as_relevant(lit); ctx.force_phase(~lit); start = 0; return true;
} }
} }
@ -1253,42 +1254,39 @@ bool theory_seq::can_be_equal(unsigned szl, expr* const* ls, unsigned szr, expr*
} }
lbool theory_seq::assume_equality(expr* l, expr* r) { bool theory_seq::assume_equality(expr* l, expr* r) {
if (m_exclude.contains(l, r)) { if (m_exclude.contains(l, r)) {
return l_false; return false;
} }
expr_ref eq(m.mk_eq(l, r), m); expr_ref eq(m.mk_eq(l, r), m);
m_rewrite(eq); m_rewrite(eq);
if (m.is_true(eq)) { if (m.is_true(eq)) {
return l_true; return false;
} }
if (m.is_false(eq)) { if (m.is_false(eq)) {
return l_false; return false;
} }
enode* n1 = ensure_enode(l); enode* n1 = ensure_enode(l);
enode* n2 = ensure_enode(r); enode* n2 = ensure_enode(r);
if (n1->get_root() == n2->get_root()) { if (n1->get_root() == n2->get_root()) {
TRACE("seq", tout << mk_pp(l, m) << " = " << mk_pp(r, m) << " roots eq\n";); TRACE("seq", tout << mk_pp(l, m) << " = " << mk_pp(r, m) << " roots eq\n";);
return l_true; return false;
} }
if (ctx.is_diseq(n1, n2)) { if (ctx.is_diseq(n1, n2)) {
TRACE("seq", tout << mk_pp(l, m) << " = " << mk_pp(r, m) << " is_diseq\n";); TRACE("seq", tout << mk_pp(l, m) << " = " << mk_pp(r, m) << " is_diseq\n";);
return l_false; return false;
}
if (false && ctx.is_diseq_slow(n1, n2)) {
return l_false;
} }
ctx.mark_as_relevant(n1); ctx.mark_as_relevant(n1);
ctx.mark_as_relevant(n2); ctx.mark_as_relevant(n2);
if (!ctx.assume_eq(n1, n2)) { if (!ctx.assume_eq(n1, n2)) {
TRACE("seq", tout << mk_pp(l, m) << " = " << mk_pp(r, m) << " can't assume\n";); TRACE("seq", tout << mk_pp(l, m) << " = " << mk_pp(r, m) << " can't assume\n";);
return l_false; return false;
} }
lbool res = ctx.get_assignment(mk_eq(l, r, false)); lbool res = ctx.get_assignment(mk_eq(l, r, false));
TRACE("seq", tout << mk_pp(l, m) << " = " << mk_pp(r, m) << " literal assigned " << res << "\n";); TRACE("seq", tout << mk_pp(l, m) << " = " << mk_pp(r, m) << " literal assigned " << res << "\n";);
return res; return res != l_false;
} }
@ -1363,14 +1361,9 @@ bool theory_seq::check_length_coherence(expr* e) {
bool theory_seq::check_length_coherence0(expr* e) { bool theory_seq::check_length_coherence0(expr* e) {
if (is_var(e) && m_rep.is_root(e)) { if (is_var(e) && m_rep.is_root(e)) {
expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m); expr_ref emp(m_util.str.mk_empty(m.get_sort(e)), m);
lbool r = l_false;
bool p = propagate_length_coherence(e); bool p = propagate_length_coherence(e);
if (!p) { if (p || assume_equality(e, emp)) {
r = assume_equality(e, emp);
}
if (p || r != l_false) {
if (!ctx.at_base_level()) { if (!ctx.at_base_level()) {
m_trail_stack.push(push_replay(alloc(replay_length_coherence, m, e))); m_trail_stack.push(push_replay(alloc(replay_length_coherence, m, e)));
} }

View file

@ -53,6 +53,7 @@ bool theory_seq::check_ne_literals(unsigned idx, unsigned& num_undef_lits) {
TRACE("seq", display_disequation(tout << "has false literal\n", n); TRACE("seq", display_disequation(tout << "has false literal\n", n);
ctx.display_literal_verbose(tout, lit); ctx.display_literal_verbose(tout, lit);
tout << "\n" << lit << " " << ctx.is_relevant(lit) << "\n"; tout << "\n" << lit << " " << ctx.is_relevant(lit) << "\n";
display(tout);
); );
return false; return false;
case l_true: case l_true:
@ -132,6 +133,13 @@ bool theory_seq::propagate_ne2eq(unsigned idx) {
bool theory_seq::propagate_ne2eq(unsigned idx, expr_ref_vector const& es) { bool theory_seq::propagate_ne2eq(unsigned idx, expr_ref_vector const& es) {
if (es.empty()) if (es.empty())
return false; return false;
for (expr* e : es) {
expr_ref len_e = mk_len(e);
rational lo;
if (lower_bound(len_e, lo) && lo > 0) {
return true;
}
}
ne const& n = m_nqs[idx]; ne const& n = m_nqs[idx];
expr_ref e(m), head(m), tail(m); expr_ref e(m), head(m), tail(m);
e = mk_concat(es, m.get_sort(es[0])); e = mk_concat(es, m.get_sort(es[0]));
@ -220,10 +228,8 @@ bool theory_seq::reduce_ne(unsigned idx) {
} }
} }
TRACE("seq", display_disequation(tout << "updated: " << updated << "\n", n););
if (updated) { if (updated) {
TRACE("seq", display_disequation(tout, n););
m_nqs.set(idx, ne(n.l(), n.r(), new_eqs, new_lits, new_deps)); m_nqs.set(idx, ne(n.l(), n.r(), new_eqs, new_lits, new_deps));
TRACE("seq", display_disequation(tout << "updated:\n", m_nqs[idx]);); TRACE("seq", display_disequation(tout << "updated:\n", m_nqs[idx]););
} }

View file

@ -4560,7 +4560,6 @@ namespace smt {
pop_to_search_lvl(); pop_to_search_lvl();
if (m.is_bool(e)) { if (m.is_bool(e)) {
if (b_internalized(e)) { if (b_internalized(e)) {
bool_var v = get_bool_var(e);
switch (get_assignment(get_bool_var(e))) { switch (get_assignment(get_bool_var(e))) {
case l_true: e = m.mk_true(); break; case l_true: e = m.mk_true(); break;
case l_false: e = m.mk_false(); break; case l_false: e = m.mk_false(); break;

View file

@ -110,32 +110,6 @@ Outline:
using namespace smt; using namespace smt;
struct display_expr {
ast_manager& m;
display_expr(ast_manager& m): m(m) {}
std::ostream& display(std::ostream& out, sym_expr* e) const {
return e->display(out);
}
};
class seq_expr_solver : public expr_solver {
kernel m_kernel;
public:
seq_expr_solver(ast_manager& m, smt_params& fp):
m_kernel(m, fp)
{}
lbool check_sat(expr* e) override {
m_kernel.push();
m_kernel.assert_expr(e);
lbool r = m_kernel.check();
m_kernel.pop(1);
IF_VERBOSE(11, verbose_stream() << "is " << r << " " << mk_pp(e, m_kernel.m()) << "\n");
return r;
}
};
void theory_seq::solution_map::update(expr* e, expr* r, dependency* d) { void theory_seq::solution_map::update(expr* e, expr* r, dependency* d) {
if (e == r) { if (e == r) {
return; return;
@ -332,7 +306,7 @@ void theory_seq::init() {
m_arith_value.init(&ctx); m_arith_value.init(&ctx);
} }
#define TRACEFIN(s) { TRACE("seq", tout << ">>" << s << "\n";); IF_VERBOSE(31, verbose_stream() << s << "\n"); } #define TRACEFIN(s) { TRACE("seq", tout << ">>" << s << "\n";); IF_VERBOSE(20, verbose_stream() << s << "\n"); }
struct scoped_enable_trace { struct scoped_enable_trace {
scoped_enable_trace() { scoped_enable_trace() {

View file

@ -431,7 +431,7 @@ namespace smt {
bool check_length_coherence(expr* e); bool check_length_coherence(expr* e);
bool fixed_length(bool is_zero = false); bool fixed_length(bool is_zero = false);
bool fixed_length(expr* e, bool is_zero); bool fixed_length(expr* e, bool is_zero);
void branch_unit_variable(dependency* dep, expr* X, expr_ref_vector const& units); bool branch_unit_variable(dependency* dep, expr* X, expr_ref_vector const& units);
bool branch_variable_eq(eq const& e); bool branch_variable_eq(eq const& e);
bool branch_binary_variable(eq const& e); bool branch_binary_variable(eq const& e);
bool can_align_from_lhs(expr_ref_vector const& ls, expr_ref_vector const& rs); bool can_align_from_lhs(expr_ref_vector const& ls, expr_ref_vector const& rs);
@ -536,7 +536,7 @@ namespace smt {
bool find_branch_candidate(unsigned& start, dependency* dep, expr_ref_vector const& ls, expr_ref_vector const& rs); bool find_branch_candidate(unsigned& start, dependency* dep, expr_ref_vector const& ls, expr_ref_vector const& rs);
expr_ref_vector expand_strings(expr_ref_vector const& es); expr_ref_vector expand_strings(expr_ref_vector const& es);
bool can_be_equal(unsigned szl, expr* const* ls, unsigned szr, expr* const* rs) const; bool can_be_equal(unsigned szl, expr* const* ls, unsigned szr, expr* const* rs) const;
lbool assume_equality(expr* l, expr* r); bool assume_equality(expr* l, expr* r);
// variable solving utilities // variable solving utilities
bool occurs(expr* a, expr* b); bool occurs(expr* a, expr* b);