solverforge_solver/manager/phase_factory/construction.rs
1//! Construction phase factory.
2
3use std::marker::PhantomData;
4
5use solverforge_core::domain::PlanningSolution;
6
7use crate::heuristic::Move;
8use crate::phase::construction::{
9 BestFitForager, ConstructionForager, ConstructionHeuristicPhase, EntityPlacer, FirstFitForager,
10 ForagerType,
11};
12use crate::phase::Phase;
13
14use super::super::SolverPhaseFactory;
15
16/// Factory for creating construction heuristic phases.
17///
18/// Construction heuristic phases build an initial solution by assigning
19/// values to uninitialized planning variables. The factory provides
20/// fresh phase instances for each solve.
21///
22/// # Type Parameters
23///
24/// * `S` - The planning solution type
25/// * `M` - The move type (typically [`ChangeMove`](crate::heuristic::ChangeMove))
26/// * `F` - The closure type that creates entity placers
27///
28/// # Example
29///
30/// ```
31/// use solverforge_solver::manager::{ConstructionPhaseFactory, SolverPhaseFactory};
32/// use solverforge_solver::heuristic::r#move::ChangeMove;
33/// use solverforge_solver::heuristic::selector::{
34/// FromSolutionEntitySelector, StaticTypedValueSelector,
35/// };
36/// use solverforge_solver::phase::construction::QueuedEntityPlacer;
37/// use solverforge_core::domain::PlanningSolution;
38/// use solverforge_core::score::SimpleScore;
39///
40/// #[derive(Clone)]
41/// struct Sol { values: Vec<Option<i32>>, score: Option<SimpleScore> }
42/// impl PlanningSolution for Sol {
43/// type Score = SimpleScore;
44/// fn score(&self) -> Option<Self::Score> { self.score }
45/// fn set_score(&mut self, score: Option<Self::Score>) { self.score = score; }
46/// }
47///
48/// fn get_v(s: &Sol, idx: usize) -> Option<i32> { s.values.get(idx).copied().flatten() }
49/// fn set_v(s: &mut Sol, idx: usize, v: Option<i32>) { if let Some(x) = s.values.get_mut(idx) { *x = v; } }
50///
51/// type M = ChangeMove<Sol, i32>;
52///
53/// // Create a first-fit construction phase factory
54/// let factory = ConstructionPhaseFactory::<Sol, M, _>::first_fit(|| {
55/// let entity_sel = Box::new(FromSolutionEntitySelector::new(0));
56/// let value_sel = Box::new(StaticTypedValueSelector::new(vec![1, 2, 3]));
57/// Box::new(QueuedEntityPlacer::new(entity_sel, value_sel, get_v, set_v, 0, "value"))
58/// });
59///
60/// // Create phase when solving
61/// let phase = factory.create_phase();
62/// assert_eq!(phase.phase_type_name(), "ConstructionHeuristic");
63/// ```
64///
65/// # Forager Types
66///
67/// - [`ForagerType::FirstFit`](crate::phase::construction::ForagerType::FirstFit):
68/// Accepts the first valid assignment (fast)
69/// - [`ForagerType::BestFit`](crate::phase::construction::ForagerType::BestFit):
70/// Evaluates all options and picks the best (better quality)
71pub struct ConstructionPhaseFactory<S, M, F>
72where
73 S: PlanningSolution,
74 M: Move<S> + Clone + Send + Sync + 'static,
75 F: Fn() -> Box<dyn EntityPlacer<S, M>> + Send + Sync,
76{
77 forager_type: ForagerType,
78 placer_factory: F,
79 _marker: PhantomData<(S, M)>,
80}
81
82impl<S, M, F> ConstructionPhaseFactory<S, M, F>
83where
84 S: PlanningSolution,
85 M: Move<S> + Clone + Send + Sync + 'static,
86 F: Fn() -> Box<dyn EntityPlacer<S, M>> + Send + Sync,
87{
88 /// Creates a new construction phase factory with the specified forager type.
89 ///
90 /// # Arguments
91 ///
92 /// * `forager_type` - The type of forager to use (FirstFit or BestFit)
93 /// * `placer_factory` - A closure that creates entity placers
94 ///
95 /// # Example
96 ///
97 /// ```
98 /// use solverforge_solver::manager::ConstructionPhaseFactory;
99 /// use solverforge_solver::phase::construction::{ForagerType, QueuedEntityPlacer};
100 /// use solverforge_solver::heuristic::r#move::ChangeMove;
101 /// use solverforge_solver::heuristic::selector::{FromSolutionEntitySelector, StaticTypedValueSelector};
102 /// use solverforge_core::domain::PlanningSolution;
103 /// use solverforge_core::score::SimpleScore;
104 ///
105 /// # #[derive(Clone)] struct S { values: Vec<Option<i32>>, score: Option<SimpleScore> }
106 /// # impl PlanningSolution for S {
107 /// # type Score = SimpleScore;
108 /// # fn score(&self) -> Option<Self::Score> { self.score }
109 /// # fn set_score(&mut self, score: Option<Self::Score>) { self.score = score; }
110 /// # }
111 /// # fn get_v(s: &S, idx: usize) -> Option<i32> { s.values.get(idx).copied().flatten() }
112 /// # fn set_v(s: &mut S, idx: usize, v: Option<i32>) { if let Some(x) = s.values.get_mut(idx) { *x = v; } }
113 /// type M = ChangeMove<S, i32>;
114 ///
115 /// let factory = ConstructionPhaseFactory::<S, M, _>::new(ForagerType::BestFit, || {
116 /// let es = Box::new(FromSolutionEntitySelector::new(0));
117 /// let vs = Box::new(StaticTypedValueSelector::new(vec![1, 2]));
118 /// Box::new(QueuedEntityPlacer::new(es, vs, get_v, set_v, 0, "v"))
119 /// });
120 /// ```
121 pub fn new(forager_type: ForagerType, placer_factory: F) -> Self {
122 Self {
123 forager_type,
124 placer_factory,
125 _marker: PhantomData,
126 }
127 }
128
129 /// Creates a factory with FirstFit forager.
130 ///
131 /// FirstFit accepts the first valid assignment for each entity,
132 /// making it fast but potentially producing lower quality initial solutions.
133 ///
134 /// # Example
135 ///
136 /// ```
137 /// use solverforge_solver::manager::ConstructionPhaseFactory;
138 /// use solverforge_solver::phase::construction::QueuedEntityPlacer;
139 /// use solverforge_solver::heuristic::r#move::ChangeMove;
140 /// use solverforge_solver::heuristic::selector::{FromSolutionEntitySelector, StaticTypedValueSelector};
141 /// use solverforge_core::domain::PlanningSolution;
142 /// use solverforge_core::score::SimpleScore;
143 ///
144 /// # #[derive(Clone)] struct S { values: Vec<Option<i32>>, score: Option<SimpleScore> }
145 /// # impl PlanningSolution for S {
146 /// # type Score = SimpleScore;
147 /// # fn score(&self) -> Option<Self::Score> { self.score }
148 /// # fn set_score(&mut self, score: Option<Self::Score>) { self.score = score; }
149 /// # }
150 /// # fn get_v(s: &S, idx: usize) -> Option<i32> { s.values.get(idx).copied().flatten() }
151 /// # fn set_v(s: &mut S, idx: usize, v: Option<i32>) { if let Some(x) = s.values.get_mut(idx) { *x = v; } }
152 /// type M = ChangeMove<S, i32>;
153 ///
154 /// let factory = ConstructionPhaseFactory::<S, M, _>::first_fit(|| {
155 /// let es = Box::new(FromSolutionEntitySelector::new(0));
156 /// let vs = Box::new(StaticTypedValueSelector::new(vec![1, 2, 3]));
157 /// Box::new(QueuedEntityPlacer::new(es, vs, get_v, set_v, 0, "v"))
158 /// });
159 /// ```
160 pub fn first_fit(placer_factory: F) -> Self {
161 Self::new(ForagerType::FirstFit, placer_factory)
162 }
163
164 /// Creates a factory with BestFit forager.
165 ///
166 /// BestFit evaluates all possible values for each entity and selects
167 /// the one that produces the best score. Slower but produces better
168 /// initial solutions.
169 ///
170 /// # Example
171 ///
172 /// ```
173 /// use solverforge_solver::manager::ConstructionPhaseFactory;
174 /// use solverforge_solver::phase::construction::QueuedEntityPlacer;
175 /// use solverforge_solver::heuristic::r#move::ChangeMove;
176 /// use solverforge_solver::heuristic::selector::{FromSolutionEntitySelector, StaticTypedValueSelector};
177 /// use solverforge_core::domain::PlanningSolution;
178 /// use solverforge_core::score::SimpleScore;
179 ///
180 /// # #[derive(Clone)] struct S { values: Vec<Option<i32>>, score: Option<SimpleScore> }
181 /// # impl PlanningSolution for S {
182 /// # type Score = SimpleScore;
183 /// # fn score(&self) -> Option<Self::Score> { self.score }
184 /// # fn set_score(&mut self, score: Option<Self::Score>) { self.score = score; }
185 /// # }
186 /// # fn get_v(s: &S, idx: usize) -> Option<i32> { s.values.get(idx).copied().flatten() }
187 /// # fn set_v(s: &mut S, idx: usize, v: Option<i32>) { if let Some(x) = s.values.get_mut(idx) { *x = v; } }
188 /// type M = ChangeMove<S, i32>;
189 ///
190 /// let factory = ConstructionPhaseFactory::<S, M, _>::best_fit(|| {
191 /// let es = Box::new(FromSolutionEntitySelector::new(0));
192 /// let vs = Box::new(StaticTypedValueSelector::new(vec![1, 2, 3]));
193 /// Box::new(QueuedEntityPlacer::new(es, vs, get_v, set_v, 0, "v"))
194 /// });
195 /// ```
196 pub fn best_fit(placer_factory: F) -> Self {
197 Self::new(ForagerType::BestFit, placer_factory)
198 }
199}
200
201impl<S, M, F> SolverPhaseFactory<S> for ConstructionPhaseFactory<S, M, F>
202where
203 S: PlanningSolution + 'static,
204 M: Move<S> + Clone + Send + Sync + 'static,
205 F: Fn() -> Box<dyn EntityPlacer<S, M>> + Send + Sync,
206{
207 fn create_phase(&self) -> Box<dyn Phase<S>> {
208 let placer = (self.placer_factory)();
209
210 let forager: Box<dyn ConstructionForager<S, M>> = match self.forager_type {
211 ForagerType::FirstFit => Box::new(FirstFitForager::new()),
212 ForagerType::BestFit => Box::new(BestFitForager::new()),
213 };
214
215 Box::new(ConstructionHeuristicPhase::new(placer, forager))
216 }
217}