3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-07-05 06:46:11 +00:00

Fix qe-lite de Bruijn reindexing after bounded quantifier expansion (#9996)

`qe-lite` could produce malformed formulas when expanding bounded
quantifiers under nested binders, leaving outer de Bruijn indices
unshifted after eliminating an inner quantifier (e.g., `(:var 1)`
escaping capture). This change fixes index normalization in that rewrite
path and adds a regression for the reported forall/exists arithmetic
case.

- **Rewrite correctness in bounded quantifier expansion**
- In `src/qe/lite/qe_lite_tactic.cpp`, after substituting bounded
variables in payload conjuncts, apply `inv_var_shifter(num_decls)` so
outer bound variables are reindexed relative to the removed binder.
- This preserves quantifier structure correctness when
`try_expand_bounded_quantifier` eliminates an inner quantifier.

- **Regression coverage for the reported pattern**
- In `src/test/smt_context.cpp`, add a focused quantified arithmetic
formula matching the bug shape:
    - outer `forall (x, x4)`
    - inner `exists (y)`
    - mixed inequalities that trigger qe-lite bounded expansion
- Assert the formula is unsatisfiable, preventing reintroduction of
invalid index handling in this path.

```c++
inst = vs(p, subst_map.size(), subst_map.data());
shift(inst, num_decls, inst); // reindex outer de Bruijn vars after eliminating inner quantifier
```

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
Copilot 2026-06-29 09:53:02 -07:00 committed by GitHub
parent a5454ec375
commit 56bf04e30a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 30 additions and 0 deletions

View file

@ -2467,6 +2467,7 @@ private:
cur_vals[i] = var_lbs[i];
var_subst vs(m, false);
inv_var_shifter shift(m);
expr_ref_vector disjuncts(m);
while (true) {
@ -2479,6 +2480,7 @@ private:
for (expr* p : payload) {
expr_ref inst(m);
inst = vs(p, subst_map.size(), subst_map.data());
shift(inst, num_decls, inst);
inst_conjs.push_back(inst);
}
expr_ref inst_body(m);