solverforge_solver/manager/
builder.rs1use std::marker::PhantomData;
4use std::time::Duration;
5
6use solverforge_config::SolverConfig;
7use solverforge_core::domain::PlanningSolution;
8use solverforge_scoring::ScoreDirector;
9
10use crate::phase::Phase;
11use crate::solver::NoTermination;
12use crate::termination::{OrTermination, StepCountTermination, Termination, TimeTermination};
13
14use super::{PhaseFactory, SolverFactory};
15
16pub struct SolverFactoryBuilder<S, D, C, P, T>
21where
22 S: PlanningSolution,
23{
24 score_calculator: C,
25 phases: P,
26 termination: T,
27 _marker: PhantomData<fn(S, D)>,
28}
29
30impl<S, D, C> SolverFactoryBuilder<S, D, C, (), NoTermination>
31where
32 S: PlanningSolution,
33 C: Fn(&S) -> S::Score + Send + Sync,
34{
35 pub fn new(score_calculator: C) -> Self {
37 Self {
38 score_calculator,
39 phases: (),
40 termination: NoTermination,
41 _marker: PhantomData,
42 }
43 }
44}
45
46impl<S, D, C, P, T> SolverFactoryBuilder<S, D, C, P, T>
47where
48 S: PlanningSolution,
49{
50 pub fn with_phase<P2>(self, phase: P2) -> SolverFactoryBuilder<S, D, C, (P, P2), T> {
52 SolverFactoryBuilder {
53 score_calculator: self.score_calculator,
54 phases: (self.phases, phase),
55 termination: self.termination,
56 _marker: PhantomData,
57 }
58 }
59
60 pub fn with_phase_factory<F>(
64 self,
65 factory: F,
66 ) -> SolverFactoryBuilder<S, D, C, (P, F::Phase), T>
67 where
68 D: ScoreDirector<S>,
69 F: PhaseFactory<S, D>,
70 {
71 let phase = factory.create();
72 SolverFactoryBuilder {
73 score_calculator: self.score_calculator,
74 phases: (self.phases, phase),
75 termination: self.termination,
76 _marker: PhantomData,
77 }
78 }
79
80 pub fn with_config(
84 self,
85 config: SolverConfig,
86 ) -> SolverFactoryBuilder<S, D, C, P, TimeTermination> {
87 let term = config.termination.unwrap_or_default();
88 let duration = term.time_limit().unwrap_or(Duration::from_secs(30));
89 SolverFactoryBuilder {
90 score_calculator: self.score_calculator,
91 phases: self.phases,
92 termination: TimeTermination::new(duration),
93 _marker: PhantomData,
94 }
95 }
96
97 pub fn with_time_limit(
99 self,
100 duration: Duration,
101 ) -> SolverFactoryBuilder<S, D, C, P, TimeTermination> {
102 SolverFactoryBuilder {
103 score_calculator: self.score_calculator,
104 phases: self.phases,
105 termination: TimeTermination::new(duration),
106 _marker: PhantomData,
107 }
108 }
109
110 pub fn with_step_limit(
112 self,
113 steps: u64,
114 ) -> SolverFactoryBuilder<S, D, C, P, StepCountTermination> {
115 SolverFactoryBuilder {
116 score_calculator: self.score_calculator,
117 phases: self.phases,
118 termination: StepCountTermination::new(steps),
119 _marker: PhantomData,
120 }
121 }
122
123 #[allow(clippy::type_complexity)]
125 pub fn with_time_limit_or(
126 self,
127 duration: Duration,
128 ) -> SolverFactoryBuilder<S, D, C, P, OrTermination<(T, TimeTermination), S, D>>
129 where
130 D: ScoreDirector<S>,
131 {
132 SolverFactoryBuilder {
133 score_calculator: self.score_calculator,
134 phases: self.phases,
135 termination: OrTermination::new((self.termination, TimeTermination::new(duration))),
136 _marker: PhantomData,
137 }
138 }
139}
140
141impl<S, D, C, P, T> SolverFactoryBuilder<S, D, C, P, T>
142where
143 S: PlanningSolution,
144 D: ScoreDirector<S>,
145 C: Fn(&S) -> S::Score + Send + Sync,
146 P: Phase<S, D>,
147 T: Termination<S, D>,
148{
149 pub fn build(self) -> Result<SolverFactory<S, D, C, P, T>, SolverBuildError> {
154 Ok(SolverFactory::new(
155 self.score_calculator,
156 self.phases,
157 self.termination,
158 ))
159 }
160}
161
162#[derive(Debug, Clone)]
164pub enum SolverBuildError {
165 InvalidConfig(String),
167}
168
169impl std::fmt::Display for SolverBuildError {
170 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171 match self {
172 SolverBuildError::InvalidConfig(msg) => {
173 write!(f, "Invalid solver configuration: {}", msg)
174 }
175 }
176 }
177}
178
179impl std::error::Error for SolverBuildError {}