3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-29 06:28:57 +00:00

enable theory propagation of regex accept condition

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2020-06-17 13:42:40 -07:00
parent be36a8fd80
commit 3b1149330d
4 changed files with 51 additions and 10 deletions

View file

@ -1325,6 +1325,8 @@ unsigned seq_util::re::min_length(expr* r) const {
return std::max(min_length(r1), min_length(r2)); return std::max(min_length(r1), min_length(r2));
if (is_loop(r, r1, lo, hi)) if (is_loop(r, r1, lo, hi))
return u.max_mul(lo, min_length(r1)); return u.max_mul(lo, min_length(r1));
if (is_range(r))
return 1;
if (is_to_re(r, s)) if (is_to_re(r, s))
return u.str.min_length(s); return u.str.min_length(s);
return 0; return 0;

View file

@ -35,13 +35,30 @@ namespace smt {
arith_util& seq_regex::a() { return th.m_autil; } arith_util& seq_regex::a() { return th.m_autil; }
void seq_regex::rewrite(expr_ref& e) { th.m_rewrite(e); } void seq_regex::rewrite(expr_ref& e) { th.m_rewrite(e); }
bool seq_regex::can_propagate() const {
for (auto const& p : m_to_propagate) {
literal trigger = p.m_trigger;
if (trigger == null_literal || ctx.get_assignment(trigger) != l_undef)
return true;
}
return false;
}
bool seq_regex::propagate() { bool seq_regex::propagate() {
bool change = false; bool change = false;
for (unsigned i = 0; !ctx.inconsistent() && i < m_to_propagate.size(); ++i) { for (unsigned i = 0; !ctx.inconsistent() && i < m_to_propagate.size(); ++i) {
if (propagate(m_to_propagate[i])) { propagation_lit const& pl = m_to_propagate[i];
literal trigger = pl.m_trigger;
if (trigger != null_literal && ctx.get_assignment(trigger) == l_undef)
continue;
if (propagate(pl.m_lit, trigger)) {
m_to_propagate.erase_and_swap(i--); m_to_propagate.erase_and_swap(i--);
change = true; change = true;
} }
else if (trigger != pl.m_trigger) {
m_to_propagate.set(i, propagation_lit(pl.m_lit, trigger));
}
} }
return change; return change;
} }
@ -148,8 +165,10 @@ namespace smt {
} }
void seq_regex::propagate_accept(literal lit) { void seq_regex::propagate_accept(literal lit) {
if (!propagate(lit)) // std::cout << "PA ";
m_to_propagate.push_back(lit); literal t = null_literal;
if (!propagate(lit, t))
m_to_propagate.push_back(propagation_lit(lit, t));
} }
/** /**
@ -165,7 +184,7 @@ namespace smt {
* (accept s i r) & len(s) > i => (accept s (+ i 1) D(nth(s,i), r)) * (accept s i r) & len(s) > i => (accept s (+ i 1) D(nth(s,i), r))
*/ */
bool seq_regex::propagate(literal lit) { bool seq_regex::propagate(literal lit, literal& trigger) {
SASSERT(!lit.sign()); SASSERT(!lit.sign());
expr* s = nullptr, *i = nullptr, *r = nullptr; expr* s = nullptr, *i = nullptr, *r = nullptr;
@ -173,6 +192,8 @@ namespace smt {
unsigned idx = 0; unsigned idx = 0;
VERIFY(sk().is_accept(e, s, i, idx, r)); VERIFY(sk().is_accept(e, s, i, idx, r));
// std::cout << "\nP " << idx << " " << r->get_id() << " ";
TRACE("seq", tout << "propagate " << mk_pp(e, m) << "\n";); TRACE("seq", tout << "propagate " << mk_pp(e, m) << "\n";);
if (re().is_empty(r)) { if (re().is_empty(r)) {
@ -185,7 +206,7 @@ namespace smt {
propagate_nullable(lit, s, idx, r); propagate_nullable(lit, s, idx, r);
return propagate_derivative(lit, e, s, i, idx, r); return propagate_derivative(lit, e, s, i, idx, r, trigger);
} }
/** /**
@ -208,6 +229,7 @@ namespace smt {
*/ */
void seq_regex::propagate_nullable(literal lit, expr* s, unsigned idx, expr* r) { void seq_regex::propagate_nullable(literal lit, expr* s, unsigned idx, expr* r) {
// std::cout << "PN ";
expr_ref is_nullable = seq_rw().is_nullable(r); expr_ref is_nullable = seq_rw().is_nullable(r);
rewrite(is_nullable); rewrite(is_nullable);
literal len_s_ge_i = th.m_ax.mk_ge(th.mk_len(s), idx); literal len_s_ge_i = th.m_ax.mk_ge(th.mk_len(s), idx);
@ -216,6 +238,8 @@ namespace smt {
} }
else if (m.is_false(is_nullable)) { else if (m.is_false(is_nullable)) {
th.propagate_lit(nullptr, 1, &lit, th.m_ax.mk_ge(th.mk_len(s), idx + 1)); th.propagate_lit(nullptr, 1, &lit, th.m_ax.mk_ge(th.mk_len(s), idx + 1));
//unsigned len = std::max(1u, re().min_length(r));
//th.propagate_lit(nullptr, 1, &lit, th.m_ax.mk_ge(th.mk_len(s), idx + re().min_length(r)));
} }
else { else {
literal is_nullable_lit = th.mk_literal(is_nullable); literal is_nullable_lit = th.mk_literal(is_nullable);
@ -237,8 +261,9 @@ namespace smt {
} }
} }
bool seq_regex::propagate_derivative(literal lit, expr* e, expr* s, expr* i, unsigned idx, expr* r) { bool seq_regex::propagate_derivative(literal lit, expr* e, expr* s, expr* i, unsigned idx, expr* r, literal& trigger) {
// (accept s i R) & len(s) > i => (accept s (+ i 1) D(nth(s, i), R)) or conds // (accept s i R) & len(s) > i => (accept s (+ i 1) D(nth(s, i), R)) or conds
// std::cout << "PD ";
expr_ref d(m); expr_ref d(m);
expr_ref head = th.mk_nth(s, i); expr_ref head = th.mk_nth(s, i);
@ -271,6 +296,7 @@ namespace smt {
case l_undef: case l_undef:
#if 1 #if 1
ctx.mark_as_relevant(lcond); ctx.mark_as_relevant(lcond);
trigger = lcond;
return false; return false;
#else #else
if (re().is_empty(tt)) { if (re().is_empty(tt)) {
@ -303,6 +329,7 @@ namespace smt {
conds.push_back(th.mk_literal(sk().mk_accept(s, a().mk_int(idx + 1), d))); conds.push_back(th.mk_literal(sk().mk_accept(s, a().mk_int(idx + 1), d)));
th.add_axiom(conds); th.add_axiom(conds);
TRACE("seq", tout << "unfold " << head << "\n" << mk_pp(r, m) << "\n";); TRACE("seq", tout << "unfold " << head << "\n" << mk_pp(r, m) << "\n";);
// std::cout << "D ";
return true; return true;
} }

View file

@ -36,11 +36,19 @@ namespace smt {
m_lit(l), m_s(s), m_re(r), m_active(true) {} m_lit(l), m_s(s), m_re(r), m_active(true) {}
}; };
struct propagation_lit {
literal m_lit;
literal m_trigger;
propagation_lit(literal lit, literal t): m_lit(lit), m_trigger(t) {}
propagation_lit(literal lit): m_lit(lit), m_trigger(null_literal) {}
propagation_lit(): m_lit(null_literal), m_trigger(null_literal) {}
};
theory_seq& th; theory_seq& th;
context& ctx; context& ctx;
ast_manager& m; ast_manager& m;
vector<s_in_re> m_s_in_re; vector<s_in_re> m_s_in_re;
scoped_vector<literal> m_to_propagate; scoped_vector<propagation_lit> m_to_propagate;
seq_util& u(); seq_util& u();
class seq_util::re& re(); class seq_util::re& re();
@ -55,13 +63,13 @@ namespace smt {
bool coallesce_in_re(literal lit); bool coallesce_in_re(literal lit);
bool propagate(literal lit); bool propagate(literal lit, literal& trigger);
bool block_unfolding(literal lit, unsigned i); bool block_unfolding(literal lit, unsigned i);
void propagate_nullable(literal lit, expr* s, unsigned idx, expr* r); void propagate_nullable(literal lit, expr* s, unsigned idx, expr* r);
bool propagate_derivative(literal lit, expr* e, expr* s, expr* i, unsigned idx, expr* r); bool propagate_derivative(literal lit, expr* e, expr* s, expr* i, unsigned idx, expr* r, literal& trigger);
expr_ref mk_first(expr* r); expr_ref mk_first(expr* r);
@ -88,6 +96,8 @@ namespace smt {
void pop_scope(unsigned num_scopes) { m_to_propagate.pop_scope(num_scopes); } void pop_scope(unsigned num_scopes) { m_to_propagate.pop_scope(num_scopes); }
bool can_propagate() const;
bool propagate(); bool propagate();
void propagate_in_re(literal lit); void propagate_in_re(literal lit);

View file

@ -2525,6 +2525,8 @@ void theory_seq::add_dependency(dependency*& dep, enode* a, enode* b) {
void theory_seq::propagate() { void theory_seq::propagate() {
if (ctx.get_fparams().m_seq_use_unicode) if (ctx.get_fparams().m_seq_use_unicode)
m_unicode.propagate(); m_unicode.propagate();
if (ctx.get_fparams().m_seq_use_derivatives && m_regex.can_propagate())
m_regex.propagate();
while (m_axioms_head < m_axioms.size() && !ctx.inconsistent()) { while (m_axioms_head < m_axioms.size() && !ctx.inconsistent()) {
expr_ref e(m); expr_ref e(m);
e = m_axioms[m_axioms_head].get(); e = m_axioms[m_axioms_head].get();