Agent-Logs-Url: https://github.com/Z3Prover/z3/sessions/04321ea7-2a53-4ed5-9f43-816dc6f7476b Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
2 KiB
[nseq] Soundness bug: str.contains not preserved through concatenation
Labels: bug, c3, nseq, soundness
Summary
The nseq solver returns sat for a benchmark that asserts:
zis a substring ofy(str.contains y z)x = y ++ yzis NOT a substring ofx(not (str.contains x z))
The third assertion contradicts the first two, so the formula should be unsat.
The seq solver correctly returns unsat; nseq incorrectly returns sat.
Affected benchmark
| File | seq verdict | nseq verdict |
|---|---|---|
contains-4.smt2 |
unsat | sat (WRONG) |
Data from: https://github.com/Z3Prover/z3/discussions/9071
Reproducing example
; contains-4.smt2 — EXPECTED: unsat, nseq returns: sat
(set-logic QF_S)
(declare-const x String)
(declare-const y String)
(declare-const z String)
(assert (str.contains y z))
(assert (= x (str.++ y y)))
(assert (not (str.contains x z)))
(check-sat)
Analysis
If str.contains y z is true, then y = L ++ z ++ R for some L, R.
Then x = y ++ y = L ++ z ++ R ++ L ++ z ++ R, so z is a substring of x.
Therefore not (str.contains x z) is a contradiction.
The nseq solver should derive this via the combination of:
contains_true_axiom:str.contains y z→y = f1 ++ z ++ f2(skolems)- The equality
x = y ++ y - The Nielsen graph constraint that propagates the concatenation decomposition
The root cause may be that the nseq solver does not propagate str.contains facts
through word equation equalities in the Nielsen graph. When x = y ++ y is processed
as a word equation, the contains constraint on y should propagate to derive a contains
constraint on x, but this inference appears to be missing.
Files to investigate
src/ast/rewriter/seq_axioms.cpp—contains_true_axiom,unroll_not_containssrc/smt/seq/seq_nielsen.h/seq_nielsen.cpp— word equation propagationsrc/smt/theory_nseq.cpp—assign_ehfor contains,populate_nielsen_graph