3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-07-16 20:15:43 +00:00

seq_split: fix derivative-complement soundness+perf via canonical range_predicate

Resolves the WIP soundness bug. Root cause: the char-classes emitted for cofactor conditions were non-canonical and unrecognized downstream (of_pred(lambda) -> opaque select(lambda,ele); raw range unions carried (and true RANGE) that is_char_const_range rejected). Fix: mk_charclass_re maps the cofactor condition (true/false/and/or/not/=/char.<=) to the canonical seq::range_predicate via its Boolean ops, then range_predicate_to_regex (seq_range_collapse.h) yields a canonical char-class regex the derivative/emptiness/primitive path handles natively. Also: derive_of_pred beta-reduces select(lambda,ele) (general of_pred soundness fix).

RESULT on gen-lb (119): 0 default disagreements, 0 nseq spurious-unsat. L15 negcount family (27) timeout->solved: e.g. l15-digit-m3-dash now sat in 0.02s (dfs-nodes 33071->55, split complement/max-split-set eliminated). No regression (L11 sat, L14 unsat). Validates the notes.md derivative-based split redesign for star-free complements.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Margus Veanes 2026-07-03 23:44:09 +03:00
parent 22eb098cd9
commit 07451d8922
3 changed files with 81 additions and 11 deletions

View file

@ -427,10 +427,22 @@ namespace seq {
expr_ref empty(re().mk_empty(re_sort), m);
expr_ref eps(re().mk_to_re(u().str.mk_empty(seq_sort)), m);
// Apply predicate to the element
array_util autil(m);
expr* args[2] = { pred, m_ele };
expr_ref cond(autil.mk_select(2, args), m);
// Apply the predicate to the current element. When `pred` is a lambda,
// beta-reduce select(lambda, ele) so the resulting character condition is
// in the range/eq form the derivative's condition analysis
// (is_char_const_range / eval_path_cond) understands; a raw
// (select (lambda ..) ele) would be opaque and mishandled downstream.
expr_ref cond(m);
if (is_lambda(pred)) {
var_subst subst(m);
expr* arg = m_ele;
cond = subst(to_quantifier(pred)->get_expr(), 1, &arg);
}
else {
array_util autil(m);
expr* args[2] = { pred, m_ele };
cond = autil.mk_select(2, args);
}
return mk_ite(cond, eps, empty);
}