solverforge_solver/phase/localsearch/acceptor/
entity_tabu.rs1use std::fmt::Debug;
4
5use solverforge_core::domain::PlanningSolution;
6
7use super::Acceptor;
8
9pub struct EntityTabuAcceptor {
24 entity_tabu_size: usize,
26 entity_tabu_list: Vec<u64>,
28 current_step_entities: Vec<u64>,
30}
31
32impl Debug for EntityTabuAcceptor {
33 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34 f.debug_struct("EntityTabuAcceptor")
35 .field("entity_tabu_size", &self.entity_tabu_size)
36 .field("tabu_list_len", &self.entity_tabu_list.len())
37 .finish()
38 }
39}
40
41impl Clone for EntityTabuAcceptor {
42 fn clone(&self) -> Self {
43 Self {
44 entity_tabu_size: self.entity_tabu_size,
45 entity_tabu_list: self.entity_tabu_list.clone(),
46 current_step_entities: self.current_step_entities.clone(),
47 }
48 }
49}
50
51impl EntityTabuAcceptor {
52 pub fn new(entity_tabu_size: usize) -> Self {
58 assert!(entity_tabu_size > 0, "entity_tabu_size must be > 0, got 0");
59 Self {
60 entity_tabu_size,
61 entity_tabu_list: Vec::with_capacity(entity_tabu_size),
62 current_step_entities: Vec::new(),
63 }
64 }
65
66 pub fn record_entity_move(&mut self, entity_id: u64) {
68 self.current_step_entities.push(entity_id);
69 }
70
71 pub fn is_entity_tabu(&self, entity_id: u64) -> bool {
72 self.entity_tabu_list.contains(&entity_id)
73 }
74}
75
76impl Default for EntityTabuAcceptor {
77 fn default() -> Self {
78 Self::new(7)
79 }
80}
81
82impl<S: PlanningSolution> Acceptor<S> for EntityTabuAcceptor {
83 fn is_accepted(&mut self, last_step_score: &S::Score, move_score: &S::Score) -> bool {
84 if move_score > last_step_score {
86 return true;
87 }
88
89 if move_score >= last_step_score {
91 return true;
92 }
93
94 false
95 }
96
97 fn phase_started(&mut self, _initial_score: &S::Score) {
98 self.entity_tabu_list.clear();
99 self.current_step_entities.clear();
100 }
101
102 fn phase_ended(&mut self) {
103 self.entity_tabu_list.clear();
104 }
105
106 fn step_started(&mut self) {
107 self.current_step_entities.clear();
108 }
109
110 fn step_ended(&mut self, _step_score: &S::Score) {
111 for entity_id in &self.current_step_entities {
113 if self.entity_tabu_list.len() >= self.entity_tabu_size {
114 self.entity_tabu_list.remove(0);
115 }
116 self.entity_tabu_list.push(*entity_id);
117 }
118 self.current_step_entities.clear();
119 }
120}