3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-07-02 13:26:10 +00:00
This commit is contained in:
CEisenhofer 2026-06-06 15:24:25 +02:00
parent eee5a9dcef
commit 7c7ca27822
5 changed files with 61 additions and 27 deletions

View file

@ -942,15 +942,24 @@ namespace seq {
return;
if (src_re->is_fail() || dst_re->is_fail())
return;
euf::snode* label_re = to_partial_label_regex(label);
SASSERT(label_re);
if (!m_seq.is_re(label_re->get_expr()) || !label_re->is_ground())
// The partial DFA must track ONLY the concrete Brzozowski automaton of
// the original ground regexes. Projection operators (re.proj) are
// synthetic stabilizers minted by cycle decomposition; every fresh
// snapshot index ν is a new expression, so recording projection-derived
// states as DFA nodes makes the SCC grow without bound (a newly-marked
// edge on every extraction) and re-triggers cycle decomposition forever
// (e.g. a cycle variable x'∈π(R) being decomposed again and again
// against its own / a sibling regex's cycle). Reject such edges.
if (src_re->has_projection() || dst_re->has_projection())
return;
//euf::snode* label_re = to_partial_label_regex(label);
//SASSERT(label_re);
//if (!m_seq.is_re(label_re->get_expr()) || !label_re->is_ground())
// return;
expr* src_e = src_re->get_expr();
expr* label_e = label_re->get_expr();
//expr* label_e = label_re->get_expr();
expr* dst_e = dst_re->get_expr();
// Deduplicate transitions by (src, dst) only — NOT by label. The
@ -971,7 +980,7 @@ namespace seq {
// already-pinned expression is harmless; the wasted slot is bounded
// by the unique-edge count.
m_partial_dfa_pin.push_back(src_e);
m_partial_dfa_pin.push_back(label_e);
//m_partial_dfa_pin.push_back(label_e);
m_partial_dfa_pin.push_back(dst_e);
unsigned edge_idx = m_partial_dfa_edges.size();
@ -979,7 +988,7 @@ namespace seq {
partial_dfa_edge e;
e.m_src = src_e;
e.m_label = label_e;
//e.m_label = label_e;
e.m_dst = dst_e;
m_partial_dfa_edges.push_back(e);
@ -3284,7 +3293,7 @@ namespace seq {
euf::snode_vector mts;
m_sg.compute_minterms(re, mts);
for (euf::snode* mt : mts) {
std::cout << "minterm: " << mk_pp(mt->get_expr(), m) << std::endl;
// std::cout << "minterm: " << mk_pp(mt->get_expr(), m) << std::endl;
euf::snode* deriv = m_sg.brzozowski_deriv(re, mt);
if (!deriv || deriv->is_fail())
continue;
@ -3295,8 +3304,7 @@ namespace seq {
}
}
}
std::string s = partial_dfa_to_dot(root_re, false);
std::cout << s << std::endl;
//std::string s = partial_dfa_to_dot(root_re, true);
}
// -----------------------------------------------------------------------
@ -3865,6 +3873,13 @@ namespace seq {
if (mem.m_str->is_empty() || mem.is_primitive())
continue;
// compute_sigma / compute_tau do not understand the projection
// operator (re.proj) — they would recurse into it and hit an
// UNREACHABLE. Projection-constrained memberships are handled by the
// cycle-decomposition path, so skip them here.
if (mem.m_regex->has_projection())
continue;
euf::snode* first = mem.m_str->first();
SASSERT(first);
SASSERT(!first->is_char());

View file

@ -900,7 +900,7 @@ namespace seq {
// at the current scope via m_sg.mk(expr) only when we actually need one.
struct partial_dfa_edge {
expr* m_src = nullptr;
expr* m_label = nullptr; // one-character regex label (char/minterm)
//expr* m_label = nullptr; // one-character regex label (char/minterm)
expr* m_dst = nullptr;
unsigned m_projection_idx = 0; // first extraction index that included this edge
};
@ -1002,14 +1002,14 @@ namespace seq {
// Construct with a caller-supplied solver. Ownership is NOT transferred;
// the caller is responsible for keeping the solver alive.
nielsen_graph(euf::sgraph& sg, sub_solver_i& solver, context_solver_i& ctx);
~nielsen_graph();
~nielsen_graph() override;
ast_manager &get_manager() {
ast_manager& get_manager() const {
return m;
}
euf::sgraph& sg() { return m_sg; }
euf::sgraph& sg() const { return m_sg; }
seq_util& seq() { return m_seq; }
seq_util const& seq() const { return m_seq; }

View file

@ -860,13 +860,13 @@ namespace seq {
for (auto* e : edges) {
out << " N" << e->m_src->get_id() << " -> N" << e->m_dst->get_id() << " [label=\"";
if (e->m_label) {
std::stringstream ss;
ss << mk_ismt2_pp(e->m_label, m);
out << sanitize(ss.str());
} else {
out << "??";
}
//if (e->m_label) {
// std::stringstream ss;
// ss << mk_ismt2_pp(e->m_label, m);
// out << sanitize(ss.str());
//} else {
// out << "??";
//}
out << "\"];\n";
}