Skip to main content

solverforge_solver/builder/search/
custom.rs

1use std::fmt::{self, Debug};
2use std::marker::PhantomData;
3
4use solverforge_config::PartitionedSearchConfig;
5use solverforge_core::domain::PlanningSolution;
6use solverforge_scoring::Director;
7
8use crate::heuristic::r#move::Move;
9use crate::heuristic::MoveSelector;
10use crate::phase::localsearch::{Acceptor, LocalSearchForager, LocalSearchPhase};
11use crate::phase::partitioned::{ChildPhases, PartitionedSearchPhase, SolutionPartitioner};
12use crate::phase::Phase;
13use crate::scope::{ProgressCallback, SolverScope};
14
15use super::SearchContext;
16
17pub trait CustomSearchPhase<S>: Debug + Send
18where
19    S: PlanningSolution,
20{
21    fn solve<D, ProgressCb>(&mut self, solver_scope: &mut SolverScope<'_, S, D, ProgressCb>)
22    where
23        D: Director<S>,
24        ProgressCb: ProgressCallback<S>;
25
26    fn phase_type_name(&self) -> &'static str {
27        "CustomSearchPhase"
28    }
29}
30
31impl<S, M, MS, A, Fo> CustomSearchPhase<S> for LocalSearchPhase<S, M, MS, A, Fo>
32where
33    S: PlanningSolution,
34    M: Move<S>,
35    MS: MoveSelector<S, M> + Debug,
36    A: Acceptor<S> + Debug,
37    Fo: LocalSearchForager<S, M> + Debug,
38{
39    fn solve<D, ProgressCb>(&mut self, solver_scope: &mut SolverScope<'_, S, D, ProgressCb>)
40    where
41        D: Director<S>,
42        ProgressCb: ProgressCallback<S>,
43    {
44        Phase::solve(self, solver_scope);
45    }
46
47    fn phase_type_name(&self) -> &'static str {
48        "LocalSearchPhase"
49    }
50}
51
52impl<S, PD, Part, SDF, PF, CP> CustomSearchPhase<S>
53    for PartitionedSearchPhase<S, PD, Part, SDF, PF, CP>
54where
55    S: PlanningSolution + 'static,
56    PD: Director<S> + 'static,
57    Part: SolutionPartitioner<S>,
58    SDF: Fn(S) -> PD + Send + Sync,
59    PF: Fn() -> CP + Send + Sync,
60    CP: ChildPhases<S, PD> + Send,
61{
62    fn solve<D, ProgressCb>(&mut self, solver_scope: &mut SolverScope<'_, S, D, ProgressCb>)
63    where
64        D: Director<S>,
65        ProgressCb: ProgressCallback<S>,
66    {
67        Phase::solve(self, solver_scope);
68    }
69
70    fn phase_type_name(&self) -> &'static str {
71        "PartitionedSearch"
72    }
73}
74
75pub trait CustomPhaseRegistry<S, V, DM, IDM>
76where
77    S: PlanningSolution,
78{
79    type Phase: CustomSearchPhase<S>;
80
81    fn contains(&self, name: &str) -> bool;
82
83    fn build_named(
84        &self,
85        name: &str,
86        context: &SearchContext<S, V, DM, IDM>,
87    ) -> Option<Self::Phase>;
88
89    fn contains_partitioned(&self, name: &str) -> bool;
90
91    fn build_partitioned_named(
92        &self,
93        name: &str,
94        config: &PartitionedSearchConfig,
95        context: &SearchContext<S, V, DM, IDM>,
96    ) -> Option<Self::Phase>;
97}
98
99pub struct NoCustomPhases;
100
101impl<S, V, DM, IDM> CustomPhaseRegistry<S, V, DM, IDM> for NoCustomPhases
102where
103    S: PlanningSolution,
104{
105    type Phase = NoCustomPhase;
106
107    fn contains(&self, _name: &str) -> bool {
108        false
109    }
110
111    fn build_named(
112        &self,
113        _name: &str,
114        _context: &SearchContext<S, V, DM, IDM>,
115    ) -> Option<Self::Phase> {
116        None
117    }
118
119    fn contains_partitioned(&self, _name: &str) -> bool {
120        false
121    }
122
123    fn build_partitioned_named(
124        &self,
125        _name: &str,
126        _config: &PartitionedSearchConfig,
127        _context: &SearchContext<S, V, DM, IDM>,
128    ) -> Option<Self::Phase> {
129        None
130    }
131}
132
133#[derive(Clone, Copy)]
134pub enum NoCustomPhase {}
135
136impl Debug for NoCustomPhase {
137    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
138        match *self {}
139    }
140}
141
142impl<S> CustomSearchPhase<S> for NoCustomPhase
143where
144    S: PlanningSolution,
145{
146    fn solve<D, ProgressCb>(&mut self, _solver_scope: &mut SolverScope<'_, S, D, ProgressCb>)
147    where
148        D: Director<S>,
149        ProgressCb: ProgressCallback<S>,
150    {
151        match *self {}
152    }
153
154    fn phase_type_name(&self) -> &'static str {
155        match *self {}
156    }
157}
158
159impl<S, D, ProgressCb> Phase<S, D, ProgressCb> for NoCustomPhase
160where
161    S: PlanningSolution,
162    D: Director<S>,
163    ProgressCb: ProgressCallback<S>,
164{
165    fn solve(&mut self, _solver_scope: &mut SolverScope<'_, S, D, ProgressCb>) {
166        match *self {}
167    }
168
169    fn phase_type_name(&self) -> &'static str {
170        match *self {}
171    }
172}
173
174pub struct CustomPhaseNode<Previous, Builder, Phase> {
175    previous: Previous,
176    name: &'static str,
177    builder: Builder,
178    _marker: PhantomData<fn() -> Phase>,
179}
180
181pub struct PartitionedPhaseNode<Previous, Builder, Phase> {
182    previous: Previous,
183    name: &'static str,
184    builder: Builder,
185    _marker: PhantomData<fn() -> Phase>,
186}
187
188impl<Previous, Builder, Phase> PartitionedPhaseNode<Previous, Builder, Phase> {
189    pub fn new(previous: Previous, name: &'static str, builder: Builder) -> Self {
190        Self {
191            previous,
192            name,
193            builder,
194            _marker: PhantomData,
195        }
196    }
197}
198
199impl<Previous, Builder, Phase> CustomPhaseNode<Previous, Builder, Phase> {
200    pub fn new(previous: Previous, name: &'static str, builder: Builder) -> Self {
201        Self {
202            previous,
203            name,
204            builder,
205            _marker: PhantomData,
206        }
207    }
208}
209
210pub enum CustomPhaseUnion<PreviousPhase, CurrentPhase> {
211    Previous(PreviousPhase),
212    Current(CurrentPhase),
213}
214
215impl<PreviousPhase: Debug, CurrentPhase: Debug> Debug
216    for CustomPhaseUnion<PreviousPhase, CurrentPhase>
217{
218    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
219        match self {
220            Self::Previous(phase) => f.debug_tuple("CustomPhase::Previous").field(phase).finish(),
221            Self::Current(phase) => f.debug_tuple("CustomPhase::Current").field(phase).finish(),
222        }
223    }
224}
225
226impl<S, PreviousPhase, CurrentPhase> CustomSearchPhase<S>
227    for CustomPhaseUnion<PreviousPhase, CurrentPhase>
228where
229    S: PlanningSolution,
230    PreviousPhase: CustomSearchPhase<S>,
231    CurrentPhase: CustomSearchPhase<S>,
232{
233    fn solve<D, ProgressCb>(&mut self, solver_scope: &mut SolverScope<'_, S, D, ProgressCb>)
234    where
235        D: Director<S>,
236        ProgressCb: ProgressCallback<S>,
237    {
238        match self {
239            Self::Previous(phase) => phase.solve(solver_scope),
240            Self::Current(phase) => phase.solve(solver_scope),
241        }
242    }
243
244    fn phase_type_name(&self) -> &'static str {
245        "CustomPhase"
246    }
247}
248
249impl<S, D, ProgressCb, PreviousPhase, CurrentPhase> Phase<S, D, ProgressCb>
250    for CustomPhaseUnion<PreviousPhase, CurrentPhase>
251where
252    S: PlanningSolution,
253    D: Director<S>,
254    ProgressCb: ProgressCallback<S>,
255    PreviousPhase: CustomSearchPhase<S>,
256    CurrentPhase: CustomSearchPhase<S>,
257{
258    fn solve(&mut self, solver_scope: &mut SolverScope<'_, S, D, ProgressCb>) {
259        CustomSearchPhase::solve(self, solver_scope);
260    }
261
262    fn phase_type_name(&self) -> &'static str {
263        CustomSearchPhase::<S>::phase_type_name(self)
264    }
265}
266
267impl<S, V, DM, IDM, Previous, Builder, CurrentPhase> CustomPhaseRegistry<S, V, DM, IDM>
268    for CustomPhaseNode<Previous, Builder, CurrentPhase>
269where
270    S: PlanningSolution,
271    Previous: CustomPhaseRegistry<S, V, DM, IDM>,
272    Builder: Fn(&SearchContext<S, V, DM, IDM>) -> CurrentPhase,
273    CurrentPhase: CustomSearchPhase<S>,
274{
275    type Phase = CustomPhaseUnion<Previous::Phase, CurrentPhase>;
276
277    fn contains(&self, name: &str) -> bool {
278        self.name == name || self.previous.contains(name)
279    }
280
281    fn build_named(
282        &self,
283        name: &str,
284        context: &SearchContext<S, V, DM, IDM>,
285    ) -> Option<Self::Phase> {
286        if self.name == name {
287            return Some(CustomPhaseUnion::Current((self.builder)(context)));
288        }
289        self.previous
290            .build_named(name, context)
291            .map(CustomPhaseUnion::Previous)
292    }
293
294    fn contains_partitioned(&self, name: &str) -> bool {
295        self.previous.contains_partitioned(name)
296    }
297
298    fn build_partitioned_named(
299        &self,
300        name: &str,
301        config: &PartitionedSearchConfig,
302        context: &SearchContext<S, V, DM, IDM>,
303    ) -> Option<Self::Phase> {
304        self.previous
305            .build_partitioned_named(name, config, context)
306            .map(CustomPhaseUnion::Previous)
307    }
308}
309
310impl<S, V, DM, IDM, Previous, Builder, CurrentPhase> CustomPhaseRegistry<S, V, DM, IDM>
311    for PartitionedPhaseNode<Previous, Builder, CurrentPhase>
312where
313    S: PlanningSolution,
314    Previous: CustomPhaseRegistry<S, V, DM, IDM>,
315    Builder: Fn(&SearchContext<S, V, DM, IDM>, &PartitionedSearchConfig) -> CurrentPhase,
316    CurrentPhase: CustomSearchPhase<S>,
317{
318    type Phase = CustomPhaseUnion<Previous::Phase, CurrentPhase>;
319
320    fn contains(&self, name: &str) -> bool {
321        self.previous.contains(name)
322    }
323
324    fn build_named(
325        &self,
326        name: &str,
327        context: &SearchContext<S, V, DM, IDM>,
328    ) -> Option<Self::Phase> {
329        self.previous
330            .build_named(name, context)
331            .map(CustomPhaseUnion::Previous)
332    }
333
334    fn contains_partitioned(&self, name: &str) -> bool {
335        self.name == name || self.previous.contains_partitioned(name)
336    }
337
338    fn build_partitioned_named(
339        &self,
340        name: &str,
341        config: &PartitionedSearchConfig,
342        context: &SearchContext<S, V, DM, IDM>,
343    ) -> Option<Self::Phase> {
344        if self.name == name {
345            return Some(CustomPhaseUnion::Current((self.builder)(context, config)));
346        }
347        self.previous
348            .build_partitioned_named(name, config, context)
349            .map(CustomPhaseUnion::Previous)
350    }
351}