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::Director;
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 {
36 Self {
37 score_calculator,
38 phases: (),
39 termination: NoTermination,
40 _marker: PhantomData,
41 }
42 }
43}
44
45impl<S, D, C, P, T> SolverFactoryBuilder<S, D, C, P, T>
46where
47 S: PlanningSolution,
48{
49 pub fn with_phase<P2>(self, phase: P2) -> SolverFactoryBuilder<S, D, C, (P, P2), T> {
50 SolverFactoryBuilder {
51 score_calculator: self.score_calculator,
52 phases: (self.phases, phase),
53 termination: self.termination,
54 _marker: PhantomData,
55 }
56 }
57
58 pub fn with_phase_factory<F>(
62 self,
63 factory: F,
64 ) -> SolverFactoryBuilder<S, D, C, (P, F::Phase), T>
65 where
66 D: Director<S>,
67 F: PhaseFactory<S, D>,
68 {
69 let phase = factory.create();
70 SolverFactoryBuilder {
71 score_calculator: self.score_calculator,
72 phases: (self.phases, phase),
73 termination: self.termination,
74 _marker: PhantomData,
75 }
76 }
77
78 pub fn with_config(
79 self,
80 config: SolverConfig,
81 ) -> SolverFactoryBuilder<S, D, C, P, TimeTermination> {
82 let term = config.termination.unwrap_or_default();
83 let duration = term.time_limit().unwrap_or(Duration::from_secs(30));
84 SolverFactoryBuilder {
85 score_calculator: self.score_calculator,
86 phases: self.phases,
87 termination: TimeTermination::new(duration),
88 _marker: PhantomData,
89 }
90 }
91
92 pub fn with_time_limit(
93 self,
94 duration: Duration,
95 ) -> SolverFactoryBuilder<S, D, C, P, TimeTermination> {
96 SolverFactoryBuilder {
97 score_calculator: self.score_calculator,
98 phases: self.phases,
99 termination: TimeTermination::new(duration),
100 _marker: PhantomData,
101 }
102 }
103
104 pub fn with_step_limit(
105 self,
106 steps: u64,
107 ) -> SolverFactoryBuilder<S, D, C, P, StepCountTermination> {
108 SolverFactoryBuilder {
109 score_calculator: self.score_calculator,
110 phases: self.phases,
111 termination: StepCountTermination::new(steps),
112 _marker: PhantomData,
113 }
114 }
115
116 #[allow(clippy::type_complexity)]
118 pub fn with_time_limit_or(
119 self,
120 duration: Duration,
121 ) -> SolverFactoryBuilder<S, D, C, P, OrTermination<(T, TimeTermination), S, D>>
122 where
123 D: Director<S>,
124 {
125 SolverFactoryBuilder {
126 score_calculator: self.score_calculator,
127 phases: self.phases,
128 termination: OrTermination::new((self.termination, TimeTermination::new(duration))),
129 _marker: PhantomData,
130 }
131 }
132}
133
134impl<S, D, C, P, T> SolverFactoryBuilder<S, D, C, P, T>
135where
136 S: PlanningSolution,
137 D: Director<S>,
138 C: Fn(&S) -> S::Score + Send + Sync,
139 P: Phase<S, D>,
140 T: Termination<S, D>,
141{
142 pub fn build(self) -> Result<SolverFactory<S, D, C, P, T>, SolverBuildError> {
147 Ok(SolverFactory::new(
148 self.score_calculator,
149 self.phases,
150 self.termination,
151 ))
152 }
153}
154
155#[derive(Debug, Clone)]
157pub enum SolverBuildError {
158 InvalidConfig(String),
160}
161
162impl std::fmt::Display for SolverBuildError {
163 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164 match self {
165 SolverBuildError::InvalidConfig(msg) => {
166 write!(f, "Invalid solver configuration: {}", msg)
167 }
168 }
169 }
170}
171
172impl std::error::Error for SolverBuildError {}