solverforge_solver/heuristic/move/
pillar_swap.rs1use std::fmt::Debug;
12
13use solverforge_core::domain::PlanningSolution;
14use solverforge_scoring::ScoreDirector;
15
16use super::Move;
17
18pub struct PillarSwapMove<S, V> {
27 left_indices: Vec<usize>,
28 right_indices: Vec<usize>,
29 descriptor_index: usize,
30 variable_name: &'static str,
31 getter: fn(&S, usize) -> Option<V>,
33 setter: fn(&mut S, usize, Option<V>),
35}
36
37impl<S, V: Clone> Clone for PillarSwapMove<S, V> {
38 fn clone(&self) -> Self {
39 Self {
40 left_indices: self.left_indices.clone(),
41 right_indices: self.right_indices.clone(),
42 descriptor_index: self.descriptor_index,
43 variable_name: self.variable_name,
44 getter: self.getter,
45 setter: self.setter,
46 }
47 }
48}
49
50impl<S, V: Debug> Debug for PillarSwapMove<S, V> {
51 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52 f.debug_struct("PillarSwapMove")
53 .field("left_indices", &self.left_indices)
54 .field("right_indices", &self.right_indices)
55 .field("descriptor_index", &self.descriptor_index)
56 .field("variable_name", &self.variable_name)
57 .finish()
58 }
59}
60
61impl<S, V> PillarSwapMove<S, V> {
62 pub fn new(
72 left_indices: Vec<usize>,
73 right_indices: Vec<usize>,
74 getter: fn(&S, usize) -> Option<V>,
75 setter: fn(&mut S, usize, Option<V>),
76 variable_name: &'static str,
77 descriptor_index: usize,
78 ) -> Self {
79 Self {
80 left_indices,
81 right_indices,
82 descriptor_index,
83 variable_name,
84 getter,
85 setter,
86 }
87 }
88
89 pub fn left_indices(&self) -> &[usize] {
91 &self.left_indices
92 }
93
94 pub fn right_indices(&self) -> &[usize] {
96 &self.right_indices
97 }
98}
99
100impl<S, V> Move<S> for PillarSwapMove<S, V>
101where
102 S: PlanningSolution,
103 V: Clone + PartialEq + Send + Sync + Debug + 'static,
104{
105 fn is_doable<D: ScoreDirector<S>>(&self, score_director: &D) -> bool {
106 if self.left_indices.is_empty() || self.right_indices.is_empty() {
107 return false;
108 }
109
110 let count = score_director.entity_count(self.descriptor_index);
111 let max = count.unwrap_or(0);
112
113 for &idx in self.left_indices.iter().chain(&self.right_indices) {
115 if idx >= max {
116 return false;
117 }
118 }
119
120 let left_val = self
122 .left_indices
123 .first()
124 .map(|&idx| (self.getter)(score_director.working_solution(), idx));
125 let right_val = self
126 .right_indices
127 .first()
128 .map(|&idx| (self.getter)(score_director.working_solution(), idx));
129
130 left_val != right_val
131 }
132
133 fn do_move<D: ScoreDirector<S>>(&self, score_director: &mut D) {
134 let left_old: Vec<(usize, Option<V>)> = self
136 .left_indices
137 .iter()
138 .map(|&idx| (idx, (self.getter)(score_director.working_solution(), idx)))
139 .collect();
140 let right_old: Vec<(usize, Option<V>)> = self
141 .right_indices
142 .iter()
143 .map(|&idx| (idx, (self.getter)(score_director.working_solution(), idx)))
144 .collect();
145
146 let left_value = left_old.first().and_then(|(_, v)| v.clone());
148 let right_value = right_old.first().and_then(|(_, v)| v.clone());
149
150 for &idx in self.left_indices.iter().chain(&self.right_indices) {
152 score_director.before_variable_changed(self.descriptor_index, idx, self.variable_name);
153 }
154
155 for &idx in &self.left_indices {
157 (self.setter)(
158 score_director.working_solution_mut(),
159 idx,
160 right_value.clone(),
161 );
162 }
163 for &idx in &self.right_indices {
165 (self.setter)(
166 score_director.working_solution_mut(),
167 idx,
168 left_value.clone(),
169 );
170 }
171
172 for &idx in self.left_indices.iter().chain(&self.right_indices) {
174 score_director.after_variable_changed(self.descriptor_index, idx, self.variable_name);
175 }
176
177 let setter = self.setter;
179 score_director.register_undo(Box::new(move |s: &mut S| {
180 for (idx, old_value) in left_old {
181 setter(s, idx, old_value);
182 }
183 for (idx, old_value) in right_old {
184 setter(s, idx, old_value);
185 }
186 }));
187 }
188
189 fn descriptor_index(&self) -> usize {
190 self.descriptor_index
191 }
192
193 fn entity_indices(&self) -> &[usize] {
194 &self.left_indices
196 }
197
198 fn variable_name(&self) -> &str {
199 self.variable_name
200 }
201}