solverforge_solver/manager/solver_factory.rs
1/* SolverFactory with zero-erasure design.
2
3Low-level solver infrastructure for building and executing solve phases.
4For async job management, see [`SolverManager`](super::SolverManager).
5*/
6
7use std::marker::PhantomData;
8
9use solverforge_core::domain::PlanningSolution;
10use solverforge_scoring::Director;
11
12use crate::phase::Phase;
13use crate::scope::SolverScope;
14use crate::solver::NoTermination;
15use crate::termination::Termination;
16
17use super::builder::SolverFactoryBuilder;
18
19/// Zero-erasure solver factory.
20///
21/// Stores phases as a concrete tuple type `P`, score calculator as `C`,
22/// and termination as `T`. No dynamic dispatch anywhere.
23///
24/// # Type Parameters
25///
26/// * `S` - The solution type
27/// * `D` - The score director type
28/// * `C` - The score calculator type
29/// * `P` - The phases tuple type
30/// * `T` - The termination type
31pub struct SolverFactory<S, D, C, P, T> {
32 score_calculator: C,
33 phases: P,
34 termination: T,
35 _marker: PhantomData<fn(S, D, P, T)>,
36}
37
38impl<S, D, C, P, T> SolverFactory<S, D, C, P, T>
39where
40 S: PlanningSolution,
41 D: Director<S>,
42 C: Fn(&S) -> S::Score + Send + Sync,
43 P: Phase<S, D>,
44 T: Termination<S, D>,
45{
46 pub fn new(score_calculator: C, phases: P, termination: T) -> Self {
47 Self {
48 score_calculator,
49 phases,
50 termination,
51 _marker: PhantomData,
52 }
53 }
54
55 pub fn score_calculator(&self) -> &C {
56 &self.score_calculator
57 }
58
59 /// Calculates score for a solution.
60 pub fn calculate_score(&self, solution: &S) -> S::Score {
61 (self.score_calculator)(solution)
62 }
63
64 pub fn phases(&self) -> &P {
65 &self.phases
66 }
67
68 pub fn phases_mut(&mut self) -> &mut P {
69 &mut self.phases
70 }
71
72 pub fn termination(&self) -> &T {
73 &self.termination
74 }
75
76 /// Solves using the configured phases and termination.
77 pub fn solve(&mut self, solver_scope: &mut SolverScope<S, D>) {
78 solver_scope.start_solving();
79 self.phases.solve(solver_scope);
80 }
81
82 /// Creates a Solver from this factory's configuration.
83 ///
84 /// The returned Solver can be used with `solve_with_director()` for
85 /// macro-generated code or `solve()` for direct use.
86 pub fn create_solver(self) -> crate::solver::Solver<'static, P, Option<T>, S, ()> {
87 crate::solver::Solver::new(self.phases).with_termination(self.termination)
88 }
89}
90
91/// Creates a builder for SolverFactory.
92///
93/// Use `SolverFactoryBuilder::new()` directly for full type control.
94pub fn solver_factory_builder<S, D, C>(
95 score_calculator: C,
96) -> SolverFactoryBuilder<S, D, C, (), NoTermination>
97where
98 S: PlanningSolution,
99 C: Fn(&S) -> S::Score + Send + Sync,
100{
101 SolverFactoryBuilder::new(score_calculator)
102}
103
104impl<S: PlanningSolution> SolverFactory<S, (), (), (), ()> {
105 /// Creates a new builder for SolverFactory.
106 ///
107 /// This allows calling `SolverFactory::<MySolution>::builder(score_fn)`
108 /// to start building a solver factory.
109 ///
110 /// # Example
111 ///
112 /// ```
113 /// use solverforge_core::domain::PlanningSolution;
114 /// use solverforge_core::score::SoftScore;
115 /// use solverforge_solver::manager::solver_factory_builder;
116 ///
117 /// #[derive(Clone)]
118 /// struct MySolution {
119 /// score: Option<SoftScore>,
120 /// }
121 ///
122 /// impl PlanningSolution for MySolution {
123 /// type Score = SoftScore;
124 /// fn score(&self) -> Option<Self::Score> { self.score }
125 /// fn set_score(&mut self, score: Option<Self::Score>) { self.score = score; }
126 /// }
127 ///
128 /// let builder = solver_factory_builder::<MySolution, (), _>(|_s| SoftScore::of(0));
129 /// ```
130 pub fn builder<D, C>(score_calculator: C) -> SolverFactoryBuilder<S, D, C, (), NoTermination>
131 where
132 C: Fn(&S) -> S::Score + Send + Sync,
133 {
134 SolverFactoryBuilder::new(score_calculator)
135 }
136}