solverforge_solver/
builder.rs1use solverforge_config::AcceptorConfig;
7use solverforge_core::domain::PlanningSolution;
8
9use crate::phase::localsearch::{
10 Acceptor, GreatDelugeAcceptor, HillClimbingAcceptor, LateAcceptanceAcceptor,
11 SimulatedAnnealingAcceptor, TabuSearchAcceptor,
12};
13
14pub struct AcceptorBuilder;
16
17impl AcceptorBuilder {
18 pub fn build<S: PlanningSolution>(config: &AcceptorConfig) -> Box<dyn Acceptor<S>> {
20 match config {
21 AcceptorConfig::HillClimbing => Box::new(HillClimbingAcceptor::new()),
22
23 AcceptorConfig::TabuSearch(tabu_config) => {
24 let tabu_size = tabu_config
26 .entity_tabu_size
27 .or(tabu_config.move_tabu_size)
28 .unwrap_or(7);
29 Box::new(TabuSearchAcceptor::<S>::new(tabu_size))
30 }
31
32 AcceptorConfig::SimulatedAnnealing(sa_config) => {
33 let starting_temp = sa_config
35 .starting_temperature
36 .as_ref()
37 .and_then(|s| s.parse::<f64>().ok())
38 .unwrap_or(0.0);
39 Box::new(SimulatedAnnealingAcceptor::new(starting_temp, 0.999985))
43 }
44
45 AcceptorConfig::LateAcceptance(la_config) => {
46 let size = la_config.late_acceptance_size.unwrap_or(400);
47 Box::new(LateAcceptanceAcceptor::<S>::new(size))
48 }
49
50 AcceptorConfig::GreatDeluge(gd_config) => {
51 let rain_speed = gd_config.water_level_increase_ratio.unwrap_or(0.001);
52 Box::new(GreatDelugeAcceptor::<S>::new(rain_speed))
53 }
54 }
55 }
56
57 pub fn hill_climbing<S: PlanningSolution>() -> HillClimbingAcceptor {
59 HillClimbingAcceptor::new()
60 }
61
62 pub fn tabu_search<S: PlanningSolution>(tabu_size: usize) -> TabuSearchAcceptor<S> {
64 TabuSearchAcceptor::<S>::new(tabu_size)
65 }
66
67 pub fn simulated_annealing(starting_temp: f64, decay_rate: f64) -> SimulatedAnnealingAcceptor {
69 SimulatedAnnealingAcceptor::new(starting_temp, decay_rate)
70 }
71
72 pub fn late_acceptance<S: PlanningSolution>(size: usize) -> LateAcceptanceAcceptor<S> {
74 LateAcceptanceAcceptor::<S>::new(size)
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81 use solverforge_config::{
82 AcceptorConfig, LateAcceptanceConfig, SimulatedAnnealingConfig, TabuSearchConfig,
83 };
84 use solverforge_core::score::SimpleScore;
85
86 #[derive(Clone, Debug)]
87 struct TestSolution {
88 score: Option<SimpleScore>,
89 }
90
91 impl PlanningSolution for TestSolution {
92 type Score = SimpleScore;
93 fn score(&self) -> Option<Self::Score> {
94 self.score
95 }
96 fn set_score(&mut self, score: Option<Self::Score>) {
97 self.score = score;
98 }
99 }
100
101 #[test]
102 fn test_acceptor_builder_hill_climbing() {
103 let config = AcceptorConfig::HillClimbing;
104 let _acceptor: Box<dyn Acceptor<TestSolution>> = AcceptorBuilder::build(&config);
105 }
106
107 #[test]
108 fn test_acceptor_builder_tabu_search() {
109 let config = AcceptorConfig::TabuSearch(TabuSearchConfig {
110 entity_tabu_size: Some(10),
111 ..Default::default()
112 });
113 let _acceptor: Box<dyn Acceptor<TestSolution>> = AcceptorBuilder::build(&config);
114 }
115
116 #[test]
117 fn test_acceptor_builder_simulated_annealing() {
118 let config = AcceptorConfig::SimulatedAnnealing(SimulatedAnnealingConfig {
119 starting_temperature: Some("1.5".to_string()),
120 });
121 let _acceptor: Box<dyn Acceptor<TestSolution>> = AcceptorBuilder::build(&config);
122 }
123
124 #[test]
125 fn test_acceptor_builder_late_acceptance() {
126 let config = AcceptorConfig::LateAcceptance(LateAcceptanceConfig {
127 late_acceptance_size: Some(500),
128 });
129 let _acceptor: Box<dyn Acceptor<TestSolution>> = AcceptorBuilder::build(&config);
130 }
131}