3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-10 19:27:06 +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

@ -2278,6 +2278,13 @@ expr_ref seq_rewriter::derivative(expr* elem, expr* r) {
result = array.mk_select(2, args);
result = kleene_predicate(result, seq_sort);
}
else if (m().is_ite(r, p, r1, r2)) {
dr1 = derivative(elem, r1);
dr2 = derivative(elem, r2);
if (dr1 && dr2) {
result = m().mk_ite(p, dr1, dr2);
}
}
return result;
}

View file

@ -1220,6 +1220,44 @@ app* seq_util::str::mk_is_empty(expr* s) const {
return m.mk_eq(s, mk_empty(get_sort(s)));
}
unsigned seq_util::str::min_length(expr* s) const {
SASSERT(u.is_seq(s));
expr_ref_vector es(m);
unsigned result = 0;
get_concat_units(s, es);
for (expr* arg : es) {
if (is_unit(arg))
result++;
}
return result;
}
unsigned seq_util::re::min_length(expr* r) const {
SASSERT(u.is_re(r));
expr* r1 = nullptr, *r2 = nullptr, *s = nullptr;
if (is_empty(r))
return UINT_MAX;
if (is_concat(r, r1, r2)) {
unsigned l1 = min_length(r1);
if (l1 == UINT_MAX)
return l1;
unsigned l2 = min_length(r2);
if (l2 == UINT_MAX)
return l2;
return l1 + l2;
}
if (m.is_ite(r, s, r1, r2))
return std::min(min_length(r1), min_length(r2));
if (is_diff(r, r1, r2))
return min_length(r1);
if (is_union(r, r1, r2))
return std::min(min_length(r1), min_length(r2));
if (is_intersection(r, r1, r2))
return std::max(min_length(r1), min_length(r2));
if (is_to_re(r, s))
return u.str.min_length(s);
return 0;
}
sort* seq_util::re::to_seq(sort* re) {
(void)u;

View file

@ -394,6 +394,8 @@ public:
void get_concat_units(expr* e, expr_ref_vector& es) const;
expr* get_leftmost_concat(expr* e) const { expr* e1, *e2; while (is_concat(e, e1, e2)) e = e1; return e; }
expr* get_rightmost_concat(expr* e) const { expr* e1, *e2; while (is_concat(e, e1, e2)) e = e2; return e; }
unsigned min_length(expr* s) const;
};
class re {
@ -456,6 +458,7 @@ public:
bool is_loop(expr const* n, expr*& body, unsigned& lo);
bool is_loop(expr const* n, expr*& body, expr*& lo, expr*& hi);
bool is_loop(expr const* n, expr*& body, expr*& lo);
unsigned min_length(expr* r) const;
};
str str;
re re;

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 &&

View file

@ -61,6 +61,8 @@ namespace smt {
expr_ref unroll_non_empty(expr* r, expr_mark& seen, unsigned depth);
bool unfold_cofactors(expr_ref& r, literal_vector& conds);
public:
seq_regex(theory_seq& th);

View file

@ -3493,8 +3493,10 @@ bool theory_seq::should_research(expr_ref_vector & unsat_core) {
}
if (k_min < UINT_MAX) {
m_max_unfolding_depth++;
IF_VERBOSE(1, verbose_stream() << "(smt.seq :increase-length " << mk_pp(s_min, m) << " " << 2*k_min << ")\n");
add_length_limit(s_min, 2*k_min, false);
k_min *= 2;
k_min = std::max(m_util.str.min_length(s_min), k_min);
IF_VERBOSE(1, verbose_stream() << "(smt.seq :increase-length " << mk_pp(s_min, m) << " " << k_min << ")\n");
add_length_limit(s_min, k_min, false);
return true;
}
else if (has_max_unfolding) {