Documentation
Local Search
Local-search acceptors, foragers, move selectors, and score-level annealing.
Local search repeatedly generates candidate moves, scores them, accepts or rejects them, and commits one accepted candidate. It is the normal improvement phase after construction.
[[phases]]
type = "local_search"
[phases.acceptor]
type = "late_acceptance"
late_acceptance_size = 400
[phases.forager]
type = "accepted_count"
limit = 4
[phases.move_selector]
type = "change_move_selector"
value_candidate_limit = 32
Acceptor
The acceptor decides whether a scored candidate can be accepted.
| Acceptor | Use |
|---|---|
hill_climbing |
accept only improving moves |
simulated_annealing |
allow controlled regressions while cooling |
tabu_search |
avoid recently visited entities, values, or moves |
late_acceptance |
compare against a historical score window |
great_deluge |
compare against a decaying score boundary |
step_counting_hill_climbing |
hold a boundary for a fixed step interval |
diversified_late_acceptance |
late acceptance with diversification pressure |
Score-Level Simulated Annealing
Simulated annealing supports per-score-level temperatures and hard-regression policy.
[phases.acceptor]
type = "simulated_annealing"
level_temperatures = [5.0, 500.0]
hard_regression_policy = "temperature_controlled"
[phases.acceptor.calibration]
sample_size = 64
target_acceptance_probability = 0.75
fallback_temperature = 2.0
level_temperatures are ordered from highest-priority score level to
lowest-priority score level. hard_regression_policy decides whether hard-score
regressions can be temperature-controlled or are never accepted.
Forager
The forager decides which accepted candidate is committed.
[phases.forager]
type = "accepted_count"
limit = 4
The accepted-count forager stops the current selector step after collecting
limit accepted candidates, then picks the best candidate inside that finite
horizon. It is the default for broad stock models because it lets streaming
selectors improve incumbents under short budgets. Use best_score when you
intentionally want a full-neighborhood greedy scan, and use
limited_neighborhood when a selector itself needs a hard pre-scoring cap.
Move Selector
Move selection lives under [phases.move_selector].
[phases.move_selector]
type = "union_move_selector"
selection_order = "round_robin"
[[phases.move_selector.selectors]]
type = "change_move_selector"
value_candidate_limit = 32
[[phases.move_selector.selectors]]
type = "swap_move_selector"
For selector details, start with Moves.
Union selectors can use sequential, round_robin,
rotating_round_robin, or stratified_random selection order. The current
stock defaults use fair ordering for broad unions so no child neighborhood owns
the prefix indefinitely.
Assignment-backed grouped scalar selectors are regular local-search selectors.
Use them when a model-owned ScalarGroup::assignment(...) should repair
uncovered required nullable slots, capacity conflicts, bounded reassignments,
same-sequence run gaps, value-window swaps, block reassignments, optional
occupant releases, or value rotations:
[phases.move_selector]
type = "grouped_scalar_move_selector"
group_name = "required_shift_assignment"
max_moves_per_step = 64
require_hard_improvement = true
Telemetry
Retained status and events preserve exact generated, evaluated, accepted,
not-doable, acceptor-rejected, forager-ignored, hard-delta, conflict-repair,
and construction-slot counters plus generation and evaluation durations.
Per-move-label telemetry reports generated, evaluated, accepted, applied,
not-doable, acceptor-rejected, forager-ignored, score-improving, score-equal,
score-worse, rejected-improving, and applied score-improvement totals. The
bounded applied-move trace records the selected candidate index, per-step
generated/evaluated/accepted/ignored counts, score delta, and hard feasibility
before and after the applied move. Displayed moves/s is a human-facing
derived value.
Variable Neighborhood Descent
VND is configured as local_search_type = "variable_neighborhood_descent" on a
local-search phase. It uses ordered neighborhoods and does not combine with
acceptor, forager, or move_selector in the same phase.
[[phases]]
type = "local_search"
local_search_type = "variable_neighborhood_descent"
[[phases.neighborhoods]]
type = "change_move_selector"
variable_name = "employee_idx"
[[phases.neighborhoods]]
type = "swap_move_selector"
variable_name = "employee_idx"
See Also
- Construction - creating the first solution
- Moves - selector family guide
- Termination - stopping local search