mirror of
https://github.com/Z3Prover/z3
synced 2026-07-18 13:05:46 +00:00
seq_split: add behaviour-neutral perf counters, surfaced via nseq -st
Adds a split_stats struct to seq_split (make/sigma-expand/materialize/splits/pushes/oracle-prunes/intersect/intersect-pairs/complement/giveups/threshold-overruns/max-split-set/simplify) and reports them in nielsen_graph::collect_statistics as 'nseq split *'. Read-only counters; solver behaviour is unchanged (verified: L11 sat, L14 unsat, gen cssfunc sat). Diagnosis on gen-lb L15 negcount: the De Morgan complement -> intersect cross-product blows up to 2^16 split-set pairs (1.3M intersect-pairs) while simplify() and the oracle never fire on that path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
7cc5a73bd8
commit
8992d5fc53
4 changed files with 69 additions and 3 deletions
|
|
@ -57,6 +57,25 @@ enum class split_mode { weak, strong };
|
|||
// default) keeps everything, so sigma is unchanged. See seq_split::compute.
|
||||
typedef std::function<bool(expr* D, expr* N)> split_oracle;
|
||||
|
||||
// Lightweight performance counters for the split algebra (surfaced via -st in
|
||||
// the nseq solver; behaviour-neutral). See seq_split.cpp for where each fires.
|
||||
struct split_stats {
|
||||
unsigned m_make = 0; // make(): suspended sigma(r) built
|
||||
unsigned m_sigma_expand = 0; // expand_fromre(): one sigma rule level
|
||||
unsigned m_materialize = 0; // materialize(): a split-set drained
|
||||
unsigned m_splits = 0; // splits produced by iterator::next()
|
||||
unsigned m_pushes = 0; // candidate <D,N> offered to push()
|
||||
unsigned m_oracle_prunes = 0; // candidates dropped by the lookahead oracle
|
||||
unsigned m_intersect = 0; // intersect() calls
|
||||
unsigned m_intersect_pairs = 0; // pairs formed by intersect() cross-products
|
||||
unsigned m_complement = 0; // complement() calls
|
||||
unsigned m_giveups = 0; // iterator give-ups (unsupported/weak/overrun)
|
||||
unsigned m_threshold_overruns = 0; // threshold hits (intersect/complement/iterator)
|
||||
unsigned m_max_split_set = 0; // largest materialized split-set seen
|
||||
unsigned m_simplify = 0; // simplify() calls
|
||||
void reset() { *this = split_stats(); }
|
||||
};
|
||||
|
||||
class seq_split {
|
||||
ast_manager& m;
|
||||
seq_rewriter& m_rw; // for mk_re_append + manager / seq_util access
|
||||
|
|
@ -81,6 +100,7 @@ class seq_split {
|
|||
func_decl_ref m_d_empty, m_d_single, m_d_fromre, m_d_union,
|
||||
m_d_inter, m_d_compl, m_d_lcat, m_d_rcat;
|
||||
expr_ref m_empty_app; // cached nullary `empty` term
|
||||
mutable split_stats m_stats; // performance counters (see -st)
|
||||
|
||||
seq_util& seq() const;
|
||||
seq_util::rex& re() const;
|
||||
|
|
@ -151,6 +171,10 @@ class seq_split {
|
|||
public:
|
||||
explicit seq_split(seq_rewriter& rw);
|
||||
|
||||
// Performance counters (read via nseq -st).
|
||||
split_stats const& stats() const { return m_stats; }
|
||||
void reset_stats() { m_stats.reset(); }
|
||||
|
||||
// Lazy split enumerator. Holds the suspended split-set worklist and produces
|
||||
// the concrete splits <D, N> one at a time, on demand, instead of computing
|
||||
// them all up front. Obtain one from seq_split::iterate (or construct it
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue