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)]
19pub enum AnyForager<S: PlanningSolution> {
20 AcceptedCount(AcceptedCountForager<S>),
22 FirstAccepted(FirstAcceptedForager<S>),
24 BestScore(BestScoreForager<S>),
26 BestScoreImproving(FirstBestScoreImprovingForager<S>),
28 LastStepScoreImproving(FirstLastStepScoreImprovingForager<S>),
30}
31
32impl<S: PlanningSolution> Debug for AnyForager<S> {
33 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34 match self {
35 Self::AcceptedCount(a) => write!(f, "AnyForager::AcceptedCount({a:?})"),
36 Self::FirstAccepted(a) => write!(f, "AnyForager::FirstAccepted({a:?})"),
37 Self::BestScore(a) => write!(f, "AnyForager::BestScore({a:?})"),
38 Self::BestScoreImproving(a) => write!(f, "AnyForager::BestScoreImproving({a:?})"),
39 Self::LastStepScoreImproving(a) => {
40 write!(f, "AnyForager::LastStepScoreImproving({a:?})")
41 }
42 }
43 }
44}
45
46impl<S: PlanningSolution, M: Move<S>> LocalSearchForager<S, M> for AnyForager<S>
47where
48 S::Score: Score,
49{
50 fn step_started(&mut self, best_score: S::Score, last_step_score: S::Score) {
51 match self {
52 Self::AcceptedCount(f) => {
53 LocalSearchForager::<S, M>::step_started(f, best_score, last_step_score)
54 }
55 Self::FirstAccepted(f) => {
56 LocalSearchForager::<S, M>::step_started(f, best_score, last_step_score)
57 }
58 Self::BestScore(f) => {
59 LocalSearchForager::<S, M>::step_started(f, best_score, last_step_score)
60 }
61 Self::BestScoreImproving(f) => {
62 LocalSearchForager::<S, M>::step_started(f, best_score, last_step_score)
63 }
64 Self::LastStepScoreImproving(f) => {
65 LocalSearchForager::<S, M>::step_started(f, best_score, last_step_score)
66 }
67 }
68 }
69
70 fn add_move_index(&mut self, index: usize, score: S::Score) {
71 match self {
72 Self::AcceptedCount(f) => LocalSearchForager::<S, M>::add_move_index(f, index, score),
73 Self::FirstAccepted(f) => LocalSearchForager::<S, M>::add_move_index(f, index, score),
74 Self::BestScore(f) => LocalSearchForager::<S, M>::add_move_index(f, index, score),
75 Self::BestScoreImproving(f) => {
76 LocalSearchForager::<S, M>::add_move_index(f, index, score)
77 }
78 Self::LastStepScoreImproving(f) => {
79 LocalSearchForager::<S, M>::add_move_index(f, index, score)
80 }
81 }
82 }
83
84 fn is_quit_early(&self) -> bool {
85 match self {
86 Self::AcceptedCount(f) => LocalSearchForager::<S, M>::is_quit_early(f),
87 Self::FirstAccepted(f) => LocalSearchForager::<S, M>::is_quit_early(f),
88 Self::BestScore(f) => LocalSearchForager::<S, M>::is_quit_early(f),
89 Self::BestScoreImproving(f) => LocalSearchForager::<S, M>::is_quit_early(f),
90 Self::LastStepScoreImproving(f) => LocalSearchForager::<S, M>::is_quit_early(f),
91 }
92 }
93
94 fn pick_move_index(&mut self) -> Option<(usize, S::Score)> {
95 match self {
96 Self::AcceptedCount(f) => LocalSearchForager::<S, M>::pick_move_index(f),
97 Self::FirstAccepted(f) => LocalSearchForager::<S, M>::pick_move_index(f),
98 Self::BestScore(f) => LocalSearchForager::<S, M>::pick_move_index(f),
99 Self::BestScoreImproving(f) => LocalSearchForager::<S, M>::pick_move_index(f),
100 Self::LastStepScoreImproving(f) => LocalSearchForager::<S, M>::pick_move_index(f),
101 }
102 }
103}
104
105pub struct ForagerBuilder;
107
108impl ForagerBuilder {
109 pub fn build<S: PlanningSolution>(config: Option<&ForagerConfig>) -> AnyForager<S>
116 where
117 S::Score: Score,
118 {
119 let Some(cfg) = config else {
120 return AnyForager::AcceptedCount(AcceptedCountForager::new(1));
121 };
122
123 match cfg.pick_early_type {
124 Some(PickEarlyType::FirstBestScoreImproving) => {
125 AnyForager::BestScoreImproving(FirstBestScoreImprovingForager::new())
126 }
127 Some(PickEarlyType::FirstLastStepScoreImproving) => {
128 AnyForager::LastStepScoreImproving(FirstLastStepScoreImprovingForager::new())
129 }
130 _ => {
131 let limit = cfg.accepted_count_limit.unwrap_or(1).max(1);
132 AnyForager::AcceptedCount(AcceptedCountForager::new(limit))
133 }
134 }
135 }
136}