Skip to content

feat: let the search callback stop the search - #37

Merged
thiagomoretto merged 2 commits into
mainfrom
worktree-search-monitor
Oct 8, 2026
Merged

thiagomoretto merged 2 commits into
mainfrom
worktree-search-monitor

Conversation

@thiagomoretto

@thiagomoretto thiagomoretto commented Oct 8, 2026 •

Copy link
Copy Markdown
Owner

The SearchEvent callback becomes a search monitor. For solve_with, local_search_with and guided_local_search_with it returns ControlFlow<()>; Break stops the search, keeps the best solution, and still reports Done.

  • Hill climb checks the flow after each accepted move.
  • Guided search checks it after each round. New GuidedRound { iter, cost } event fires every round, so a monitor gets a tick even when nothing improves.
  • Construction keeps a plain FnMut(SearchEvent) observer: it cannot stop before every node is placed. solve_with reads a Break on FirstSolution and skips the improvement phase.
  • examples/early_stop.rs: no built-in rule. On X-n101-k25, the example stops once no gain of 1% or more lands for 2 seconds (MIN_GAIN_PCT = 0 gives plain "no improvement").

Breaking: callbacks for solve_with, local_search_with and guided_local_search_with must now return ControlFlow::Continue(()). search_log() does this already.

Tests: monitor_stops_guided_search, monitor_stops_before_improving, monitor_stops_hill_climb.

Known limit: GLS's first descent and each penalized descent run silent, so a stop lands between rounds, not inside one.

The SearchEvent callback now returns ControlFlow<()>. Break ends the
descent or guided search at once, keeps the best solution, and still
reports Done. Construction ignores it: no solution exists before every
node is placed.

Guided search now fires GuidedRound every round, so a monitor gets a
tick even when nothing improves. examples/early_stop stops once no gain
of 1% or more lands for 2 seconds.

Breaking: callbacks must return ControlFlow::Continue(()) to go on.
@thiagomoretto
thiagomoretto marked this pull request as ready for review October 8, 2026 14:02
Construction keeps a plain observer: it cannot stop, so its type no
longer pretends it can. solve_with reads a Break on FirstSolution and
skips the improvement phase.

One stop closure in descend, a bool in GLS instead of a ControlFlow
carried across rounds, and the example runs on X-n101-k25 through
cvrplib instead of a hand-rolled instance.
@thiagomoretto
thiagomoretto merged commit 859bd60 into main Oct 8, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant