3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-10 19:27:06 +00:00

string to regex approximation used to strengthen membership constraints ()

* string to regex approximation used to strengthen membership constraints

* fixed pull request comments
This commit is contained in:
Margus Veanes 2020-08-01 16:45:00 -07:00 committed by GitHub
parent fb035c0634
commit 8137143ada
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 98 additions and 3 deletions

View file

@ -1449,3 +1449,17 @@ bool seq_util::re::is_loop(expr const* n, expr*& body, expr*& lo) const {
}
return false;
}
/**
Returns true iff e is the epsilon regex.
*/
bool seq_util::re::is_epsilon(expr* r) const {
expr* s;
return is_to_re(r, s) && u.str.is_empty(s);
}
/**
Makes the epsilon regex for a given sequence sort.
*/
app* seq_util::re::mk_epsilon(sort* seq_sort) {
return mk_to_re(u.str.mk_empty(seq_sort));
}

View file

@ -474,6 +474,8 @@ public:
bool is_loop(expr const* n, expr*& body, expr*& lo) const;
unsigned min_length(expr* r) const;
unsigned max_length(expr* r) const;
bool is_epsilon(expr* r) const;
app* mk_epsilon(sort* seq_sort);
};
str str;
re re;

View file

@ -109,11 +109,37 @@ namespace smt {
return;
}
if (coallesce_in_re(lit))
return;
// Convert a non-ground sequence into an additional regex and
// strengthen the original regex constraint into an intersection
// for example:
// (x ++ "a" ++ y) in b*
// is coverted to
// (x ++ "a" ++ y) in intersect((.* ++ "a" ++ .*), b*)
if (!m.is_value(s)) {
expr_ref s_approx = get_overapprox_regex(s);
if (!re().is_full_seq(s_approx)) {
r = re().mk_inter(r, s_approx);
TRACE("seq_regex", tout
<< "get_overapprox_regex(" << mk_pp(s, m)
<< ") = " << mk_pp(s_approx, m) << std::endl;);
STRACE("seq_regex_brief", tout
<< "overapprox=" << state_str(r) << " ";);
}
}
if (is_string_equality(lit))
if (coallesce_in_re(lit)) {
TRACE("seq_regex", tout
<< "simplified conjunctions to an intersection" << std::endl;);
STRACE("seq_regex_brief", tout << "coallesce_in_re ";);
return;
}
if (is_string_equality(lit)) {
TRACE("seq_regex", tout
<< "simplified regex using string equality" << std::endl;);
STRACE("seq_regex_brief", tout << "string_eq ";);
return;
}
expr_ref zero(a().mk_int(0), m);
expr_ref acc = sk().mk_accept(s, zero, r);
@ -124,6 +150,56 @@ namespace smt {
th.propagate_lit(nullptr, 1, &lit, acc_lit);
}
/**
* Gets an overapproximating regex s_approx for the input string expression s.
* such that for any valuation v(s) of s, v(s) in L(s_approx).
* If the overapproximation is trivial then dotstar is returned.
*/
expr_ref seq_regex::get_overapprox_regex(expr* s) {
expr_ref s_to_re(re().mk_to_re(s), m);
expr_ref epsilon(re().mk_epsilon(m.get_sort(s)), m);
expr_ref dotstar(re().mk_full_seq(m.get_sort(s_to_re)), m);
if (m.is_value(s)) {
return s_to_re;
}
else {
expr_ref_vector es(m);
expr_ref s_approx(m);
if (str().is_concat(s)) {
str().get_concat(s, es);
//here it is known that es is nonempty or else s would be a value
expr_ref e_approx(m), last(m);
for (expr* e : es) {
e_approx = get_overapprox_regex(e);
if (!s_approx)
s_approx = e_approx;
else if (last != dotstar || e_approx != dotstar)
s_approx = re().mk_concat(e_approx, s_approx);
last = e_approx;
}
return s_approx;
}
else if (m.is_ite(s)) {
s_approx = get_overapprox_regex(to_app(s)->get_arg(1));
//if either branch approximates to .* then the result is also .*
if (!re().is_full_seq(s_approx)) {
expr_ref r2 = get_overapprox_regex(to_app(s)->get_arg(2));
if (re().is_full_seq(r2)) {
s_approx = r2;
}
else if (s_approx != r2) {
s_approx = re().mk_union(s_approx, r2);
}
}
return s_approx;
}
else {
// TBD: other app expressions that can be approximated
return dotstar;
}
}
}
/**
* Propagate the atom (accept s i r)
*

View file

@ -75,6 +75,9 @@ namespace smt {
bool is_string_equality(literal lit);
// Get a regex which overapproximates a given string
expr_ref get_overapprox_regex(expr* s);
void rewrite(expr_ref& e);
bool coallesce_in_re(literal lit);