mirror of
https://github.com/Z3Prover/z3
synced 2026-07-15 03:25:43 +00:00
Revert #10052: eager-commit of infinitesimal LP hint is unsound for shared-symbol objectives (#10057)
## Summary Reverts #10052, whose eager-commit of infinitesimal LP hints is **unsound** for shared-symbol objectives. #10052 added, in `opt_solver::maximize_objective`: ```cpp if (val.is_finite() && !val.get_infinitesimal().is_zero() && val > m_objective_values[i]) m_objective_values[i] = val; ``` on the premise that *"a non-zero infinitesimal ⇒ an exact, unattainable strict optimum, so the LP hint is authoritative."* That holds for a **pure LP**, but is **false when the objective is a shared symbol** with another theory (e.g. the auxiliary uninterpreted function used to encode a `distinct` with > 32 arguments). There the LP relaxation only yields a *hint* that can be a strict **over-estimate**, and #10052 commits it without validation — exactly the class of bound that #10028's `check_bound` exists to reject. ## Counterexample A 6-mark Golomb ruler over integers `x0..x5`, with the `distinct` padded to > 32 arguments so `x5` becomes a shared symbol; objective is a real `obj` with `obj > x5` (full file attached to #5720): - Ground truth: `minimize x5` (integer) ⇒ **17**; since `obj > x5`, the true optimum is **`17 + ε`**. - With #10052, z3 reports **`(obj (+ 5.0 epsilon))`** — wrong and **infeasible** (`obj < 6` is `unsat`; the returned model itself has `x5 = 35, obj = 49.5`). | benchmark | with #10052 (master) | after this revert | | --- | --- | --- | | Golomb `bug.smt2` (shared symbol) | `(obj (+ 5.0 epsilon))` ❌ infeasible | `(obj 18)` ✅ consistent | | #5720 (`max r < 1`) | `1 - epsilon` ✅ | `0` ❌ (regression returns) | ## Tradeoff / follow-up This revert restores soundness on the shared-symbol case but **reintroduces the #5720 regression** (`max r<1` ⇒ `0`), which is why **#5720 has been reopened**. A correct fix should preserve the strict single-objective supremum **without** trusting an unvalidated shared-symbol hint — e.g. gate the eager commit on `!has_shared` (pure LP only), or validate the rational part of the hint while keeping the infinitesimal. The same blind spot affects the alternative `check_bound` guard proposed in #10051. Re: #5720 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
f37b435923
commit
835679b27d
1 changed files with 0 additions and 18 deletions
|
|
@ -342,24 +342,6 @@ namespace opt {
|
|||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// A finite hint with a non-zero infinitesimal is a strict
|
||||
// supremum/infimum (e.g. maximizing r subject to r < 1 yields
|
||||
// 1 - epsilon). No concrete model can attain such a value, and
|
||||
// check_bound() below cannot validate it either: opt_solver::mk_ge
|
||||
// drops the negative infinitesimal, turning the bound r >= 1 - epsilon
|
||||
// into the unsatisfiable r >= 1. Commit it eagerly here so that it is
|
||||
// neither overwritten by the strictly smaller current model value in
|
||||
// update_objective() nor lost when validation fails and this routine
|
||||
// returns false (callers such as optsmt::geometric_lex then report
|
||||
// m_objective_values as the optimum). This restores the pre-#10028
|
||||
// behavior for strict optima while leaving the plain-rational
|
||||
// (zero-infinitesimal) over-estimates that #10028 fixed to the
|
||||
// deferred-commit logic below.
|
||||
//
|
||||
if (val.is_finite() && !val.get_infinitesimal().is_zero() && val > m_objective_values[i])
|
||||
m_objective_values[i] = val;
|
||||
|
||||
//
|
||||
// retrieve value of objective from current model and update
|
||||
// current optimal.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue