mirror of
https://github.com/Z3Prover/z3
synced 2026-06-27 19:08:49 +00:00
tuning simplification processing
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
f42172e65a
commit
9456297046
4 changed files with 293 additions and 50 deletions
|
|
@ -23,6 +23,7 @@ Author:
|
|||
#include "ast/for_each_expr.h"
|
||||
#include "ast/rewriter/seq_regex_bisim.h"
|
||||
#include <ast/rewriter/expr_safe_replace.h>
|
||||
#include <chrono>
|
||||
|
||||
namespace smt {
|
||||
|
||||
|
|
@ -224,6 +225,40 @@ namespace smt {
|
|||
th.add_axiom(~lit);
|
||||
return true;
|
||||
}
|
||||
// Second pass: deeper exploration for intersection/complement/diff regexes
|
||||
// These are candidates for dead state detection (the result may be empty)
|
||||
// For these, do unlimited depth exploration with a time budget
|
||||
unsigned r_id = get_state_id(r);
|
||||
expr* r1 = nullptr, *r2 = nullptr;
|
||||
if (!m_state_graph.is_dead(r_id) && !m_state_graph.is_live(r_id) &&
|
||||
(re().is_intersection(r, r1, r2) || re().is_complement(r, r1) || re().is_diff(r, r1, r2))) {
|
||||
// Collect all unexplored states and explore them iteratively
|
||||
// with a time budget
|
||||
auto pass2_start = std::chrono::steady_clock::now();
|
||||
bool changed = true;
|
||||
while (changed && !m_state_graph.is_dead(r_id)) {
|
||||
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - pass2_start).count();
|
||||
if (elapsed > 100) break;
|
||||
changed = false;
|
||||
for (unsigned i = 0; i < m_state_to_expr.size() && !m_state_graph.is_dead(r_id); ++i) {
|
||||
unsigned st_id = i + 1;
|
||||
if (m_state_graph.is_done(st_id) || m_state_graph.is_live(st_id) || m_state_graph.is_dead(st_id))
|
||||
continue;
|
||||
// This is an unexplored state — explore it
|
||||
expr* st = m_state_to_expr.get(i);
|
||||
if (re().get_info(st).nullable == l_true)
|
||||
continue;
|
||||
if (update_state_graph(st, 1))
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (m_state_graph.is_dead(r_id)) {
|
||||
STRACE(seq_regex_brief, tout << "(dead2) ";);
|
||||
th.add_axiom(~lit);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -848,7 +883,7 @@ namespace smt {
|
|||
/*
|
||||
Update the state graph with expression r and all its derivatives.
|
||||
*/
|
||||
bool seq_regex::update_state_graph(expr* r) {
|
||||
bool seq_regex::update_state_graph(expr* r, unsigned depth) {
|
||||
unsigned r_id = get_state_id(r);
|
||||
if (m_state_graph.is_done(r_id)) return false;
|
||||
if (m_state_graph.get_size() >= m_max_state_graph_size) {
|
||||
|
|
@ -891,15 +926,37 @@ namespace smt {
|
|||
m_state_graph.add_edge(r_id, dr_id, maybecycle);
|
||||
}
|
||||
m_state_graph.mark_done(r_id);
|
||||
// Recursively explore unexplored targets for dead state detection
|
||||
// Skip targets that are nullable to avoid state explosion
|
||||
for (auto const& dr: derivatives) {
|
||||
unsigned dr_id = get_state_id(dr);
|
||||
if (m_state_graph.is_done(dr_id) || m_state_graph.is_live(dr_id))
|
||||
continue;
|
||||
if (re().get_info(dr).nullable == l_true)
|
||||
continue;
|
||||
update_state_graph(dr);
|
||||
// Explore direct targets for dead state detection (depth 1 only)
|
||||
// This compensates for less-canonical derivative representations
|
||||
if (depth < 1) {
|
||||
for (auto const& dr: derivatives) {
|
||||
unsigned dr_id = get_state_id(dr);
|
||||
if (m_state_graph.is_done(dr_id) || m_state_graph.is_live(dr_id))
|
||||
continue;
|
||||
if (re().get_info(dr).nullable == l_true)
|
||||
continue;
|
||||
update_state_graph(dr, depth + 1);
|
||||
}
|
||||
}
|
||||
else if (depth == 1) {
|
||||
// At depth 1, do lightweight exploration: compute derivatives
|
||||
// of this state's targets but only to check if they're all dead.
|
||||
// Don't add complex states to the graph — just mark them dead if
|
||||
// their get_info says min_length == UINT_MAX or is_empty.
|
||||
for (auto const& dr: derivatives) {
|
||||
unsigned dr_id = get_state_id(dr);
|
||||
if (m_state_graph.is_done(dr_id) || m_state_graph.is_live(dr_id))
|
||||
continue;
|
||||
auto dr_info = re().get_info(dr);
|
||||
if (dr_info.nullable == l_true) {
|
||||
m_state_graph.add_state(dr_id);
|
||||
m_state_graph.mark_live(dr_id);
|
||||
}
|
||||
else if (re().is_empty(dr) || dr_info.min_length == UINT_MAX) {
|
||||
m_state_graph.add_state(dr_id);
|
||||
m_state_graph.mark_done(dr_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue