mirror of
https://github.com/Z3Prover/z3
synced 2025-04-22 16:45:31 +00:00
inline conditions with derivative computation
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
a32fabf5ee
commit
4dbf7b183d
2 changed files with 145 additions and 66 deletions
|
@ -2304,7 +2304,110 @@ br_status seq_rewriter::mk_re_reverse(expr* r, expr_ref& result) {
|
|||
Symbolic derivative: seq -> regex -> regex
|
||||
seq should be single char
|
||||
*/
|
||||
|
||||
br_status seq_rewriter::mk_re_derivative(expr* ele, expr* r, expr_ref& result) {
|
||||
result = mk_derivative(ele, r);
|
||||
// TBD: we may even declare BR_DONE here and potentially miss some simplifications
|
||||
return re().is_derivative(result) ? BR_DONE : BR_REWRITE_FULL;
|
||||
}
|
||||
|
||||
expr_ref seq_rewriter::mk_derivative(expr* ele, expr* r) {
|
||||
expr_ref result(m_op_cache.find(OP_RE_DERIVATIVE, ele, r), m());
|
||||
if (!result) {
|
||||
result = mk_derivative_rec(ele, r);
|
||||
m_op_cache.insert(OP_RE_DERIVATIVE, ele, r, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
expr_ref seq_rewriter::mk_der_union(expr* r1, expr* r2) {
|
||||
return mk_der_op(OP_RE_UNION, r1, r2);
|
||||
}
|
||||
|
||||
expr_ref seq_rewriter::mk_der_inter(expr* r1, expr* r2) {
|
||||
return mk_der_op(OP_RE_INTERSECT, r1, r2);
|
||||
}
|
||||
|
||||
expr_ref seq_rewriter::mk_der_concat(expr* r1, expr* r2) {
|
||||
return mk_der_op(OP_RE_CONCAT, r1, r2);
|
||||
}
|
||||
|
||||
expr_ref seq_rewriter::mk_der_op_rec(decl_kind k, expr* a, expr* b) {
|
||||
expr* ca = nullptr, *a1 = nullptr, *a2 = nullptr;
|
||||
expr* cb = nullptr, *b1 = nullptr, *b2 = nullptr;
|
||||
expr_ref result(m());
|
||||
if (m().is_ite(a, ca, a1, a2)) {
|
||||
if (m().is_ite(b, cb, b1, b2)) {
|
||||
if (ca == cb) {
|
||||
expr_ref r1 = mk_der_op(k, a1, b1);
|
||||
expr_ref r2 = mk_der_op(k, a2, b2);
|
||||
result = m().mk_ite(ca, r1, r2);
|
||||
return result;
|
||||
}
|
||||
else if (ca->get_id() < cb->get_id()) {
|
||||
expr_ref r1 = mk_der_op(k, a, b1);
|
||||
expr_ref r2 = mk_der_op(k, a, b2);
|
||||
result = m().mk_ite(cb, r1, r2);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
expr_ref r1 = mk_der_op(k, a1, b);
|
||||
expr_ref r2 = mk_der_op(k, a2, b);
|
||||
result = m().mk_ite(ca, r1, r2);
|
||||
return result;
|
||||
}
|
||||
if (m().is_ite(b, cb, b1, b2)) {
|
||||
expr_ref r1 = mk_der_op(k, a, b1);
|
||||
expr_ref r2 = mk_der_op(k, a, b2);
|
||||
result = m().mk_ite(cb, r1, r2);
|
||||
return result;
|
||||
}
|
||||
switch (k) {
|
||||
case OP_RE_INTERSECT:
|
||||
if (BR_FAILED == mk_re_inter(a, b, result))
|
||||
result = re().mk_inter(a, b);
|
||||
break;
|
||||
case OP_RE_UNION:
|
||||
if (BR_FAILED == mk_re_union(a, b, result))
|
||||
result = re().mk_union(a, b);
|
||||
break;
|
||||
case OP_RE_CONCAT:
|
||||
if (BR_FAILED == mk_re_concat(a, b, result))
|
||||
result = re().mk_concat(a, b);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
expr_ref seq_rewriter::mk_der_op(decl_kind k, expr* a, expr* b) {
|
||||
expr_ref _a(a, m()), _b(b, m());
|
||||
expr_ref result(m_op_cache.find(k, a, b), m());
|
||||
if (!result) {
|
||||
result = mk_der_op_rec(k, a, b);
|
||||
m_op_cache.insert(k, a, b, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
expr_ref seq_rewriter::mk_der_compl(expr* r) {
|
||||
expr_ref result(m_op_cache.find(OP_RE_COMPLEMENT, r, nullptr), m());
|
||||
if (!result) {
|
||||
expr* c = nullptr, * r1 = nullptr, * r2 = nullptr;
|
||||
if (m().is_ite(r, c, r1, r2)) {
|
||||
result = m().mk_ite(c, mk_der_compl(r1), mk_der_compl(r2));
|
||||
}
|
||||
else if (BR_FAILED == mk_re_complement(r, result))
|
||||
result = re().mk_complement(r);
|
||||
}
|
||||
m_op_cache.insert(OP_RE_COMPLEMENT, r, nullptr, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
expr_ref seq_rewriter::mk_derivative_rec(expr* ele, expr* r) {
|
||||
expr_ref result(m());
|
||||
sort* seq_sort = nullptr, *ele_sort = nullptr;
|
||||
VERIFY(m_util.is_re(r, seq_sort));
|
||||
VERIFY(m_util.is_seq(seq_sort, ele_sort));
|
||||
|
@ -2313,110 +2416,77 @@ br_status seq_rewriter::mk_re_derivative(expr* ele, expr* r, expr_ref& result) {
|
|||
unsigned lo = 0, hi = 0;
|
||||
if (re().is_concat(r, r1, r2)) {
|
||||
expr_ref is_n = is_nullable(r1);
|
||||
expr_ref dr1(re().mk_derivative(ele, r1), m());
|
||||
expr_ref dr2(re().mk_derivative(ele, r2), m());
|
||||
result = re().mk_concat(dr1, r2);
|
||||
expr_ref dr1 = mk_derivative(ele, r1);
|
||||
result = mk_der_concat(dr1, r2);
|
||||
if (m().is_false(is_n)) {
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
else if (m().is_true(is_n)) {
|
||||
result = re().mk_union(result, dr2);
|
||||
return BR_REWRITE3;
|
||||
}
|
||||
else {
|
||||
result = re().mk_union(result, re_and(is_n, dr2));
|
||||
return BR_REWRITE3;
|
||||
return result;
|
||||
}
|
||||
expr_ref dr2 = mk_derivative(ele, r2);
|
||||
return mk_der_union(result, re_and(is_n, dr2));
|
||||
}
|
||||
else if (re().is_star(r, r1)) {
|
||||
result = re().mk_concat(re().mk_derivative(ele, r1), r);
|
||||
return BR_REWRITE2;
|
||||
return mk_der_concat(mk_derivative(ele, r1), r);
|
||||
}
|
||||
else if (re().is_plus(r, r1)) {
|
||||
result = re().mk_derivative(ele, re().mk_star(r1));
|
||||
return BR_REWRITE1;
|
||||
expr_ref star(re().mk_star(r1), m());
|
||||
return mk_derivative(ele, star);
|
||||
}
|
||||
else if (re().is_union(r, r1, r2)) {
|
||||
result = re().mk_union(
|
||||
re().mk_derivative(ele, r1),
|
||||
re().mk_derivative(ele, r2)
|
||||
);
|
||||
return BR_REWRITE2;
|
||||
return mk_der_union(mk_derivative(ele, r1), mk_derivative(ele, r2));
|
||||
}
|
||||
else if (re().is_intersection(r, r1, r2)) {
|
||||
result = re().mk_inter(
|
||||
re().mk_derivative(ele, r1),
|
||||
re().mk_derivative(ele, r2)
|
||||
);
|
||||
return BR_REWRITE2;
|
||||
return mk_der_inter(mk_derivative(ele, r1), mk_derivative(ele, r2));
|
||||
}
|
||||
else if (re().is_diff(r, r1, r2)) {
|
||||
result = re().mk_diff(
|
||||
re().mk_derivative(ele, r1),
|
||||
re().mk_derivative(ele, r2)
|
||||
);
|
||||
return BR_REWRITE2;
|
||||
return mk_der_inter(mk_derivative(ele, r1), mk_der_compl(mk_derivative(ele, r2)));
|
||||
}
|
||||
else if (m().is_ite(r, p, r1, r2)) {
|
||||
result = m().mk_ite(
|
||||
p,
|
||||
re().mk_derivative(ele, r1),
|
||||
re().mk_derivative(ele, r2)
|
||||
);
|
||||
return BR_REWRITE2;
|
||||
// there is no BDD normalization here
|
||||
result = m().mk_ite(p, mk_derivative(ele, r1), mk_derivative(ele, r2));
|
||||
return result;
|
||||
}
|
||||
else if (re().is_opt(r, r1)) {
|
||||
result = re().mk_derivative(ele, r1);
|
||||
return BR_REWRITE1;
|
||||
return mk_derivative(ele, r1);
|
||||
}
|
||||
else if (re().is_complement(r, r1)) {
|
||||
result = re().mk_complement(re().mk_derivative(ele, r1));
|
||||
return BR_REWRITE2;
|
||||
return mk_der_compl(mk_derivative(ele, r1));
|
||||
}
|
||||
else if (re().is_loop(r, r1, lo)) {
|
||||
if (lo > 0) {
|
||||
lo--;
|
||||
}
|
||||
result = re().mk_concat(
|
||||
re().mk_derivative(ele, r1),
|
||||
re().mk_loop(r1, lo)
|
||||
);
|
||||
return BR_REWRITE2;
|
||||
return mk_der_concat(mk_derivative(ele, r1), re().mk_loop(r1, lo));
|
||||
}
|
||||
else if (re().is_loop(r, r1, lo, hi)) {
|
||||
if (hi == 0) {
|
||||
result = re().mk_empty(m().get_sort(r));
|
||||
return BR_DONE;
|
||||
return result;
|
||||
}
|
||||
hi--;
|
||||
if (lo > 0) {
|
||||
lo--;
|
||||
}
|
||||
result = re().mk_concat(
|
||||
re().mk_derivative(ele, r1),
|
||||
re().mk_loop(r1, lo, hi)
|
||||
);
|
||||
return BR_REWRITE2;
|
||||
return mk_der_concat(mk_derivative(ele, r1), re().mk_loop(r1, lo, hi));
|
||||
}
|
||||
else if (re().is_full_seq(r) ||
|
||||
re().is_empty(r)) {
|
||||
result = r;
|
||||
return BR_DONE;
|
||||
return result;
|
||||
}
|
||||
else if (re().is_to_re(r, r1)) {
|
||||
// r1 is a string here (not a regexp)
|
||||
expr_ref hd(m()), tl(m());
|
||||
if (get_head_tail(r1, hd, tl)) {
|
||||
// head must be equal; if so, derivative is tail
|
||||
result = re_and(m().mk_eq(ele, hd),re().mk_to_re(tl));
|
||||
return BR_REWRITE2;
|
||||
result = re_and(m().mk_eq(ele, hd), re().mk_to_re(tl));
|
||||
return result;
|
||||
}
|
||||
else if (str().is_empty(r1)) {
|
||||
result = re().mk_empty(m().get_sort(r));
|
||||
return BR_DONE;
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return BR_FAILED;
|
||||
return expr_ref(re().mk_derivative(ele, r), m());
|
||||
}
|
||||
}
|
||||
else if (re().is_reverse(r, r1) && re().is_to_re(r1, r2)) {
|
||||
|
@ -2429,14 +2499,14 @@ br_status seq_rewriter::mk_re_derivative(expr* ele, expr* r, expr_ref& result) {
|
|||
m().mk_eq(ele, tl),
|
||||
re().mk_reverse(re().mk_to_re(hd))
|
||||
);
|
||||
return BR_REWRITE3;
|
||||
return result;
|
||||
}
|
||||
else if (str().is_empty(r2)) {
|
||||
result = re().mk_empty(m().get_sort(r));
|
||||
return BR_DONE;
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return BR_FAILED;
|
||||
return expr_ref(re().mk_derivative(ele, r), m());
|
||||
}
|
||||
}
|
||||
else if (re().is_range(r, r1, r2)) {
|
||||
|
@ -2448,34 +2518,34 @@ br_status seq_rewriter::mk_re_derivative(expr* ele, expr* r, expr_ref& result) {
|
|||
r2 = m_util.mk_char(s2[0]);
|
||||
result = m().mk_and(m_util.mk_le(r1, ele), m_util.mk_le(ele, r2));
|
||||
result = re_predicate(result, seq_sort);
|
||||
return BR_REWRITE3;
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
result = re().mk_empty(m().get_sort(r));
|
||||
return BR_DONE;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
expr* e1 = nullptr, *e2 = nullptr;
|
||||
if (str().is_unit(r1, e1) && str().is_unit(r2, e2)) {
|
||||
result = m().mk_and(m_util.mk_le(e1, ele), m_util.mk_le(ele, e2));
|
||||
result = re_predicate(result, seq_sort);
|
||||
return BR_REWRITE2;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else if (re().is_full_char(r)) {
|
||||
result = re().mk_to_re(str().mk_empty(seq_sort));
|
||||
return BR_DONE;
|
||||
return result;
|
||||
}
|
||||
else if (re().is_of_pred(r, p)) {
|
||||
array_util array(m());
|
||||
expr* args[2] = { p, ele };
|
||||
result = array.mk_select(2, args);
|
||||
result = re_predicate(result, seq_sort);
|
||||
return BR_REWRITE2;
|
||||
return result;
|
||||
}
|
||||
// stuck cases: re().is_derivative, variable, ...
|
||||
// and re().is_reverse if the reverse is not applied to a string
|
||||
return BR_FAILED;
|
||||
return expr_ref(re().mk_derivative(ele, r), m());
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -180,6 +180,15 @@ class seq_rewriter {
|
|||
expr_ref re_predicate(expr* cond, sort* seq_sort);
|
||||
expr_ref mk_seq_concat(expr* a, expr* b);
|
||||
|
||||
expr_ref mk_der_op(decl_kind k, expr* a, expr* b);
|
||||
expr_ref mk_der_op_rec(decl_kind k, expr* a, expr* b);
|
||||
expr_ref mk_der_concat(expr* a, expr* b);
|
||||
expr_ref mk_der_union(expr* a, expr* b);
|
||||
expr_ref mk_der_inter(expr* a, expr* b);
|
||||
expr_ref mk_der_compl(expr* a);
|
||||
expr_ref mk_derivative(expr* ele, expr* r);
|
||||
expr_ref mk_derivative_rec(expr* ele, expr* r);
|
||||
|
||||
br_status mk_seq_unit(expr* e, expr_ref& result);
|
||||
br_status mk_seq_concat(expr* a, expr* b, expr_ref& result);
|
||||
br_status mk_seq_length(expr* a, expr_ref& result);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue