3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-07-15 03:25:43 +00:00

restructure

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2026-07-03 23:24:58 -07:00
parent 7d75e6f40a
commit 00ee1ca75c
2 changed files with 58 additions and 80 deletions

View file

@ -132,11 +132,9 @@ namespace smt {
* s = x ++ y and x in R and y in Q
*/
bool seq_regex::is_string_equality(literal lit) {
expr* s = nullptr, *r = nullptr;
bool seq_regex::is_string_equality(literal lit, expr* s, expr* r) {
expr* e = ctx.bool_var2expr(lit.var());
expr_ref id(a().mk_int(e->get_id()), m);
VERIFY(str().is_in_re(e, s, r));
sort* seq_sort = s->get_sort();
vector<expr_ref_vector> patterns;
auto mk_cont = [&](unsigned idx) {
@ -191,31 +189,34 @@ namespace smt {
return;
}
if (unfold_prefix(lit)) {
if (unfold_prefix(lit, s, r)) {
TRACE(seq_regex, tout << "unfolded prefix" << std::endl;);
STRACE(seq_regex_brief, tout << "unfold_prefix ";);
return;
}
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)) {
if (is_string_equality(lit, s, r)) {
TRACE(seq_regex, tout
<< "simplified regex using string equality" << std::endl;);
STRACE(seq_regex_brief, tout << "string_eq ";);
return;
}
if (factor_membership(lit)) {
if (factor_ite(lit, s, r)) {
TRACE(seq_regex, tout << "factored ite in regex" << std::endl;);
STRACE(seq_regex_brief, tout << "factor_ite ";);
return;
}
if (factor_membership(lit, s, r)) {
TRACE(seq_regex, tout << "factor membership\n");
return;
}
initialize_accept(lit, s, r);
}
void seq_regex::initialize_accept(literal lit, expr *s, expr *r) {
// Convert a non-ground sequence into an additional regex and
// strengthen the original regex constraint into an intersection
// for example:
@ -228,11 +229,9 @@ namespace smt {
if (!re().is_full_seq(s_approx)) {
r = re().mk_inter(r, s_approx);
_r_temp_owner = r;
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) << " ";);
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) << " ";);
}
}
@ -444,12 +443,10 @@ namespace smt {
true);
}
bool seq_regex::factor_membership(literal lit) {
bool seq_regex::factor_membership(literal lit, expr* s, expr* r) {
if (!th.get_fparams().m_seq_regex_factorization_enabled)
return false;
expr *s = nullptr, *r = nullptr;
expr *e = ctx.bool_var2expr(lit.var());
VERIFY(str().is_in_re(e, s, r));
// TODO - replace this with a propagator closure that gets invoked and removed on backtracking.
// it tracks <lit, split_set, in_re2 literals>
// an in_re2 literal is of the form in_re2(u, R1, v, R2)
@ -505,18 +502,39 @@ namespace smt {
return false;
}
bool seq_regex::unfold_prefix(literal lit) {
expr *s = nullptr, *r = nullptr;
expr *e = ctx.bool_var2expr(lit.var());
VERIFY(str().is_in_re(e, s, r));
bool seq_regex::factor_ite(literal lit, expr* s, expr* r) {
bool_rewriter br(m);
expr_ref c(m), t(m), e(m);
if (!br.decompose_ite(r, c, t, e))
return false;
auto c_lit = th.mk_literal(c);
switch (ctx.get_assignment(c_lit)) {
case l_true: {
literal lits[2] = {lit, c_lit};
th.propagate_lit(nullptr, 2, lits, th.mk_literal(re().mk_in_re(s, t)));
break;
}
case l_false: {
literal lits[2] = {lit, ~c_lit};
th.propagate_lit(nullptr, 2, lits, th.mk_literal(re().mk_in_re(s, e)));
break;
}
case l_undef: {
ctx.mark_as_relevant(c_lit);
break;
}
}
return true;
}
bool seq_regex::unfold_prefix(literal lit, expr* s, expr* r) {
expr_ref_vector prefix(m);
expr *hd, *v, *tl = s, *tl1;
while (str().is_concat(tl, hd, tl1) && str().is_unit(hd, v) && m.is_value(v))
while (str().is_concat(tl, hd, tl1) && str().is_unit(hd, v))
prefix.push_back(v),
tl = tl1;
VERIFY(!(str().is_concat(tl, hd, tl1) && str().is_unit(hd)));
if (prefix.empty())
return false;
@ -538,58 +556,16 @@ namespace smt {
return true;
}
/**
* Combine a conjunction of membership relations for the same string
* within the same Regex.
*/
bool seq_regex::coallesce_in_re(literal lit) {
return false; // disabled
expr* s = nullptr, *r = nullptr;
expr* e = ctx.bool_var2expr(lit.var());
VERIFY(str().is_in_re(e, s, r));
expr_ref regex(r, m);
literal_vector lits;
for (unsigned i = 0; i < m_s_in_re.size(); ++i) {
auto const& entry = m_s_in_re[i];
if (!entry.m_active)
continue;
enode* n1 = th.ensure_enode(entry.m_s);
enode* n2 = th.ensure_enode(s);
if (n1->get_root() != n2->get_root())
continue;
if (entry.m_re == regex)
continue;
th.m_trail_stack.push(vector_value_trail<s_in_re, true>(m_s_in_re, i));
m_s_in_re[i].m_active = false;
IF_VERBOSE(11, verbose_stream() << "Intersect " << regex << " " <<
mk_pp(entry.m_re, m) << " " << mk_pp(s, m) << " " << mk_pp(entry.m_s, m) << std::endl;);
regex = re().mk_inter(entry.m_re, regex);
rewrite(regex);
lits.push_back(~entry.m_lit);
if (n1 != n2)
lits.push_back(~th.mk_eq(n1->get_expr(), n2->get_expr(), false));
}
m_s_in_re.push_back(s_in_re(lit, s, regex));
th.get_trail_stack().push(push_back_vector<vector<s_in_re>>(m_s_in_re));
if (lits.empty())
return false;
lits.push_back(~lit);
lits.push_back(th.mk_literal(re().mk_in_re(s, regex)));
th.add_axiom(lits);
return true;
}
expr_ref seq_regex::symmetric_diff(expr* r1, expr* r2) {
expr_ref r(m);
if (r1 == r2)
r = re().mk_empty(r1->get_sort());
else if (re().is_empty(r1))
else if (re().is_empty(r1))
r = r2;
else if (re().is_empty(r2))
r = r1;
else
r = re().mk_union(re().mk_diff(r1, r2), re().mk_diff(r2, r1));
else
r = re().mk_xor(r1, r2);
rewrite(r);
return r;
}
@ -705,7 +681,6 @@ namespace smt {
STRACE(seq_regex_brief, tout << "PNEQ ";);
sort* seq_sort = nullptr;
VERIFY(u().is_re(r1, seq_sort));
expr_ref r = symmetric_diff(r1, r2);
if (is_ground(r1) && is_ground(r2)) {
seq::regex_bisim bisim(seq_rw());
switch (bisim.are_equivalent(r1, r2)) {
@ -720,6 +695,7 @@ namespace smt {
break;
}
}
auto r = symmetric_diff(r1, r2);
expr_ref emp(re().mk_empty(r->get_sort()), m);
expr_ref n(m.mk_fresh_const("re.char", seq_sort), m);
expr_ref is_non_empty = sk().mk_is_non_empty(r, r, n);

View file

@ -168,20 +168,22 @@ namespace smt {
seq::skolem& sk();
arith_util& a();
bool is_string_equality(literal lit);
bool is_string_equality(literal lit, expr* s, expr* r);
// 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);
bool block_unfolding(literal lit, unsigned i);
bool unfold_prefix(literal lit);
bool unfold_prefix(literal lit, expr* s, expr* r);
bool factor_membership(literal lit);
bool factor_membership(literal lit, expr* s, expr* r);
bool factor_ite(literal lit, expr* s, expr* r);
void initialize_accept(literal lit, expr *s, expr *r);
expr_ref mk_first(expr* r, expr* n);