Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhances solver with plateau detection, adds missing Python options #80

Merged

Conversation

merschformann
Copy link
Member

@merschformann merschformann commented Dec 19, 2024

Description

Introduced plateau detection for solvers, allowing termination based on lack of improvement over time or iterations.

Changes

  • Added PlateauOptions struct for plateau detection configuration.
  • Integrated plateau detection into solve process.
  • Updated github.com/nextmv-io/sdk dependency to include an upstream golden file test fix.
  • Added golden file tests for plateau stopping criterion.
  • Adds missing stop balancing and max time horizon options for Python nextroute.
  • Modified Python nextroute options test to ensure we won't miss other Go implementation options in future (avoid drift).

Preview

This PR adds the option to define stopping criteria when the solve process (value progression / improvement) starts to stagnate / converge.
This can be done via the typical nextroute.ParallelSolveOptions struct or simply via the options (applicable for most cases):

Nextmv Hybrid Optimization Platform
Usage:
...
  -solve.plateau.absolutethreshold float
        absolute threshold for significant improvement (env SOLVE_PLATEAU_ABSOLUTE_THRESHOLD) (default -1)
  -solve.plateau.duration duration
        maximum duration without (significant) improvement (env SOLVE_PLATEAU_DURATION)
  -solve.plateau.iterations int
        maximum number of iterations without (significant) improvement (env SOLVE_PLATEAU_ITERATIONS)
  -solve.plateau.relativethreshold float
        relative threshold for significant improvement (env SOLVE_PLATEAU_RELATIVE_THRESHOLD)
  -solve.rundeterministically

@merschformann merschformann changed the title Enhances Solver with Plateau Detection Enhances solver with plateau detection, adds missing Python options Dec 20, 2024
}

// IsStop returns true if the solver should stop due to a detected plateau.
func (t *plateauTracker) IsStop(iterations int, elapsed time.Duration) bool {
Copy link
Contributor

@dirkschumacher dirkschumacher Dec 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rename the function to ShouldStop? Also because we have the concept of a Stop in nextroute. But what the function does is to decide if the solver should stop.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, good call. 👍

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed it to ShouldTerminate to stay away from the Stop double meaning. 😊

@@ -351,6 +363,12 @@ func (s *parallelSolverImpl) Solve(
if totalIterations.Add(1) >= int64(interpretedParallelSolveOptions.Iterations) {
cancel()
}
if s.plateauTracker.IsStop(
Copy link
Contributor

@dirkschumacher dirkschumacher Dec 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This gets called very often. Maybe we can add a benchmark test that ensures that IsStop never allocates and does totalIterations.Load() cost a lot? Because we can reuse the result of totalIterations.Add(1) then we don't have to lock again (if Load() locks).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking the same thing. Now that you mention it, I think avoiding the double atomic call is better. I doubt that it makes concurrency issues worse (which I was worried about before for some reason), but may even make it better. For sure, it will avoid extra cost (however small they may be).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify, you are only worried about a potential performance loss for when a user activates plateau tracking, right? (it's off by default - so shouldn't cause a regression)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think the code in the hot path of the solver needs to be as fast as possible and ideally should not allocate (which it does not, unless some interface related hidden allocations are triggered). With the change of how the iteration count is retrieved the tracker will have minimal overhead if it is disabled.

Copy link
Member

@sebastian-quintero sebastian-quintero left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@dirkschumacher dirkschumacher merged commit 10157b2 into develop Dec 24, 2024
34 checks passed
@dirkschumacher dirkschumacher deleted the merschformann/adding-early-termination-criteria branch December 24, 2024 07:32
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.

4 participants