1use std::fmt::Debug;
57use std::marker::PhantomData;
58
59use solverforge_core::domain::PlanningSolution;
60use solverforge_scoring::Director;
61
62use crate::heuristic::r#move::ListReverseMove;
63
64use super::entity::EntitySelector;
65use super::list_support::ordered_index;
66use super::move_selector::{
67 CandidateId, CandidateStore, MoveCandidateRef, MoveCursor, MoveSelector, MoveStreamContext,
68};
69
70pub struct ListReverseMoveSelector<S, V, ES> {
80 entity_selector: ES,
81 list_len: fn(&S, usize) -> usize,
82 list_get: fn(&S, usize, usize) -> Option<V>,
83 list_reverse: fn(&mut S, usize, usize, usize),
84 variable_name: &'static str,
85 descriptor_index: usize,
86 _phantom: PhantomData<(fn() -> S, fn() -> V)>,
87}
88
89pub struct ListReverseMoveCursor<S, V>
90where
91 S: PlanningSolution,
92 V: Clone + Send + Sync + Debug + 'static,
93{
94 store: CandidateStore<S, ListReverseMove<S, V>>,
95 entities: Vec<usize>,
96 route_lens: Vec<usize>,
97 context: MoveStreamContext,
98 entity_idx: usize,
99 start_offset: usize,
100 end_offset: usize,
101 list_len: fn(&S, usize) -> usize,
102 list_get: fn(&S, usize, usize) -> Option<V>,
103 list_reverse: fn(&mut S, usize, usize, usize),
104 variable_name: &'static str,
105 descriptor_index: usize,
106}
107
108impl<S, V> ListReverseMoveCursor<S, V>
109where
110 S: PlanningSolution,
111 V: Clone + Send + Sync + Debug + 'static,
112{
113 #[allow(clippy::too_many_arguments)]
114 fn new(
115 entities: Vec<usize>,
116 route_lens: Vec<usize>,
117 context: MoveStreamContext,
118 list_len: fn(&S, usize) -> usize,
119 list_get: fn(&S, usize, usize) -> Option<V>,
120 list_reverse: fn(&mut S, usize, usize, usize),
121 variable_name: &'static str,
122 descriptor_index: usize,
123 ) -> Self {
124 Self {
125 store: CandidateStore::new(),
126 entities,
127 route_lens,
128 context,
129 entity_idx: 0,
130 start_offset: 0,
131 end_offset: 0,
132 list_len,
133 list_get,
134 list_reverse,
135 variable_name,
136 descriptor_index,
137 }
138 }
139
140 fn push_move(&mut self, entity: usize, start: usize, end: usize) -> CandidateId {
141 self.store.push(ListReverseMove::new(
142 entity,
143 start,
144 end,
145 self.list_len,
146 self.list_get,
147 self.list_reverse,
148 self.variable_name,
149 self.descriptor_index,
150 ))
151 }
152}
153
154impl<S, V> MoveCursor<S, ListReverseMove<S, V>> for ListReverseMoveCursor<S, V>
155where
156 S: PlanningSolution,
157 V: Clone + Send + Sync + Debug + 'static,
158{
159 fn next_candidate(&mut self) -> Option<CandidateId> {
160 loop {
161 let entity = *self.entities.get(self.entity_idx)?;
162 let len = self.route_lens[self.entity_idx];
163 if len < 2 {
164 self.entity_idx += 1;
165 self.start_offset = 0;
166 self.end_offset = 0;
167 continue;
168 }
169
170 while self.start_offset < len {
171 let start = ordered_index(
172 self.start_offset,
173 len,
174 self.context,
175 0x1157_2A07_0000_0002 ^ entity as u64 ^ self.descriptor_index as u64,
176 );
177 let end_count = len.saturating_sub(start + 1);
178 if self.end_offset < end_count {
179 let end = start
180 + 2
181 + ordered_index(
182 self.end_offset,
183 end_count,
184 self.context,
185 0x1157_2A07_0000_0003 ^ entity as u64 ^ start as u64,
186 );
187 self.end_offset += 1;
188 return Some(self.push_move(entity, start, end));
189 }
190 self.start_offset += 1;
191 self.end_offset = 0;
192 }
193
194 self.entity_idx += 1;
195 self.start_offset = 0;
196 self.end_offset = 0;
197 }
198 }
199
200 fn candidate(&self, id: CandidateId) -> Option<MoveCandidateRef<'_, S, ListReverseMove<S, V>>> {
201 self.store.candidate(id)
202 }
203
204 fn take_candidate(&mut self, id: CandidateId) -> ListReverseMove<S, V> {
205 self.store.take_candidate(id)
206 }
207}
208
209impl<S, V> Iterator for ListReverseMoveCursor<S, V>
210where
211 S: PlanningSolution,
212 V: Clone + Send + Sync + Debug + 'static,
213{
214 type Item = ListReverseMove<S, V>;
215
216 fn next(&mut self) -> Option<Self::Item> {
217 let id = self.next_candidate()?;
218 Some(self.take_candidate(id))
219 }
220}
221
222impl<S, V: Debug, ES: Debug> Debug for ListReverseMoveSelector<S, V, ES> {
223 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
224 f.debug_struct("ListReverseMoveSelector")
225 .field("entity_selector", &self.entity_selector)
226 .field("variable_name", &self.variable_name)
227 .field("descriptor_index", &self.descriptor_index)
228 .finish()
229 }
230}
231
232impl<S, V, ES> ListReverseMoveSelector<S, V, ES> {
233 pub fn new(
242 entity_selector: ES,
243 list_len: fn(&S, usize) -> usize,
244 list_get: fn(&S, usize, usize) -> Option<V>,
245 list_reverse: fn(&mut S, usize, usize, usize),
246 variable_name: &'static str,
247 descriptor_index: usize,
248 ) -> Self {
249 Self {
250 entity_selector,
251 list_len,
252 list_get,
253 list_reverse,
254 variable_name,
255 descriptor_index,
256 _phantom: PhantomData,
257 }
258 }
259}
260
261impl<S, V, ES> MoveSelector<S, ListReverseMove<S, V>> for ListReverseMoveSelector<S, V, ES>
262where
263 S: PlanningSolution,
264 V: Clone + Send + Sync + Debug + 'static,
265 ES: EntitySelector<S>,
266{
267 type Cursor<'a>
268 = ListReverseMoveCursor<S, V>
269 where
270 Self: 'a;
271
272 fn open_cursor<'a, D: Director<S>>(&'a self, score_director: &D) -> Self::Cursor<'a> {
273 self.open_cursor_with_context(score_director, MoveStreamContext::default())
274 }
275
276 fn open_cursor_with_context<'a, D: Director<S>>(
277 &'a self,
278 score_director: &D,
279 context: MoveStreamContext,
280 ) -> Self::Cursor<'a> {
281 let mut entities: Vec<usize> = self
282 .entity_selector
283 .iter(score_director)
284 .map(|r| r.entity_index)
285 .collect();
286 let entity_start = context.start_offset(
287 entities.len(),
288 0x1157_2A07_0000_0001 ^ self.descriptor_index as u64,
289 );
290 entities.rotate_left(entity_start);
291
292 let solution = score_director.working_solution();
293 let route_lens = entities
294 .iter()
295 .map(|&entity| (self.list_len)(solution, entity))
296 .collect();
297
298 ListReverseMoveCursor::new(
299 entities,
300 route_lens,
301 context,
302 self.list_len,
303 self.list_get,
304 self.list_reverse,
305 self.variable_name,
306 self.descriptor_index,
307 )
308 }
309
310 fn size<D: Director<S>>(&self, score_director: &D) -> usize {
311 let solution = score_director.working_solution();
312 let list_len = self.list_len;
313
314 self.entity_selector
315 .iter(score_director)
316 .map(|r| {
317 let m = list_len(solution, r.entity_index);
318 if m >= 2 {
321 m * (m - 1) / 2
322 } else {
323 0
324 }
325 })
326 .sum()
327 }
328}