3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-07-27 09:22:41 +00:00

opt: keep infinitesimal LP optimum instead of falling back to model value

When an objective's optimum is an open (strict) bound, the arithmetic
relaxation returns a value carrying a non-zero infinitesimal (e.g.
minimizing a real x subject to x > 0, whose infimum is the unattained 0,
reported as "epsilon"). opt_solver::maximize_objective validates such a
hint with check_bound(), which asserts the objective is >= val via mk_ge
and searches for a model reaching it. mk_ge cannot faithfully encode the
infinitesimal (it drops a negative infinitesimal and turns a positive one
into a strict bound), so this validation always fails spuriously for an
open optimum. Since #10028 (fdc32d0e6) stopped committing the hint before
validation, this false negative now discards the true infinitesimal
optimum and reports an attainable - strictly worse - model value instead
(x = 1 rather than epsilon).

Treat a hint with a non-zero infinitesimal as valid in check_bound: for
such open bounds the relaxation value is exact. Hints without an
infinitesimal (such as the integer objective of #10028) are still
validated normally, so that fix is preserved.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Lev Nachmanson 2026-07-05 02:31:15 -07:00 committed by GitHub
parent 557a0cadab
commit 1d936e2384
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -358,9 +358,25 @@ namespace opt {
//
// check that "val" obtained from optimization hint is a valid bound.
//
// A hint with a non-zero infinitesimal denotes an *open* (strict)
// optimum: the objective approaches "val" but no concrete model attains
// it (e.g. minimizing a real x subject to x > 0, whose infimum is the
// unattained 0, reported as "epsilon"). check_bound validates a hint by
// asserting the objective is >= val (mk_ge) and searching for a model
// that reaches it, but mk_ge cannot faithfully encode the infinitesimal
// (a negative infinitesimal is dropped, a positive one becomes a strict
// bound), so this search always fails spuriously for an open optimum.
// In that case the arithmetic relaxation value is exact, so accept the
// hint rather than discarding the true optimum and falling back to an
// attainable - and therefore strictly worse - model value (issue #5314).
// Hints without an infinitesimal (such as the integer objective of
// #10028) are still validated normally, preserving that fix.
//
auto check_bound = [&]() {
SASSERT(has_shared);
if (!val.get_infinitesimal().is_zero())
return true;
return bound_value(i, val) && l_true == m_context.check(0, nullptr);
};