solverforge_solver/manager/phase_factory/
local_search.rs

1//! Local search phase factory with zero type erasure.
2
3use std::marker::PhantomData;
4
5use solverforge_core::domain::PlanningSolution;
6use solverforge_scoring::ScoreDirector;
7
8use crate::heuristic::{Move, MoveSelector};
9use crate::phase::localsearch::{
10    AcceptedCountForager, Acceptor, HillClimbingAcceptor, LateAcceptanceAcceptor,
11    LocalSearchForager, LocalSearchPhase, SimulatedAnnealingAcceptor, TabuSearchAcceptor,
12};
13
14use super::super::PhaseFactory;
15
16/// Zero-erasure factory for local search phases.
17///
18/// All types flow through generics - MoveSelector `MS`, Acceptor `A`,
19/// and Forager `Fo` are all concrete types.
20///
21/// # Type Parameters
22///
23/// * `S` - The planning solution type
24/// * `M` - The move type
25/// * `MS` - The move selector type (concrete)
26/// * `A` - The acceptor type (concrete)
27/// * `Fo` - The forager type (concrete)
28pub struct LocalSearchPhaseFactory<S, M, MS, A, Fo>
29where
30    S: PlanningSolution,
31    M: Move<S>,
32    MS: MoveSelector<S, M>,
33    A: Acceptor<S>,
34    Fo: LocalSearchForager<S, M>,
35{
36    move_selector: MS,
37    acceptor: A,
38    forager: Fo,
39    step_limit: Option<u64>,
40    _marker: PhantomData<fn() -> (S, M)>,
41}
42
43impl<S, M, MS, A, Fo> LocalSearchPhaseFactory<S, M, MS, A, Fo>
44where
45    S: PlanningSolution,
46    M: Move<S>,
47    MS: MoveSelector<S, M>,
48    A: Acceptor<S>,
49    Fo: LocalSearchForager<S, M>,
50{
51    /// Creates a new factory with concrete components.
52    pub fn new(move_selector: MS, acceptor: A, forager: Fo) -> Self {
53        Self {
54            move_selector,
55            acceptor,
56            forager,
57            step_limit: None,
58            _marker: PhantomData,
59        }
60    }
61
62    /// Sets step limit.
63    pub fn with_step_limit(mut self, limit: u64) -> Self {
64        self.step_limit = Some(limit);
65        self
66    }
67}
68
69// Convenience constructors with specific acceptors
70
71impl<S, M, MS> LocalSearchPhaseFactory<S, M, MS, HillClimbingAcceptor, AcceptedCountForager<S>>
72where
73    S: PlanningSolution,
74    M: Move<S>,
75    MS: MoveSelector<S, M>,
76{
77    /// Creates a hill climbing local search.
78    pub fn hill_climbing(move_selector: MS) -> Self {
79        Self::new(
80            move_selector,
81            HillClimbingAcceptor::new(),
82            AcceptedCountForager::new(1),
83        )
84    }
85}
86
87impl<S, M, MS> LocalSearchPhaseFactory<S, M, MS, TabuSearchAcceptor<S>, AcceptedCountForager<S>>
88where
89    S: PlanningSolution,
90    M: Move<S>,
91    MS: MoveSelector<S, M>,
92{
93    /// Creates a tabu search local search.
94    pub fn tabu_search(move_selector: MS, tabu_size: usize) -> Self {
95        Self::new(
96            move_selector,
97            TabuSearchAcceptor::new(tabu_size),
98            AcceptedCountForager::new(1),
99        )
100    }
101}
102
103impl<S, M, MS>
104    LocalSearchPhaseFactory<S, M, MS, SimulatedAnnealingAcceptor, AcceptedCountForager<S>>
105where
106    S: PlanningSolution,
107    M: Move<S>,
108    MS: MoveSelector<S, M>,
109{
110    /// Creates a simulated annealing local search.
111    pub fn simulated_annealing(move_selector: MS, starting_temp: f64, decay_rate: f64) -> Self {
112        Self::new(
113            move_selector,
114            SimulatedAnnealingAcceptor::new(starting_temp, decay_rate),
115            AcceptedCountForager::new(1),
116        )
117    }
118}
119
120impl<S, M, MS> LocalSearchPhaseFactory<S, M, MS, LateAcceptanceAcceptor<S>, AcceptedCountForager<S>>
121where
122    S: PlanningSolution,
123    M: Move<S>,
124    MS: MoveSelector<S, M>,
125{
126    /// Creates a late acceptance local search.
127    pub fn late_acceptance(move_selector: MS, size: usize) -> Self {
128        Self::new(
129            move_selector,
130            LateAcceptanceAcceptor::new(size),
131            AcceptedCountForager::new(1),
132        )
133    }
134}
135
136impl<S, D, M, MS, A, Fo> PhaseFactory<S, D> for LocalSearchPhaseFactory<S, M, MS, A, Fo>
137where
138    S: PlanningSolution,
139    D: ScoreDirector<S>,
140    M: Move<S> + Send + Sync + 'static,
141    MS: MoveSelector<S, M> + Clone + Send + Sync + 'static,
142    A: Acceptor<S> + Clone + Send + Sync + 'static,
143    Fo: LocalSearchForager<S, M> + Clone + Send + Sync + 'static,
144{
145    type Phase = LocalSearchPhase<S, M, MS, A, Fo>;
146
147    fn create(&self) -> Self::Phase {
148        LocalSearchPhase::new(
149            self.move_selector.clone(),
150            self.acceptor.clone(),
151            self.forager.clone(),
152            self.step_limit,
153        )
154    }
155}