solverforge_solver/builder/
forager.rs1use solverforge_config::ForagerConfig;
4use solverforge_core::domain::PlanningSolution;
5use solverforge_core::score::Score;
6use std::fmt::Debug;
7
8use crate::heuristic::r#move::Move;
9use crate::heuristic::selector::move_selector::CandidateId;
10use crate::phase::localsearch::{
11 AcceptedCountForager, BestScoreForager, FirstAcceptedForager, FirstBestScoreImprovingForager,
12 FirstLastStepScoreImprovingForager, LocalSearchForager,
13};
14
15#[allow(clippy::large_enum_variant)]
21pub enum AnyForager<S: PlanningSolution> {
22 AcceptedCount(AcceptedCountForager<S>),
24 FirstAccepted(FirstAcceptedForager<S>),
26 BestScore(BestScoreForager<S>),
28 BestScoreImproving(FirstBestScoreImprovingForager<S>),
30 LastStepScoreImproving(FirstLastStepScoreImprovingForager<S>),
32}
33
34impl<S: PlanningSolution> Debug for AnyForager<S> {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 match self {
37 Self::AcceptedCount(a) => write!(f, "AnyForager::AcceptedCount({a:?})"),
38 Self::FirstAccepted(a) => write!(f, "AnyForager::FirstAccepted({a:?})"),
39 Self::BestScore(a) => write!(f, "AnyForager::BestScore({a:?})"),
40 Self::BestScoreImproving(a) => write!(f, "AnyForager::BestScoreImproving({a:?})"),
41 Self::LastStepScoreImproving(a) => {
42 write!(f, "AnyForager::LastStepScoreImproving({a:?})")
43 }
44 }
45 }
46}
47
48impl<S: PlanningSolution, M: Move<S>> LocalSearchForager<S, M> for AnyForager<S>
49where
50 S::Score: Score,
51{
52 fn step_started(&mut self, best_score: S::Score, last_step_score: S::Score) {
53 match self {
54 Self::AcceptedCount(f) => {
55 LocalSearchForager::<S, M>::step_started(f, best_score, last_step_score)
56 }
57 Self::FirstAccepted(f) => {
58 LocalSearchForager::<S, M>::step_started(f, best_score, last_step_score)
59 }
60 Self::BestScore(f) => {
61 LocalSearchForager::<S, M>::step_started(f, best_score, last_step_score)
62 }
63 Self::BestScoreImproving(f) => {
64 LocalSearchForager::<S, M>::step_started(f, best_score, last_step_score)
65 }
66 Self::LastStepScoreImproving(f) => {
67 LocalSearchForager::<S, M>::step_started(f, best_score, last_step_score)
68 }
69 }
70 }
71
72 fn add_move_index(&mut self, index: CandidateId, score: S::Score) {
73 match self {
74 Self::AcceptedCount(f) => LocalSearchForager::<S, M>::add_move_index(f, index, score),
75 Self::FirstAccepted(f) => LocalSearchForager::<S, M>::add_move_index(f, index, score),
76 Self::BestScore(f) => LocalSearchForager::<S, M>::add_move_index(f, index, score),
77 Self::BestScoreImproving(f) => {
78 LocalSearchForager::<S, M>::add_move_index(f, index, score)
79 }
80 Self::LastStepScoreImproving(f) => {
81 LocalSearchForager::<S, M>::add_move_index(f, index, score)
82 }
83 }
84 }
85
86 fn is_quit_early(&self) -> bool {
87 match self {
88 Self::AcceptedCount(f) => LocalSearchForager::<S, M>::is_quit_early(f),
89 Self::FirstAccepted(f) => LocalSearchForager::<S, M>::is_quit_early(f),
90 Self::BestScore(f) => LocalSearchForager::<S, M>::is_quit_early(f),
91 Self::BestScoreImproving(f) => LocalSearchForager::<S, M>::is_quit_early(f),
92 Self::LastStepScoreImproving(f) => LocalSearchForager::<S, M>::is_quit_early(f),
93 }
94 }
95
96 fn pick_move_index(&mut self) -> Option<(CandidateId, S::Score)> {
97 match self {
98 Self::AcceptedCount(f) => LocalSearchForager::<S, M>::pick_move_index(f),
99 Self::FirstAccepted(f) => LocalSearchForager::<S, M>::pick_move_index(f),
100 Self::BestScore(f) => LocalSearchForager::<S, M>::pick_move_index(f),
101 Self::BestScoreImproving(f) => LocalSearchForager::<S, M>::pick_move_index(f),
102 Self::LastStepScoreImproving(f) => LocalSearchForager::<S, M>::pick_move_index(f),
103 }
104 }
105}
106
107pub struct ForagerBuilder;
109
110impl ForagerBuilder {
111 pub fn build<S: PlanningSolution>(config: Option<&ForagerConfig>) -> AnyForager<S>
113 where
114 S::Score: Score,
115 {
116 let Some(cfg) = config else {
117 return AnyForager::AcceptedCount(AcceptedCountForager::new(1));
118 };
119
120 match cfg {
121 ForagerConfig::AcceptedCount(accepted) => {
122 let limit = accepted.limit.unwrap_or(1).max(1);
123 AnyForager::AcceptedCount(AcceptedCountForager::new(limit))
124 }
125 ForagerConfig::BestScore => AnyForager::BestScore(BestScoreForager::new()),
126 ForagerConfig::FirstAccepted => AnyForager::FirstAccepted(FirstAcceptedForager::new()),
127 ForagerConfig::FirstBestScoreImproving => {
128 AnyForager::BestScoreImproving(FirstBestScoreImprovingForager::new())
129 }
130 ForagerConfig::FirstLastStepScoreImproving => {
131 AnyForager::LastStepScoreImproving(FirstLastStepScoreImprovingForager::new())
132 }
133 }
134 }
135}