Fix inconsistent optimization result with unvalidated LP bound (#10028)#10040
Merged
Conversation
When an objective shares symbols with other theories (e.g. it occurs inside the auxiliary uninterpreted function used to encode a large `distinct`), the arithmetic relaxation only yields a HINT for the optimum, which may over-estimate the true optimum and be unachievable by any model. opt_solver::maximize_objective committed this hint into m_objective_values *before* validating it with check_bound, and never rolled it back when validation failed. Meanwhile optsmt::geometric_lex ignored the boolean return value and asserted the blocker derived from the unachievable hint, terminating the search prematurely. The result was a reported optimum that neither is achievable nor matches the returned model (e.g. objective 20 with a model where x9 = 500, while the true optimum is 55). Fix: - opt_solver.cpp: do not commit the hint before it is validated. When validation fails, update_objective now records the actual (achievable) model value instead of the stale over-estimate. The no-model case keeps its previous behavior. - optsmt.cpp: geometric_lex now honors the validation result. When the hint could not be validated, it discards the poisoned blocker and tightens from the real model value, so the search keeps converging toward the true optimum. When the hint is valid, behavior is unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
e1be189 to
458a5f6
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #10028.
Problem
Minimizing an integer variable over a problem containing a large
distinctconstraint returned an inconsistent result: the reported optimum did not match the returned model, and it was not the true optimum.Reproducer from the issue (a Golomb-ruler problem, true optimum = 55):
Root cause
A
distinctwith more than 32 arguments is encoded with a fresh uninterpreted sort and function (smt_internalizer.cpp), so the objective variable becomes a shared symbol whose feasible values depend on EUF as well as arithmetic. The arithmetic relaxation therefore only produces a hint for the optimum, which may over-estimate it and be unachievable.Two combined defects:
opt_solver::maximize_objectivecommitted the hint intom_objective_valuesbefore validating it withcheck_bound, and never rolled it back when validation failed.update_objectiveonly ever raises the stored value, so the real (achievable) model value was discarded.optsmt::geometric_lexignored the boolean return value and asserted the blocker derived from the unachievable hint, so the very nextcheck_satwas UNSAT and the search terminated prematurely, reporting the bogus bound together with a non-matching model.Fix
opt_solver.cpp: do not commit the hint before it is validated. On validation failure,update_objectivenow records the actual achievable model value. The no-model early-return keeps its previous behavior.optsmt.cpp:geometric_lexnow honors the validation result. When the hint could not be validated, it discards the poisoned blocker and tightens from the real model value, so the search keeps converging toward the true optimum. When the hint is valid, the condition reduces to the original expression and behavior is unchanged.After the fix the same reproducer produces consistent, monotonically-improving bounds (325 → 85 → … → 58 → … → 55), and the reported objective always matches the returned model.
Testing
Exact-optimum, fast-terminating checks (all correct): EUF-forced minimum (= 5),
distinct(x, 0..32)minimize (= 33), Golomb n=8 (= 34), plus basic min/max, real objective, box, lex, pareto, and weighted soft/maxsat.Regression suites, rebuilt in both Release and Debug:
test-z3 /aregressions/smt2(908 files,model_validate=true)