mirror of
https://github.com/Z3Prover/z3
synced 2026-08-07 06:28:18 +00:00
Add monadic regex statistics
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 2bcccba7-ac7d-476e-8dfe-718a21d37554
This commit is contained in:
parent
079eb4b534
commit
3e1fd56ca2
4 changed files with 82 additions and 9 deletions
|
|
@ -92,9 +92,11 @@ lbool seq_monadic::nullable(expr* r) {
|
|||
}
|
||||
|
||||
expr_ref_pair_vector const& seq_monadic::derivative_cofactors(expr* r) {
|
||||
++m_stats.m_cofactor_calls;
|
||||
expr_ref_pair_vector* v = nullptr;
|
||||
if (m_cofactors.find(r, v))
|
||||
return *v;
|
||||
++m_stats.m_states;
|
||||
v = alloc(expr_ref_pair_vector, m);
|
||||
if (m_config.m_mode == transition_mode::light_antimirov)
|
||||
m_rw.light_ant_derivative_cofactors(r, *v);
|
||||
|
|
@ -122,7 +124,14 @@ bool seq_monadic::live_states(expr* R, expr_ref_vector& out) {
|
|||
intern(R);
|
||||
const unsigned STATE_CAP = 1u << 12;
|
||||
for (unsigned i = 0; i < states.size(); ++i) {
|
||||
if (states.size() > STATE_CAP || !m.inc()) return false;
|
||||
if (states.size() > STATE_CAP) {
|
||||
m_stats.inc_bail(bail_reason::state_cap);
|
||||
return false;
|
||||
}
|
||||
if (!m.inc()) {
|
||||
m_stats.inc_bail(bail_reason::resource);
|
||||
return false;
|
||||
}
|
||||
expr_ref_pair_vector const& cof = derivative_cofactors(states.get(i));
|
||||
for (auto const& [g, t] : cof) {
|
||||
if (re().is_empty(t)) continue;
|
||||
|
|
@ -280,7 +289,11 @@ lbool seq_monadic::product_nonempty(svector<component> const& comps, expr_ref* w
|
|||
guard_set nacc = acc;
|
||||
nacc.conjoin(g);
|
||||
lbool ne = nacc.eval(nullptr);
|
||||
if (ne == l_undef) { bail = true; return; } // non-range / unknown guard
|
||||
if (ne == l_undef) {
|
||||
m_stats.inc_bail(bail_reason::guard);
|
||||
bail = true;
|
||||
return;
|
||||
}
|
||||
if (ne == l_false) continue; // empty joint guard: prune
|
||||
cur[i] = t;
|
||||
rec(i + 1, nacc);
|
||||
|
|
@ -289,7 +302,16 @@ lbool seq_monadic::product_nonempty(svector<component> const& comps, expr_ref* w
|
|||
};
|
||||
|
||||
while (!work.empty()) {
|
||||
if (m_budget == 0 || !m.inc()) { m_giveup = true; return l_undef; }
|
||||
if (m_budget == 0) {
|
||||
m_stats.inc_bail(bail_reason::budget);
|
||||
m_giveup = true;
|
||||
return l_undef;
|
||||
}
|
||||
if (!m.inc()) {
|
||||
m_stats.inc_bail(bail_reason::resource);
|
||||
m_giveup = true;
|
||||
return l_undef;
|
||||
}
|
||||
--m_budget;
|
||||
for (unsigned i = n; i-- > 0; ) {
|
||||
st[i] = work.back();
|
||||
|
|
@ -300,8 +322,10 @@ lbool seq_monadic::product_nonempty(svector<component> const& comps, expr_ref* w
|
|||
*witness_word = reconstruct(fill_key(st));
|
||||
return l_true;
|
||||
}
|
||||
if (undecided)
|
||||
if (undecided) {
|
||||
m_stats.inc_bail(bail_reason::nullability);
|
||||
return l_undef;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < n; ++i)
|
||||
branches[i] = &derivative_cofactors(st[i]);
|
||||
|
|
@ -373,16 +397,24 @@ void seq_monadic::reset_search() {
|
|||
bool seq_monadic::prepare(membership_vec const& memberships) {
|
||||
reset_search();
|
||||
for (auto const& [term, regex, d] : memberships) {
|
||||
if (!u().is_re(regex, m_seq_sort))
|
||||
if (!u().is_re(regex, m_seq_sort)) {
|
||||
m_stats.inc_bail(bail_reason::unsupported);
|
||||
return false;
|
||||
if (!u().is_seq(m_seq_sort, m_elem_sort))
|
||||
}
|
||||
if (!u().is_seq(m_seq_sort, m_elem_sort)) {
|
||||
m_stats.inc_bail(bail_reason::unsupported);
|
||||
return false;
|
||||
}
|
||||
vector<atom> atoms;
|
||||
expr* the_var = nullptr;
|
||||
if (!parse_term(term, atoms, the_var))
|
||||
if (!parse_term(term, atoms, the_var)) {
|
||||
m_stats.inc_bail(bail_reason::unsupported);
|
||||
return false;
|
||||
if (!the_var)
|
||||
}
|
||||
if (!the_var) {
|
||||
m_stats.inc_bail(bail_reason::unsupported);
|
||||
return false; // no variable: ground membership, not our case
|
||||
}
|
||||
m_regexes.push_back(regex);
|
||||
m_atoms.push_back(atoms);
|
||||
m_pin.push_back(regex);
|
||||
|
|
@ -460,7 +492,13 @@ lbool seq_monadic::dfs_membership(unsigned mi) {
|
|||
lbool seq_monadic::dfs_atoms(unsigned mi, unsigned i, expr* R) {
|
||||
if (m_giveup)
|
||||
return l_undef; // unwind the whole search, don't keep branching
|
||||
if (m_budget == 0 || !m.inc()) {
|
||||
if (m_budget == 0) {
|
||||
m_stats.inc_bail(bail_reason::budget);
|
||||
m_giveup = true;
|
||||
return l_undef;
|
||||
}
|
||||
if (!m.inc()) {
|
||||
m_stats.inc_bail(bail_reason::resource);
|
||||
m_giveup = true;
|
||||
return l_undef;
|
||||
}
|
||||
|
|
@ -472,6 +510,7 @@ lbool seq_monadic::dfs_atoms(unsigned mi, unsigned i, expr* R) {
|
|||
return dfs_membership(mi + 1);
|
||||
if (nb == l_false)
|
||||
return l_false;
|
||||
m_stats.inc_bail(bail_reason::nullability);
|
||||
return l_undef; // undecidable nullability
|
||||
}
|
||||
atom const& a = atoms[i];
|
||||
|
|
@ -622,3 +661,19 @@ lbool seq_monadic::check() {
|
|||
minimize_core(m_memberships);
|
||||
return r;
|
||||
}
|
||||
|
||||
void seq_monadic::collect_statistics(::statistics& st) const {
|
||||
static char const* const bail_names[] = {
|
||||
"seq monadic bail unsupported",
|
||||
"seq monadic bail state cap",
|
||||
"seq monadic bail dnf cap",
|
||||
"seq monadic bail budget",
|
||||
"seq monadic bail resource",
|
||||
"seq monadic bail nullability",
|
||||
"seq monadic bail guard"
|
||||
};
|
||||
st.update("seq monadic cofactor calls", m_stats.m_cofactor_calls);
|
||||
st.update("seq monadic states", m_stats.m_states);
|
||||
for (unsigned i = 0; i < static_cast<unsigned>(bail_reason::num_reasons); ++i)
|
||||
st.update(bail_names[i], m_stats.m_bails[i]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ Author:
|
|||
#include "util/obj_pair_hashtable.h"
|
||||
#include "util/dependency.h"
|
||||
#include "util/trail.h"
|
||||
#include "util/statistics.h"
|
||||
#include <utility>
|
||||
#include <tuple>
|
||||
#include <map>
|
||||
|
|
@ -115,6 +116,18 @@ private:
|
|||
config(transition_mode mode) : m_mode(mode) {}
|
||||
};
|
||||
|
||||
enum class bail_reason { unsupported, state_cap, dnf_cap, budget, resource, nullability, guard, num_reasons };
|
||||
|
||||
struct statistics {
|
||||
unsigned m_cofactor_calls = 0;
|
||||
unsigned m_states = 0;
|
||||
unsigned m_bails[static_cast<unsigned>(bail_reason::num_reasons)] = {};
|
||||
|
||||
void inc_bail(bail_reason reason) {
|
||||
++m_bails[static_cast<unsigned>(reason)];
|
||||
}
|
||||
};
|
||||
|
||||
ast_manager& m;
|
||||
seq_rewriter& m_rw;
|
||||
th_rewriter m_thrw; // normalizes constant-element derivatives (folds
|
||||
|
|
@ -126,6 +139,7 @@ private:
|
|||
unsigned m_budget = 0; // global work budget (search nodes + product pops)
|
||||
bool m_giveup = false; // set when the budget is exhausted
|
||||
config m_config;
|
||||
statistics m_stats;
|
||||
obj_map<expr, expr*> m_model; // last extracted model (var -> witness); see get_model()
|
||||
cofactor_cache m_cofactors; // memoizes derivative_cofactors per regex (see class above)
|
||||
guard_set::cache m_rp_cache; // cofactor guard -> range predicate
|
||||
|
|
@ -266,6 +280,8 @@ public:
|
|||
|
||||
~seq_monadic() { reset_live_cache(); }
|
||||
|
||||
void collect_statistics(::statistics &st) const;
|
||||
|
||||
transition_mode mode() const { return m_config.m_mode; }
|
||||
|
||||
// Enable/disable model generation (default: enabled). When enabled, a successful
|
||||
|
|
|
|||
|
|
@ -261,6 +261,7 @@ namespace smt {
|
|||
bool can_propagate() const { return false; }
|
||||
bool propagate() const { return false; }
|
||||
final_check_status final_check();
|
||||
void collect_statistics(::statistics& st) const { m_monadic.collect_statistics(st); }
|
||||
|
||||
void propagate_in_re(literal lit);
|
||||
|
||||
|
|
|
|||
|
|
@ -1954,6 +1954,7 @@ std::ostream& theory_seq::display_deps(std::ostream& out, dependency* dep) const
|
|||
}
|
||||
|
||||
void theory_seq::collect_statistics(::statistics & st) const {
|
||||
m_regex.collect_statistics(st);
|
||||
st.update("seq num splits", m_stats.m_num_splits);
|
||||
st.update("seq num reductions", m_stats.m_num_reductions);
|
||||
st.update("seq length coherence", m_stats.m_check_length_coherence);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue