Skip to main content

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::Director;
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    pub fn new(move_selector: MS, acceptor: A, forager: Fo) -> Self {
52        Self {
53            move_selector,
54            acceptor,
55            forager,
56            step_limit: None,
57            _marker: PhantomData,
58        }
59    }
60
61    pub fn with_step_limit(mut self, limit: u64) -> Self {
62        self.step_limit = Some(limit);
63        self
64    }
65}
66
67// Convenience constructors with specific acceptors
68
69impl<S, M, MS> LocalSearchPhaseFactory<S, M, MS, HillClimbingAcceptor, AcceptedCountForager<S>>
70where
71    S: PlanningSolution,
72    M: Move<S>,
73    MS: MoveSelector<S, M>,
74{
75    pub fn hill_climbing(move_selector: MS) -> Self {
76        Self::new(
77            move_selector,
78            HillClimbingAcceptor::new(),
79            AcceptedCountForager::new(1),
80        )
81    }
82}
83
84impl<S, M, MS> LocalSearchPhaseFactory<S, M, MS, TabuSearchAcceptor<S>, AcceptedCountForager<S>>
85where
86    S: PlanningSolution,
87    M: Move<S>,
88    MS: MoveSelector<S, M>,
89{
90    pub fn tabu_search(move_selector: MS, tabu_size: usize) -> Self {
91        Self::new(
92            move_selector,
93            TabuSearchAcceptor::new(tabu_size),
94            AcceptedCountForager::new(1),
95        )
96    }
97}
98
99impl<S, M, MS>
100    LocalSearchPhaseFactory<S, M, MS, SimulatedAnnealingAcceptor, AcceptedCountForager<S>>
101where
102    S: PlanningSolution,
103    M: Move<S>,
104    MS: MoveSelector<S, M>,
105{
106    pub fn simulated_annealing(move_selector: MS, starting_temp: f64, decay_rate: f64) -> Self {
107        Self::new(
108            move_selector,
109            SimulatedAnnealingAcceptor::new(starting_temp, decay_rate),
110            AcceptedCountForager::new(1),
111        )
112    }
113}
114
115impl<S, M, MS> LocalSearchPhaseFactory<S, M, MS, LateAcceptanceAcceptor<S>, AcceptedCountForager<S>>
116where
117    S: PlanningSolution,
118    M: Move<S>,
119    MS: MoveSelector<S, M>,
120{
121    pub fn late_acceptance(move_selector: MS, size: usize) -> Self {
122        Self::new(
123            move_selector,
124            LateAcceptanceAcceptor::new(size),
125            AcceptedCountForager::new(1),
126        )
127    }
128}
129
130impl<S, D, M, MS, A, Fo> PhaseFactory<S, D> for LocalSearchPhaseFactory<S, M, MS, A, Fo>
131where
132    S: PlanningSolution,
133    D: Director<S>,
134    M: Move<S> + Send + Sync + 'static,
135    MS: MoveSelector<S, M> + Clone + Send + Sync + 'static,
136    A: Acceptor<S> + Clone + Send + Sync + 'static,
137    Fo: LocalSearchForager<S, M> + Clone + Send + Sync + 'static,
138{
139    type Phase = LocalSearchPhase<S, M, MS, A, Fo>;
140
141    fn create(&self) -> Self::Phase {
142        LocalSearchPhase::new(
143            self.move_selector.clone(),
144            self.acceptor.clone(),
145            self.forager.clone(),
146            self.step_limit,
147        )
148    }
149}