3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-07-21 22:45:51 +00:00

cleanup and add comments

This commit is contained in:
Nikolaj Bjorner 2026-07-02 19:32:09 -07:00
parent 2b4a473334
commit d43d61a4bf
2 changed files with 89 additions and 56 deletions

View file

@ -127,7 +127,6 @@ namespace smt {
return;
}
if (is_string_equality(lit)) {
TRACE(seq_regex, tout
<< "simplified regex using string equality" << std::endl;);
@ -135,60 +134,10 @@ namespace smt {
return;
}
// 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)
// Assert in_re2(u, R1, v, R2) => u in R1 and v in R2
// forward on split_set until there is a new in_re2 literal that is not already false.
// If there was an already created in_re2 literal that is true,
// then check that the propagation axiom is true
// if it isn't true, then assert it.
// if it is true, we are done
// If split_set is done and all in_re2 literals are false, there is a conflict.
// Assert the conflict clause lit => (or in_re2 literals)
// Final check also unfolds this axiomatization
// (we have to add a final check to seq_regex for this).
if (th.get_fparams().m_seq_regex_factorization_enabled) {
unsigned threshold = th.get_fparams().m_seq_regex_factorization_threshold;
expr_ref_vector prefix(m);
expr *hd, *tl, *v;
auto filter = [&](expr* p, expr* _q) -> bool {
expr_ref q(_q, m);
for (expr* v : prefix) {
q = seq_rw().mk_derivative(v, q);
if (re().is_empty(q))
return false;
}
return re().is_empty(q);
};
split_set result(seq_rw(), r, threshold, filter);
auto [head, tail] = result.try_split_sequence(s);
if (head && tail) {
tl = tail;
while (str().is_concat(tl, hd, tl) && str().is_unit(hd, v) && m.is_value(v)) {
prefix.push_back(v);
}
// propagate all cases
expr_ref_vector cases(m);
expr_ref_vector branches(m);
for (auto [pre, post] : result) {
expr_ref mem_head(re().mk_in_re(head, pre), m);
expr_ref mem_tail(re().mk_in_re(tail, post), m);
cases.push_back(m.mk_and(mem_head, mem_tail));
}
if (!result.failed()) {
const expr_ref cases_expr(m.mk_or(cases), m);
ctx.internalize(cases_expr, false);
th.propagate_lit(nullptr, 1, &lit, ctx.get_literal(cases_expr));
return;
}
}
// fallthrough; decomposition failed
}
if (factor_membership(lit)) {
TRACE(seq_regex, tout << "factor membership\n");
return;
}
// Convert a non-ground sequence into an additional regex and
// strengthen the original regex constraint into an intersection
@ -216,7 +165,6 @@ namespace smt {
TRACE(seq, tout << "propagate " << acc << "\n";);
//th.propagate_lit(nullptr, 1, &lit, acc_lit);
th.add_axiom(~lit, acc_lit);
}
@ -419,6 +367,66 @@ namespace smt {
true);
}
bool seq_regex::factor_membership(literal lit) {
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)
// Assert in_re2(u, R1, v, R2) => u in R1 and v in R2
// forward on split_set until there is a new in_re2 literal that is not already false.
// If there was an already created in_re2 literal that is true,
// then check that the propagation axiom is true
// if it isn't true, then assert it.
// if it is true, we are done
// If split_set is done and all in_re2 literals are false, there is a conflict.
// Assert the conflict clause lit => (or in_re2 literals)
// Final check also unfolds this axiomatization
// (we have to add a final check to seq_regex for this).
if (!th.get_fparams().m_seq_regex_factorization_enabled)
return false;
unsigned threshold = th.get_fparams().m_seq_regex_factorization_threshold;
expr_ref_vector prefix(m);
expr *hd, *tl, *v;
auto filter = [&](expr *p, expr *_q) -> bool {
expr_ref q(_q, m);
for (expr *v : prefix) {
q = seq_rw().mk_derivative(v, q);
if (re().is_empty(q))
return false;
}
return re().is_empty(q);
};
split_set result(seq_rw(), r, threshold, filter);
auto [head, tail] = result.try_split_sequence(s);
if (head && tail) {
tl = tail;
while (str().is_concat(tl, hd, tl) && str().is_unit(hd, v) && m.is_value(v))
prefix.push_back(v);
// propagate all cases
expr_ref_vector cases(m);
expr_ref_vector branches(m);
for (auto [pre, post] : result) {
expr_ref mem_head(re().mk_in_re(head, pre), m);
expr_ref mem_tail(re().mk_in_re(tail, post), m);
cases.push_back(m.mk_and(mem_head, mem_tail));
}
if (!result.failed()) {
const expr_ref cases_expr(m.mk_or(cases), m);
ctx.internalize(cases_expr, false);
th.propagate_lit(nullptr, 1, &lit, ctx.get_literal(cases_expr));
return true;
}
}
return false;
}
bool seq_regex::unfold_prefix(literal lit) {
expr *s = nullptr, *r = nullptr;
expr *e = ctx.bool_var2expr(lit.var());