mirror of
https://github.com/Z3Prover/z3
synced 2026-07-15 19:45:41 +00:00
seq_split: dedup identical <D,N> pairs in intersect (sound, memory-only)
A split-set denotes the UNION of its pairs, so identical (hash-consed) <D,N> pairs are redundant; skipping them in the De Morgan cross-product cuts the materialized split-set ~7x on L15 negcount (65536 -> 9216) with no behaviour change (verified L11 sat / L14 unsat). NOTE: memory-only -- it does not fix the underlying combinatorial blow-up of complement()'s structural De Morgan on a concatenation of predicates (root cause; see spec analysis). Adds nseq-split-dedup-drops counter. Easily reverted if a derivative/minterm-based complement supersedes the cross-product. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
8992d5fc53
commit
07c797c32b
3 changed files with 13 additions and 0 deletions
|
|
@ -20,6 +20,7 @@ Author:
|
|||
#include "ast/rewriter/seq_rewriter.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "util/obj_hashtable.h"
|
||||
#include "util/obj_pair_hashtable.h"
|
||||
#include "util/stack.h"
|
||||
|
||||
seq_split::seq_split(seq_rewriter& rw) :
|
||||
|
|
@ -191,6 +192,10 @@ bool seq_split::intersect(split_set const& s1, split_set const& s2, split_set& r
|
|||
unsigned threshold, split_oracle const& oracle) const {
|
||||
++m_stats.m_intersect;
|
||||
const seq_util::rex& r = re();
|
||||
// Dedup the cross-product: a split-set denotes the UNION of its <D,N> pairs,
|
||||
// so identical (perfectly-shared) pairs are redundant. Skipping them keeps
|
||||
// the De Morgan fold from accumulating exponentially many equal splits.
|
||||
obj_pair_hashtable<expr, expr> seen;
|
||||
for (auto const& p1 : s1) {
|
||||
for (auto const& p2 : s2) {
|
||||
if (r.is_empty(p1.m_d) || r.is_empty(p2.m_d) ||
|
||||
|
|
@ -199,6 +204,12 @@ bool seq_split::intersect(split_set const& s1, split_set const& s2, split_set& r
|
|||
const expr_ref di(m_rw.mk_regex_inter_normalize(p1.m_d, p2.m_d), m);
|
||||
const expr_ref ni(m_rw.mk_regex_inter_normalize(p1.m_n, p2.m_n), m);
|
||||
++m_stats.m_intersect_pairs;
|
||||
std::pair<expr*, expr*> key(di.get(), ni.get());
|
||||
if (seen.contains(key)) {
|
||||
++m_stats.m_dedup_drops;
|
||||
continue;
|
||||
}
|
||||
seen.insert(key);
|
||||
push(result, oracle, di, ni);
|
||||
if (result.size() > threshold) {
|
||||
++m_stats.m_threshold_overruns;
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ struct split_stats {
|
|||
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_dedup_drops = 0; // duplicate <D,N> pairs skipped in intersect
|
||||
unsigned m_simplify = 0; // simplify() calls
|
||||
void reset() { *this = split_stats(); }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6019,6 +6019,7 @@ namespace seq {
|
|||
st.update("nseq split giveups", sp.m_giveups);
|
||||
st.update("nseq split threshold-overruns", sp.m_threshold_overruns);
|
||||
st.update("nseq split max-split-set", sp.m_max_split_set);
|
||||
st.update("nseq split dedup-drops", sp.m_dedup_drops);
|
||||
st.update("nseq split simplify", sp.m_simplify);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue