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)] pub 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 accepted_count_limit(&self) -> Option<usize> {
97 match self {
98 Self::AcceptedCount(f) => LocalSearchForager::<S, M>::accepted_count_limit(f),
99 Self::FirstAccepted(f) => LocalSearchForager::<S, M>::accepted_count_limit(f),
100 Self::BestScore(f) => LocalSearchForager::<S, M>::accepted_count_limit(f),
101 Self::BestScoreImproving(f) => LocalSearchForager::<S, M>::accepted_count_limit(f),
102 Self::LastStepScoreImproving(f) => LocalSearchForager::<S, M>::accepted_count_limit(f),
103 }
104 }
105
106 fn pick_move_index(&mut self) -> Option<(CandidateId, S::Score)> {
107 match self {
108 Self::AcceptedCount(f) => LocalSearchForager::<S, M>::pick_move_index(f),
109 Self::FirstAccepted(f) => LocalSearchForager::<S, M>::pick_move_index(f),
110 Self::BestScore(f) => LocalSearchForager::<S, M>::pick_move_index(f),
111 Self::BestScoreImproving(f) => LocalSearchForager::<S, M>::pick_move_index(f),
112 Self::LastStepScoreImproving(f) => LocalSearchForager::<S, M>::pick_move_index(f),
113 }
114 }
115}
116
117pub struct ForagerBuilder;
119
120impl ForagerBuilder {
121 pub fn build<S: PlanningSolution>(config: Option<&ForagerConfig>) -> AnyForager<S>
123 where
124 S::Score: Score,
125 {
126 let Some(cfg) = config else {
127 return AnyForager::AcceptedCount(AcceptedCountForager::new(1));
128 };
129
130 match cfg {
131 ForagerConfig::AcceptedCount(accepted) => {
132 let limit = accepted.limit.unwrap_or(1).max(1);
133 AnyForager::AcceptedCount(AcceptedCountForager::new(limit))
134 }
135 ForagerConfig::BestScore => AnyForager::BestScore(BestScoreForager::new()),
136 ForagerConfig::FirstAccepted => AnyForager::FirstAccepted(FirstAcceptedForager::new()),
137 ForagerConfig::FirstBestScoreImproving => {
138 AnyForager::BestScoreImproving(FirstBestScoreImprovingForager::new())
139 }
140 ForagerConfig::FirstLastStepScoreImproving => {
141 AnyForager::LastStepScoreImproving(FirstLastStepScoreImprovingForager::new())
142 }
143 }
144 }
145}