solverforge_solver/manager/
mod.rs

1//! High-level solver management with ergonomic API.
2//!
3//! The `SolverManager` provides a simplified interface for configuring and
4//! running solvers. It stores configuration and can create solvers on demand.
5//!
6//! # Overview
7//!
8//! The manager module provides:
9//! - [`SolverManager`]: High-level solver configuration and creation
10//! - [`SolverPhaseFactory`]: Trait for creating fresh phase instances per solve
11//! - [`CloneablePhaseFactory`]: Factory that clones a prototype phase
12//! - [`ClosurePhaseFactory`]: Factory using a closure
13//!
14//! # Example
15//!
16//! ```
17//! use solverforge_solver::manager::{SolverManager, LocalSearchType};
18//! use solverforge_core::domain::PlanningSolution;
19//! use solverforge_core::score::SimpleScore;
20//! use std::time::Duration;
21//!
22//! #[derive(Clone)]
23//! struct Schedule { score: Option<SimpleScore> }
24//!
25//! impl PlanningSolution for Schedule {
26//!     type Score = SimpleScore;
27//!     fn score(&self) -> Option<Self::Score> { self.score }
28//!     fn set_score(&mut self, score: Option<Self::Score>) { self.score = score; }
29//! }
30//!
31//! // Create a manager with score calculator and termination
32//! let manager = SolverManager::<Schedule>::builder(|_| SimpleScore::of(0))
33//!     .with_construction_heuristic()
34//!     .with_local_search(LocalSearchType::HillClimbing)
35//!     .with_time_limit(Duration::from_secs(30))
36//!     .build()
37//!     .expect("Failed to build manager");
38//!
39//! // Create a solver from the manager
40//! let solver = manager.create_solver();
41//! ```
42
43mod builder;
44mod config;
45mod phase_factory;
46mod solver_manager;
47
48#[cfg(test)]
49mod builder_tests;
50#[cfg(test)]
51mod mod_tests;
52#[cfg(test)]
53mod mod_tests_integration;
54#[cfg(test)]
55mod phase_factory_tests;
56#[cfg(test)]
57mod phase_factory_tests_localsearch;
58
59pub use builder::SolverManagerBuilder;
60pub use config::{ConstructionType, LocalSearchType, PhaseConfig};
61pub use phase_factory::{ConstructionPhaseFactory, LocalSearchPhaseFactory};
62pub use solver_manager::SolverManager;
63
64use solverforge_core::domain::PlanningSolution;
65
66use crate::phase::Phase;
67
68/// Factory trait for creating phases.
69///
70/// Phase factories allow creating fresh phase instances for each solve,
71/// ensuring clean state between solves. This is essential because phases
72/// often maintain internal state (like step counters or tabu lists) that
73/// must be reset for each new solve.
74///
75/// # Implementing SolverPhaseFactory
76///
77/// There are two common ways to implement this trait:
78///
79/// 1. Use [`CloneablePhaseFactory`] for phases that implement `Clone`
80/// 2. Use [`ClosurePhaseFactory`] with a closure that creates phases
81///
82/// # Example
83///
84/// ```no_run
85/// use solverforge_solver::manager::SolverPhaseFactory;
86/// use solverforge_solver::phase::Phase;
87/// use solverforge_core::domain::PlanningSolution;
88/// use solverforge_core::score::SimpleScore;
89///
90/// # #[derive(Clone)]
91/// # struct MySolution { score: Option<SimpleScore> }
92/// # impl PlanningSolution for MySolution {
93/// #     type Score = SimpleScore;
94/// #     fn score(&self) -> Option<Self::Score> { self.score }
95/// #     fn set_score(&mut self, score: Option<Self::Score>) { self.score = score; }
96/// # }
97/// struct MyPhaseFactory;
98///
99/// impl SolverPhaseFactory<MySolution> for MyPhaseFactory {
100///     fn create_phase(&self) -> Box<dyn Phase<MySolution>> {
101///         // Create and return a new phase instance
102///         todo!("Create phase here")
103///     }
104/// }
105/// ```
106pub trait SolverPhaseFactory<S: PlanningSolution>: Send + Sync {
107    /// Creates a new phase instance.
108    ///
109    /// This method is called once per solve to create a fresh phase
110    /// with clean state.
111    fn create_phase(&self) -> Box<dyn Phase<S>>;
112}
113
114/// A simple phase factory that clones a prototype phase.
115///
116/// This factory stores a prototype phase and clones it for each solve.
117/// Use this when your phase type implements `Clone`.
118///
119/// # Example
120///
121/// ```
122/// use solverforge_solver::manager::{CloneablePhaseFactory, SolverPhaseFactory};
123/// use solverforge_solver::phase::Phase;
124/// use solverforge_solver::scope::SolverScope;
125/// use solverforge_core::domain::PlanningSolution;
126/// use solverforge_core::score::SimpleScore;
127///
128/// #[derive(Clone)]
129/// struct MySolution { score: Option<SimpleScore> }
130///
131/// impl PlanningSolution for MySolution {
132///     type Score = SimpleScore;
133///     fn score(&self) -> Option<Self::Score> { self.score }
134///     fn set_score(&mut self, score: Option<Self::Score>) { self.score = score; }
135/// }
136///
137/// // A simple cloneable phase
138/// #[derive(Clone, Debug)]
139/// struct SimplePhase;
140///
141/// impl Phase<MySolution> for SimplePhase {
142///     fn solve(&mut self, _scope: &mut SolverScope<MySolution>) {}
143///     fn phase_type_name(&self) -> &'static str { "SimplePhase" }
144/// }
145///
146/// // Create factory that will clone this phase for each solve
147/// let factory = CloneablePhaseFactory::new(SimplePhase);
148/// let phase = factory.create_phase();
149/// assert_eq!(phase.phase_type_name(), "SimplePhase");
150/// ```
151pub struct CloneablePhaseFactory<P> {
152    prototype: P,
153}
154
155impl<P: Clone> CloneablePhaseFactory<P> {
156    /// Creates a new factory from a prototype phase.
157    ///
158    /// The prototype will be cloned each time [`SolverPhaseFactory::create_phase()`]
159    /// is called.
160    ///
161    /// # Example
162    ///
163    /// ```
164    /// use solverforge_solver::manager::CloneablePhaseFactory;
165    /// use solverforge_solver::phase::Phase;
166    /// use solverforge_solver::scope::SolverScope;
167    /// use solverforge_core::domain::PlanningSolution;
168    /// use solverforge_core::score::SimpleScore;
169    ///
170    /// # #[derive(Clone)]
171    /// # struct S { score: Option<SimpleScore> }
172    /// # impl PlanningSolution for S {
173    /// #     type Score = SimpleScore;
174    /// #     fn score(&self) -> Option<Self::Score> { self.score }
175    /// #     fn set_score(&mut self, score: Option<Self::Score>) { self.score = score; }
176    /// # }
177    /// #[derive(Clone, Debug)]
178    /// struct MyPhase;
179    /// impl Phase<S> for MyPhase {
180    ///     fn solve(&mut self, _: &mut SolverScope<S>) {}
181    ///     fn phase_type_name(&self) -> &'static str { "MyPhase" }
182    /// }
183    ///
184    /// let factory = CloneablePhaseFactory::new(MyPhase);
185    /// ```
186    pub fn new(prototype: P) -> Self {
187        Self { prototype }
188    }
189}
190
191impl<S, P> SolverPhaseFactory<S> for CloneablePhaseFactory<P>
192where
193    S: PlanningSolution,
194    P: Phase<S> + Clone + Send + Sync + 'static,
195{
196    fn create_phase(&self) -> Box<dyn Phase<S>> {
197        Box::new(self.prototype.clone())
198    }
199}
200
201/// A phase factory using a closure.
202///
203/// This factory uses a closure to create phase instances. This is useful
204/// when the phase creation requires complex logic or external dependencies
205/// that cannot be easily cloned.
206///
207/// # Example
208///
209/// ```
210/// use solverforge_solver::manager::{ClosurePhaseFactory, SolverPhaseFactory};
211/// use solverforge_solver::phase::Phase;
212/// use solverforge_solver::scope::SolverScope;
213/// use solverforge_core::domain::PlanningSolution;
214/// use solverforge_core::score::SimpleScore;
215///
216/// #[derive(Clone)]
217/// struct MySolution { score: Option<SimpleScore> }
218///
219/// impl PlanningSolution for MySolution {
220///     type Score = SimpleScore;
221///     fn score(&self) -> Option<Self::Score> { self.score }
222///     fn set_score(&mut self, score: Option<Self::Score>) { self.score = score; }
223/// }
224///
225/// #[derive(Debug)]
226/// struct DynamicPhase { step_count: u32 }
227/// impl Phase<MySolution> for DynamicPhase {
228///     fn solve(&mut self, _: &mut SolverScope<MySolution>) {}
229///     fn phase_type_name(&self) -> &'static str { "DynamicPhase" }
230/// }
231///
232/// // Factory creates fresh instances with reset state
233/// let factory = ClosurePhaseFactory::<MySolution, _>::new(|| {
234///     Box::new(DynamicPhase { step_count: 0 })
235/// });
236///
237/// let phase = factory.create_phase();
238/// assert_eq!(phase.phase_type_name(), "DynamicPhase");
239/// ```
240pub struct ClosurePhaseFactory<S, F>
241where
242    S: PlanningSolution,
243    F: Fn() -> Box<dyn Phase<S>> + Send + Sync,
244{
245    factory: F,
246    _marker: std::marker::PhantomData<S>,
247}
248
249impl<S, F> ClosurePhaseFactory<S, F>
250where
251    S: PlanningSolution,
252    F: Fn() -> Box<dyn Phase<S>> + Send + Sync,
253{
254    /// Creates a new factory from a closure.
255    ///
256    /// The closure will be called each time a new phase is needed.
257    ///
258    /// # Example
259    ///
260    /// ```
261    /// use solverforge_solver::manager::ClosurePhaseFactory;
262    /// use solverforge_solver::phase::Phase;
263    /// use solverforge_solver::scope::SolverScope;
264    /// use solverforge_core::domain::PlanningSolution;
265    /// use solverforge_core::score::SimpleScore;
266    ///
267    /// # #[derive(Clone)]
268    /// # struct S { score: Option<SimpleScore> }
269    /// # impl PlanningSolution for S {
270    /// #     type Score = SimpleScore;
271    /// #     fn score(&self) -> Option<Self::Score> { self.score }
272    /// #     fn set_score(&mut self, score: Option<Self::Score>) { self.score = score; }
273    /// # }
274    /// #[derive(Debug)]
275    /// struct P;
276    /// impl Phase<S> for P {
277    ///     fn solve(&mut self, _: &mut SolverScope<S>) {}
278    ///     fn phase_type_name(&self) -> &'static str { "P" }
279    /// }
280    ///
281    /// let factory = ClosurePhaseFactory::<S, _>::new(|| Box::new(P));
282    /// ```
283    pub fn new(factory: F) -> Self {
284        Self {
285            factory,
286            _marker: std::marker::PhantomData,
287        }
288    }
289}
290
291impl<S, F> SolverPhaseFactory<S> for ClosurePhaseFactory<S, F>
292where
293    S: PlanningSolution,
294    F: Fn() -> Box<dyn Phase<S>> + Send + Sync,
295{
296    fn create_phase(&self) -> Box<dyn Phase<S>> {
297        (self.factory)()
298    }
299}