pub struct LocalSearchPhaseFactory<S, M, F>where
S: PlanningSolution,
M: Move<S> + Clone + Send + Sync + 'static,
F: Fn() -> Box<dyn MoveSelector<S, M>> + Send + Sync,{ /* private fields */ }Expand description
Factory for creating local search phases.
Local search phases improve an existing solution by exploring neighboring solutions. The factory provides fresh phase instances for each solve, ensuring that internal state (like tabu lists or temperature) is reset.
§Type Parameters
S- The planning solution typeM- The move type (e.g.,ChangeMove,SwapMove)F- The closure type that creates move selectors
§Available Acceptors
hill_climbing: Only accept improving movestabu_search: Avoid recently visited statessimulated_annealing: Probabilistic acceptancelate_acceptance: Compare against historical scores
§Example
use solverforge_solver::manager::{LocalSearchPhaseFactory, SolverPhaseFactory};
use solverforge_solver::heuristic::r#move::ChangeMove;
use solverforge_solver::heuristic::selector::ChangeMoveSelector;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SimpleScore;
#[derive(Clone)]
struct S { values: Vec<Option<i32>>, score: Option<SimpleScore> }
impl PlanningSolution for S {
type Score = SimpleScore;
fn score(&self) -> Option<Self::Score> { self.score }
fn set_score(&mut self, score: Option<Self::Score>) { self.score = score; }
}
fn get_v(s: &S, idx: usize) -> Option<i32> { s.values.get(idx).copied().flatten() }
fn set_v(s: &mut S, idx: usize, v: Option<i32>) { if let Some(x) = s.values.get_mut(idx) { *x = v; } }
type M = ChangeMove<S, i32>;
// Hill climbing with step limit
let factory = LocalSearchPhaseFactory::<S, M, _>::hill_climbing(|| {
Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "value", vec![1, 2, 3]))
}).with_step_limit(1000);
// Tabu search
let tabu = LocalSearchPhaseFactory::<S, M, _>::tabu_search(7, || {
Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "value", vec![1, 2, 3]))
});
// Simulated annealing
let sa = LocalSearchPhaseFactory::<S, M, _>::simulated_annealing(1.0, 0.999, || {
Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "value", vec![1, 2, 3]))
});Implementations§
Source§impl<S, M, F> LocalSearchPhaseFactory<S, M, F>where
S: PlanningSolution,
M: Move<S> + Clone + Send + Sync + 'static,
F: Fn() -> Box<dyn MoveSelector<S, M>> + Send + Sync,
impl<S, M, F> LocalSearchPhaseFactory<S, M, F>where
S: PlanningSolution,
M: Move<S> + Clone + Send + Sync + 'static,
F: Fn() -> Box<dyn MoveSelector<S, M>> + Send + Sync,
Sourcepub fn new(search_type: LocalSearchType, move_selector_factory: F) -> Self
pub fn new(search_type: LocalSearchType, move_selector_factory: F) -> Self
Creates a new local search phase factory with the specified search type.
§Arguments
search_type- The type of local search algorithmmove_selector_factory- A closure that creates move selectors
§Example
use solverforge_solver::manager::{LocalSearchType, LocalSearchPhaseFactory};
use solverforge_solver::heuristic::r#move::ChangeMove;
use solverforge_solver::heuristic::selector::ChangeMoveSelector;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SimpleScore;
type M = ChangeMove<S, i32>;
let factory = LocalSearchPhaseFactory::<S, M, _>::new(
LocalSearchType::TabuSearch { tabu_size: 10 },
|| Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "v", vec![1, 2])),
);Sourcepub fn with_step_limit(self, limit: u64) -> Self
pub fn with_step_limit(self, limit: u64) -> Self
Sets the step limit for this phase.
The phase will terminate after executing this many steps. This is useful for multi-phase configurations where you want to limit time spent in each phase.
§Example
use solverforge_solver::manager::LocalSearchPhaseFactory;
use solverforge_solver::heuristic::r#move::ChangeMove;
use solverforge_solver::heuristic::selector::ChangeMoveSelector;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SimpleScore;
type M = ChangeMove<S, i32>;
let factory = LocalSearchPhaseFactory::<S, M, _>::hill_climbing(|| {
Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "v", vec![1, 2]))
}).with_step_limit(500);Sourcepub fn hill_climbing(move_selector_factory: F) -> Self
pub fn hill_climbing(move_selector_factory: F) -> Self
Creates a factory with hill climbing acceptor.
Hill climbing only accepts moves that improve the score. It is simple and fast, but can easily get stuck in local optima.
§Example
use solverforge_solver::manager::LocalSearchPhaseFactory;
use solverforge_solver::heuristic::r#move::ChangeMove;
use solverforge_solver::heuristic::selector::ChangeMoveSelector;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SimpleScore;
type M = ChangeMove<S, i32>;
let factory = LocalSearchPhaseFactory::<S, M, _>::hill_climbing(|| {
Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "value", vec![1, 2, 3]))
});Sourcepub fn tabu_search(tabu_size: usize, move_selector_factory: F) -> Self
pub fn tabu_search(tabu_size: usize, move_selector_factory: F) -> Self
Creates a factory with tabu search acceptor.
Tabu search maintains a list of recently made moves and forbids reversing them. This helps escape local optima by forcing exploration.
§Arguments
tabu_size- Number of recent moves to remembermove_selector_factory- Closure that creates move selectors
§Example
use solverforge_solver::manager::LocalSearchPhaseFactory;
use solverforge_solver::heuristic::r#move::ChangeMove;
use solverforge_solver::heuristic::selector::ChangeMoveSelector;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SimpleScore;
type M = ChangeMove<S, i32>;
// Remember last 7 moves
let factory = LocalSearchPhaseFactory::<S, M, _>::tabu_search(7, || {
Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "v", vec![1, 2, 3]))
});Sourcepub fn simulated_annealing(
starting_temp: f64,
decay_rate: f64,
move_selector_factory: F,
) -> Self
pub fn simulated_annealing( starting_temp: f64, decay_rate: f64, move_selector_factory: F, ) -> Self
Creates a factory with simulated annealing acceptor.
Simulated annealing accepts worse moves with a probability that decreases over time. Initially, it explores widely; as the “temperature” cools, it becomes more selective.
§Arguments
starting_temp- Initial temperature (higher = more exploration)decay_rate- Rate at which temperature decreases (0.0 to 1.0)move_selector_factory- Closure that creates move selectors
§Example
use solverforge_solver::manager::LocalSearchPhaseFactory;
use solverforge_solver::heuristic::r#move::ChangeMove;
use solverforge_solver::heuristic::selector::ChangeMoveSelector;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SimpleScore;
type M = ChangeMove<S, i32>;
// Start at temperature 1.0, decay by 0.1% per step
let factory = LocalSearchPhaseFactory::<S, M, _>::simulated_annealing(
1.0,
0.999,
|| Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "v", vec![1, 2, 3])),
);Sourcepub fn late_acceptance(size: usize, move_selector_factory: F) -> Self
pub fn late_acceptance(size: usize, move_selector_factory: F) -> Self
Creates a factory with late acceptance acceptor.
Late acceptance compares the new score against the score from N steps ago. If the new score is better than or equal to that historical score, the move is accepted. This provides a balance between exploration and exploitation.
§Arguments
size- Number of steps to look backmove_selector_factory- Closure that creates move selectors
§Example
use solverforge_solver::manager::LocalSearchPhaseFactory;
use solverforge_solver::heuristic::r#move::ChangeMove;
use solverforge_solver::heuristic::selector::ChangeMoveSelector;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SimpleScore;
type M = ChangeMove<S, i32>;
// Compare against score from 400 steps ago
let factory = LocalSearchPhaseFactory::<S, M, _>::late_acceptance(400, || {
Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "v", vec![1, 2, 3]))
});Sourcepub fn value_tabu_search(
value_tabu_size: usize,
move_selector_factory: F,
) -> Self
pub fn value_tabu_search( value_tabu_size: usize, move_selector_factory: F, ) -> Self
Creates a factory with value tabu acceptor.
Value tabu remembers recently assigned values and forbids reassigning them. This is different from entity tabu in that it tracks values, not entity-variable combinations.
§Arguments
value_tabu_size- Number of recent values to forbidmove_selector_factory- Closure that creates move selectors
§Example
use solverforge_solver::manager::LocalSearchPhaseFactory;
use solverforge_solver::heuristic::r#move::ChangeMove;
use solverforge_solver::heuristic::selector::ChangeMoveSelector;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SimpleScore;
type M = ChangeMove<S, i32>;
// Forbid last 5 assigned values
let factory = LocalSearchPhaseFactory::<S, M, _>::value_tabu_search(5, || {
Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "v", vec![1, 2, 3]))
});Sourcepub fn move_tabu_search(
move_tabu_size: usize,
aspiration_enabled: bool,
move_selector_factory: F,
) -> Self
pub fn move_tabu_search( move_tabu_size: usize, aspiration_enabled: bool, move_selector_factory: F, ) -> Self
Creates a factory with move tabu acceptor.
Move tabu remembers recently made moves (by hash) and forbids making the same move again. Supports aspiration criterion: tabu moves can be accepted if they lead to a new best solution.
§Arguments
move_tabu_size- Number of recent moves to forbidaspiration_enabled- Whether to allow tabu moves that reach new best scoremove_selector_factory- Closure that creates move selectors
§Example
use solverforge_solver::manager::LocalSearchPhaseFactory;
use solverforge_solver::heuristic::r#move::ChangeMove;
use solverforge_solver::heuristic::selector::ChangeMoveSelector;
use solverforge_core::domain::PlanningSolution;
use solverforge_core::score::SimpleScore;
type M = ChangeMove<S, i32>;
// Forbid last 10 moves, with aspiration enabled
let factory = LocalSearchPhaseFactory::<S, M, _>::move_tabu_search(10, true, || {
Box::new(ChangeMoveSelector::<S, i32>::simple(get_v, set_v, 0, "v", vec![1, 2, 3]))
});