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