3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-07-18 02:16:40 +00:00

hoist co-factors eagerly without adding axioms

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2020-05-25 15:10:45 -07:00
parent e938ee33bb
commit a97bc65af4
6 changed files with 94 additions and 68 deletions

View file

@ -100,6 +100,32 @@ namespace smt {
m_to_propagate.push_back(lit);
}
// s in R[if(p,R1,R2)] & p => s in R[R1]
// s in R[if(p,R1,R2)] & ~p => s in R[R2]
bool seq_regex::unfold_cofactors(expr_ref& r, literal_vector& conds) {
expr_ref cond(m), tt(m), el(m);
while (seq_rw().has_cofactor(r, cond, tt, el)) {
rewrite(cond);
literal lcond = th.mk_literal(cond);
switch (ctx.get_assignment(lcond)) {
case l_true:
conds.push_back(~lcond);
r = tt;
break;
case l_false:
conds.push_back(lcond);
r = el;
break;
case l_undef:
ctx.mark_as_relevant(lcond);
return false;
}
rewrite(r);
}
return true;
}
/**
* Propagate the atom (accept s i r)
@ -144,79 +170,30 @@ namespace smt {
case l_false:
break;
}
// s in R[if(p,R1,R2)] & p => s in R[R1]
// s in R[if(p,R1,R2)] & ~p => s in R[R2]
// TBD combine the two places that perform co-factor rewriting
expr_ref cond(m), tt(m), el(m);
if (seq_rw().has_cofactor(r, cond, tt, el)) {
rewrite(cond);
literal lcond = th.mk_literal(cond), next_lit;
switch (ctx.get_assignment(lcond)) {
case l_true: {
rewrite(tt);
literal lits[2] = { lit, lcond };
next_lit = th.mk_literal(sk().mk_accept(s, i, tt));
th.propagate_lit(nullptr, 2, lits, next_lit);
return true;
}
case l_false: {
rewrite(el);
next_lit = th.mk_literal(sk().mk_accept(s, i, el));
literal lits[2] = { lit, ~lcond };
th.propagate_lit(nullptr, 2, lits, next_lit);
return true;
}
case l_undef:
ctx.mark_as_relevant(lcond);
return false;
}
}
expr_ref head(m), d(r, m), i_next(m);
literal_vector conds;
if (!unfold_cofactors(d, conds))
return false;
// s in R & len(s) > i => tail(s,i) in D(nth(s, i), R)
expr_ref head(m), d(m), i_next(m);
head = th.mk_nth(s, i);
i_next = a().mk_int(idx + 1);
d = seq_rw().derivative(head, r);
d = seq_rw().derivative(head, d);
if (!d)
throw default_exception("unable to expand derivative");
// immediately expand a co-factor here so that condition on the character
// is expanded.
literal_vector conds;
while (seq_rw().has_cofactor(d, cond, tt, el)) {
rewrite(cond);
literal lcond = th.mk_literal(cond);
bool is_undef = false;
switch (ctx.get_assignment(lcond)) {
case l_true:
conds.push_back(~lcond);
d = tt;
break;
case l_false:
conds.push_back(lcond);
d = el;
break;
case l_undef:
ctx.mark_as_relevant(lcond);
d = m.mk_ite(cond, tt, el);
is_undef = true;
break;
}
if (is_undef)
break;
rewrite(d);
}
literal acc_next = th.mk_literal(sk().mk_accept(s, i_next, d));
if (conds.empty()) {
th.add_axiom(~lit, len_s_le_i, th.mk_literal(sk().mk_accept(s, i_next, d)));
th.add_axiom(~lit, len_s_le_i, acc_next);
}
else {
conds.push_back(~lit);
conds.push_back(len_s_le_i);
conds.push_back(th.mk_literal(sk().mk_accept(s, i_next, d)));
for (literal lit : conds) ctx.mark_as_relevant(lit);
conds.push_back(acc_next);
for (literal c : conds)
ctx.mark_as_relevant(c);
ctx.mk_th_axiom(th.get_id(), conds.size(), conds.c_ptr());
}
TRACE("seq", tout << "head " << head << "\n";
@ -226,15 +203,12 @@ namespace smt {
/**
* Put a limit to the unfolding of s.
* TBD:
* Given an Regex R, we can compute the minimal length string accepted by R
* A strong analysis could compute the minimal length of s to be accepted by R
* For example if s = x + "abc" and R = .* ++ "def" . .**, then minimal length
* of s is 6.
* Limiting the depth of unfolding s below such lengths is not useful.
*/
bool seq_regex::block_unfolding(literal lit, unsigned i) {
expr* s = nullptr, *idx = nullptr, *r = nullptr;
expr* e = ctx.bool_var2expr(lit.var());
VERIFY(sk().is_accept(e, s, idx, r));
expr* t = nullptr;
if (i > th.m_max_unfolding_depth &&
th.m_max_unfolding_lit != null_literal &&