Stop conditions

Stop conditions are essential components of the simulated annealing algorithm that determine when the optimization process should terminate. Without a properly defined stop condition, the simulation might run indefinitely or terminate prematurely before finding a satisfactory solution.

In this framework, a stop condition is implemented as a callable (function or object) that monitors the progress of the annealing process. It receives the current AnnealingState as an argument and returns a boolean value:

  • True: The simulation should end immediately.

  • False: The simulation should continue to the next iteration.

The AnnealingState provides rich information for decision-making, including the current iteration count, current temperature, and details about the best solution found so far. This allows for various strategies, such as stopping after a certain number of iterations, when a specific fitness threshold is reached, or when the temperature drops below a certain level.

Solution based stop conditions

Solution based stop conditions focus on the function values encountered during the course of the simulation.

Improvement Threshold

The SolutionImprovementThreshold stops the simulation when the best solution of the simulation hasn’t been updated for a certain amount of iterations.

Key characteristics:

  • Initialization: It takes a positive number of iterations that the simulation is allowed to run without finding a better (local) optimum.

  • Reset Behavior: The internal counter is automatically initialized or reset when the simulation is started anew.

Warning

SolutionImprovementThreshold is stateful. The internal counter and best value reset when state.iteration == 0, which happens automatically at the start of every simulate() call, so reusing an instance across multiple simulate() calls is safe.

If you drive the annealing loop manually and the iteration counter does not start at 0, the reset will not trigger — the counter will continue from the previous run and the stop condition may fire immediately or never, depending on the leftover state. In that case, create a new instance for each run.

Time based stop conditions

Time-based conditions allow the simulation to be constrained by wall-clock duration. While currently focused on real-time elapsed, this category may expand in the future to include CPU-time-based metrics.

Iteration Threshold

The IterationThreshold stops the simulation after a predefined number of iterations. This approach is not recommended for calculation heavy simulations.

Key characteristics:

  • Initialization: It takes a postive number of iterations.

  • Reset Behavior: The internal counter is automatically initialized or reset when the simulation is started anew

(Real) Time Threshold

The TimeThreshold strategy monitors the actual elapsed time (wall-clock time) since the start of the simulation. It is important to distinguish this from CPU time: TimeThreshold measures the time as perceived by a human observer, which includes time spent on I/O or waiting for system resources.

Key characteristics:

  • Initialization: It takes a duration (either as a timedelta object or a float representing seconds).

  • Reset Behavior: The internal timer is automatically initialized or reset when the simulation reaches its first iteration (iteration 0), ensuring the measurement starts exactly when the algorithm begins.

  • Strategic Use: While it can be used as a standalone stop condition, it is most effective when combined with other criteria to ensure predictable simulation runs.

Warning

TimeThreshold is stateful. The timer resets when state.iteration == 0, which happens automatically at the start of every simulate() call, so reusing an instance across multiple simulate() calls is safe.

If you drive the annealing loop manually and the iteration counter does not start at 0, the reset will not trigger — the timer will continue from where the previous run left off, which is almost certainly not what you want. In that case, create a new TimeThreshold instance for each run.

from datetime import timedelta
from time import sleep
from altbacken.core.state import AnnealingState
from altbacken.external.stop import TimeThreshold

stop_condition = TimeThreshold(timedelta(seconds=2))
state = AnnealingState.initial(2.0, 4.0)
assert not stop_condition(state) # Timer starts now
sleep(2.5)
state.iteration += 1 # Otherwise reset behaviour would be triggered
assert stop_condition(state)

If you intend to use only seconds, a float can be provided in the constructor

from altbacken.external.stop import TimeThreshold

stop_condition = TimeThreshold(2)

Temperature based stop conditions

Temperature based stop conditions monitor the temperature to decide if the simulation should stop. This can be either the temperature itself or the the change in temperature.

Temperature Threshold

The TemperatureThreshold monitors the temperature value and stops the simulation if the temperature falls beneath the predefined threshold.

Key characteristics:

  • Initialization: It takes a temperature threshold float value.

  • Reset Behavior: As it has no state, it can be used multiple times without issues.

Special stop conditions

Some stop conditions are more technical in nature and not related to the simulation domain. They can be used to create complex stop conditions on basis of existing ones or offer further debug options.

Compound Condition

The CompoundStopCondition acts as a wrapper to perform boolean logic on other stop conditions. The following code snippet defines stop as Keep the simulation running as long as the temperature is above or eqaul to 10 and less than 100 iterations are performed. Supported operations are the binary operations and (&), or (|) and inversion (~).

left: TemperatureThreshold = TemperatureThreshold(10.0)
right: IterationThreshold = IterationThreshold(100)
stop: StopCondition = CompoundStopCondition(left) & right