mirror of
https://github.com/Z3Prover/z3
synced 2026-07-12 10:06:23 +00:00
Derive with ranges (#9965)
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Margus Veanes <margus@microsoft.com> Co-authored-by: Margus Veanes <veanes@users.noreply.github.com>
This commit is contained in:
parent
e76239ceda
commit
15f33f458d
27 changed files with 3597 additions and 1541 deletions
|
|
@ -85,45 +85,6 @@ namespace seq {
|
|||
return is_ground(r);
|
||||
}
|
||||
|
||||
/*
|
||||
Collect the leaves of a t-regex der (an ITE-tree whose leaves are
|
||||
regex expressions) into the output vector. Empty (re.empty) leaves
|
||||
are dropped.
|
||||
|
||||
Each leaf is treated as a single bisimulation state regardless of
|
||||
its top-level shape (including re.union and re.antimirov_union):
|
||||
descending into a union at the leaf would split one state into
|
||||
several, which is semantically unsound for the bisimulation /
|
||||
union-find merging that follows.
|
||||
|
||||
Returns false if we encountered an unexpected node (e.g. a free
|
||||
variable creeping in) — in that case the caller should bail out.
|
||||
*/
|
||||
bool regex_bisim::collect_leaves(expr* der, expr_ref_vector& leaves) {
|
||||
ptr_vector<expr> work;
|
||||
obj_hashtable<expr> seen;
|
||||
work.push_back(der);
|
||||
seen.insert(der);
|
||||
while (!work.empty()) {
|
||||
expr* e = work.back();
|
||||
work.pop_back();
|
||||
expr* c = nullptr, * t = nullptr, * f = nullptr;
|
||||
if (m.is_ite(e, c, t, f)) {
|
||||
if (seen.insert_if_not_there(t))
|
||||
work.push_back(t);
|
||||
if (seen.insert_if_not_there(f))
|
||||
work.push_back(f);
|
||||
continue;
|
||||
}
|
||||
if (m_util.re.is_empty(e))
|
||||
continue;
|
||||
if (!m_util.is_re(e))
|
||||
return false;
|
||||
leaves.push_back(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Fast inequivalence check based on the get_info().classical flag.
|
||||
|
||||
|
|
@ -232,15 +193,19 @@ namespace seq {
|
|||
m_worklist.pop_back();
|
||||
|
||||
// Compute the symbolic derivative wrt the canonical variable
|
||||
// (:var 0). The result is a transition regex (ITE tree) whose
|
||||
// leaves are regex expressions. We use the classical Brzozowski
|
||||
// entry point so the derivative stays as a single TRegex and
|
||||
// does not lift unions to the top via antimirov nodes — this
|
||||
// preserves the XOR-pair invariant the bisimulation relies on.
|
||||
expr_ref d(m_rw.mk_brz_derivative(r), m);
|
||||
// (:var 0) and enumerate its reachable leaves in fully
|
||||
// ITE-hoisted normal form. Every if-then-else over the input
|
||||
// character — even one that would otherwise be buried under a
|
||||
// concat or union — is hoisted to the top and infeasible
|
||||
// minterms are pruned, so each leaf is a ground regex free of
|
||||
// (:var 0) whose nullability is always decidable. Unions are
|
||||
// kept intact as single leaves (a union leaf denotes a single
|
||||
// bisimulation state, never a split into separate states).
|
||||
expr_ref_pair_vector cofs(m);
|
||||
m_rw.brz_derivative_cofactors(r, cofs);
|
||||
expr_ref_vector leaves(m);
|
||||
if (!collect_leaves(d, leaves))
|
||||
return l_undef;
|
||||
for (auto const& p : cofs)
|
||||
leaves.push_back(p.second);
|
||||
|
||||
// First pass: check for any nullable leaf (definitive
|
||||
// distinguishing empty-continuation word) or any classically
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue