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}