Repository navigation
Drop restart no-goods from incomplete slave searches - #277
Merged
Merged
Conversation
zayenz
marked this pull request as ready for review
November 13, 2026 05:37
When the slave configuration function returns false, the slave search is incomplete: it explores a restricted search space, for example a large neighbourhood. The no-goods recorded by that search only hold in the restricted space, but RBS passed them to the master configuration function, whose default posts them in the master. The master could then lose better solutions, and RBS could report a solution as optimal when it was not. RBS now passes the empty no-goods when the search that recorded them was incomplete. The result of the slave configuration when search starts was discarded before; it now determines whether that first search yields valid no-goods. The first search is still treated as complete for termination, so FlatZinc models whose slave function returns false on the first restart keep their behaviour.
zayenz
force-pushed
the
fix/rbs-incomplete-nogoods
branch
from
November 13, 2026 05:42
d41c085 to
18d4abf
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.
Problem
Restart-based search with no-goods can report a solution as optimal when it is not.
Space::slave()returning false means the slave search is incomplete: it explores a restricted search space, such as an LNS neighbourhood. The no-goods recorded by that search only rule out parts of the restricted space.RBS::nextstill passed them toSpace::master(), whose default posts them in the master. The master then lost solutions that the restriction had excluded only in that one slave.Small example (the new test): four distinct variables over 0..3, minimise
x0. The first slave restrictsx2andx3to {0,1} and returns false. That search findsx0 = 2and records no-goods that rule outx0 = 0andx0 = 1. Posted in the master, those no-goods fail it, and RBS finishes, claimingx0 = 2is optimal, althoughx0 = 0is feasible (0,1,2,3).The first slave is configured in
Gecode::RBS::RBS(gecode/search/rbs.hpp), which discarded its result. Its no-goods were always treated as valid, even for a restricted first slave.This also made the relax crash fixed in #276 frequent: in
photo -nogoods true, the wrong no-goods remove values from the master thatrelaxlater tries to keep from the last solution.Fix
RBS::master_nogoods()returns the empty no-goods (NoGoods::eng) when the search that recorded them was incomplete, and the engine's no-goods otherwise. Both restart paths inRBS::nextuse it.Search::Seq::rbsengineoverload takes it; the old overload stays for binary compatibility and passestrue.slave()returns false on the first restart foron_restartmodels, so honouring it there would change when those models finish. Only no-goods are affected.Space::slave()andMetaInfo::nogoods()states the contract.No public API changes. Searches whose slaves are complete behave exactly as before. Searches with incomplete slaves post fewer no-goods, so they may explore more but no longer lose solutions.
Test
Search::RBS::IncompleteNoGoodsis the example above withnogoods_limit = 128. Without the fix it reportsx0 = 2and finishes. With the fix it findsx0 = 0.A two-thread variant passed without the fix as well, so it is not included.
Validation
Linux (erebor), GCC 15 Release:
gecode-test -test Search::RBS::IncompleteNoGoodsgecode-test -threads 4 -tag checkgecode-test -threads 4 -tag standard -test ^Search::gecode-test -threads 4 -tag standard -test ^NoGoods::gecode-test -threads 4 -tag standard -test ^FlatZincphoto -restart constant -restart-scale {1,5,8} -nogoods true -seed {1..8} -time 1500 1main: 15/24 on 6.5.0)Linux, Clang 21 Debug with ASan and UBSan:
-test ^Search::RBS37/37 and-tag check -test ^NoGoods::96/96.macOS Release: the new test fails without the fix and passes with it.
uv run misc/tidy.py --checkpasses.Relation to #276
The two fixes are independent. With only this fix,
photo -restart constant -nogoods truedid not crash in the sweep above, because the relax failures become rare. The relax bug is still there, so #276 is still needed.Not fixed here
RBS::stopped()can give the wrong answer and statistics are counted twice.