mirror of
https://github.com/Z3Prover/z3
synced 2025-04-12 04:03:39 +00:00
updated rewrite rules to propagate nullability over nonground regexes (#4663)
* updated rewrite rules to propagate nullability over nonground regexes * updated rewrite rules to propagate nullability over nonground regexes * fixed incorrect rewrite status flag
This commit is contained in:
parent
ab10616b77
commit
78b88f761c
|
@ -2265,7 +2265,7 @@ expr_ref seq_rewriter::is_nullable_rec(expr* r) {
|
||||||
result = m().mk_ite(cond, is_nullable(r1), is_nullable(r2));
|
result = m().mk_ite(cond, is_nullable(r1), is_nullable(r2));
|
||||||
}
|
}
|
||||||
else if (m_util.is_re(r, seq_sort)) {
|
else if (m_util.is_re(r, seq_sort)) {
|
||||||
result = re().mk_in_re(str().mk_empty(seq_sort), r);
|
result = is_nullable_symbolic_regex(r, seq_sort);
|
||||||
}
|
}
|
||||||
else if (str().is_concat(r, r1, r2)) {
|
else if (str().is_concat(r, r1, r2)) {
|
||||||
m_br.mk_and(is_nullable(r1), is_nullable(r2), result);
|
m_br.mk_and(is_nullable(r1), is_nullable(r2), result);
|
||||||
|
@ -2286,6 +2286,31 @@ expr_ref seq_rewriter::is_nullable_rec(expr* r) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expr_ref seq_rewriter::is_nullable_symbolic_regex(expr* r, sort* seq_sort) {
|
||||||
|
SASSERT(m_util.is_re(r));
|
||||||
|
expr* elem = nullptr, * r2 = nullptr, * s = nullptr;
|
||||||
|
expr_ref elems(str().mk_empty(seq_sort), m());
|
||||||
|
expr_ref result(m());
|
||||||
|
while (re().is_derivative(r, elem, r2)) {
|
||||||
|
if (str().is_empty(elems))
|
||||||
|
elems = str().mk_unit(elem);
|
||||||
|
else
|
||||||
|
elems = str().mk_concat(str().mk_unit(elem), elems);
|
||||||
|
r = r2;
|
||||||
|
}
|
||||||
|
if (re().is_to_re(r, s)) {
|
||||||
|
// r is nullable
|
||||||
|
// iff after taking the derivatives the remaining sequence is empty
|
||||||
|
// iff the inner sequence equals to the sequence of derivative elements in reverse
|
||||||
|
result = m().mk_eq(elems, s);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// the default case when either r is not a derivative
|
||||||
|
// or when the nested derivatives are not applied to a sequence
|
||||||
|
result = re().mk_in_re(str().mk_empty(seq_sort), r);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Push reverse inwards (whenever possible).
|
Push reverse inwards (whenever possible).
|
||||||
*/
|
*/
|
||||||
|
@ -3203,6 +3228,11 @@ Disabled rewrite:
|
||||||
disjunctions that cover cases where s overlaps given that "ab" does
|
disjunctions that cover cases where s overlaps given that "ab" does
|
||||||
not overlap with any of the sequences.
|
not overlap with any of the sequences.
|
||||||
It is disabled because the solver doesn't handle disjunctions of regexes well.
|
It is disabled because the solver doesn't handle disjunctions of regexes well.
|
||||||
|
|
||||||
|
TBD:
|
||||||
|
Enable rewrite when R = R1|R2 and derivative cannot make progress: 's in R' ==> 's in R1' | 's in R2'
|
||||||
|
cannot make progress here means that R1 or R2 starts with an uninterpreted symbol
|
||||||
|
This will help propagate cases like "abc"X in opt(to_re(X)) to equalities.
|
||||||
*/
|
*/
|
||||||
br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) {
|
br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) {
|
||||||
|
|
||||||
|
@ -3222,6 +3252,16 @@ br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) {
|
||||||
result = m_br.mk_eq_rw(a, b1);
|
result = m_br.mk_eq_rw(a, b1);
|
||||||
return BR_REWRITE1;
|
return BR_REWRITE1;
|
||||||
}
|
}
|
||||||
|
expr* eps = nullptr;
|
||||||
|
if (re().is_opt(b, b1) ||
|
||||||
|
(re().is_union(b, b1, eps) && re().is_epsilon(eps)) ||
|
||||||
|
(re().is_union(b, eps, b1) && re().is_epsilon(eps)))
|
||||||
|
{
|
||||||
|
result = m().mk_ite(m().mk_eq(str().mk_length(a), m_autil.mk_int(0)),
|
||||||
|
m().mk_true(),
|
||||||
|
re().mk_in_re(a, b1));
|
||||||
|
return BR_REWRITE_FULL;
|
||||||
|
}
|
||||||
if (str().is_empty(a)) {
|
if (str().is_empty(a)) {
|
||||||
result = is_nullable(b);
|
result = is_nullable(b);
|
||||||
if (str().is_in_re(result))
|
if (str().is_in_re(result))
|
||||||
|
|
|
@ -193,6 +193,8 @@ class seq_rewriter {
|
||||||
expr_ref mk_der_cond(expr* cond, expr* ele, sort* seq_sort);
|
expr_ref mk_der_cond(expr* cond, expr* ele, sort* seq_sort);
|
||||||
expr_ref mk_der_antimorov_union(expr* r1, expr* r2);
|
expr_ref mk_der_antimorov_union(expr* r1, expr* r2);
|
||||||
bool ite_bdds_compatabile(expr* a, expr* b);
|
bool ite_bdds_compatabile(expr* a, expr* b);
|
||||||
|
/* if r has the form deriv(en..deriv(e1,to_re(s))..) returns 's = [e1..en]' else returns '() in r'*/
|
||||||
|
expr_ref is_nullable_symbolic_regex(expr* r, sort* seq_sort);
|
||||||
#ifdef Z3DEBUG
|
#ifdef Z3DEBUG
|
||||||
bool check_deriv_normal_form(expr* r, int level = 3);
|
bool check_deriv_normal_form(expr* r, int level = 3);
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue