1use std::fmt::Debug;
4
5use solverforge_core::domain::PlanningSolution;
6use solverforge_scoring::Director;
7
8use crate::heuristic::r#move::ListMoveUnion;
9use crate::heuristic::selector::list_kernel::{
10 critical_analysis, filtered_move_count, filtered_multi_support_swap_count,
11 multi_critical_ruin_count, CriticalAnalysis, NativePrecedenceEmitter, PrecedenceCursor,
12};
13
14use super::entity::EntitySelector;
15use super::move_selector::{
16 CandidateId, MoveCandidateRef, MoveCursor, MoveSelector, MoveStreamContext,
17};
18use super::precedence_route::PrecedenceRouteHooks;
19
20pub struct ListPrecedenceMoveSelector<S, V, ES> {
26 entity_selector: ES,
27 element_count: fn(&S) -> usize,
28 index_to_element: fn(&S, usize) -> V,
29 node_duration: fn(&S, V) -> usize,
30 fixed_successors: fn(&S, V, &mut Vec<V>),
31 entity_count: fn(&S) -> usize,
32 list_len: fn(&S, usize) -> usize,
33 list_get: fn(&S, usize, usize) -> Option<V>,
34 list_remove: fn(&mut S, usize, usize) -> Option<V>,
35 list_insert: fn(&mut S, usize, usize, V),
36 list_set: fn(&mut S, usize, usize, V),
37 list_reverse: fn(&mut S, usize, usize, usize),
38 ruin_remove: fn(&mut S, usize, usize) -> V,
39 ruin_insert: fn(&mut S, usize, usize, V),
40 element_owner_fn: Option<fn(&S, &V) -> Option<usize>>,
41 sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
42 sublist_insert: fn(&mut S, usize, usize, Vec<V>),
43 variable_name: &'static str,
44 descriptor_index: usize,
45}
46
47pub struct ListPrecedenceMoveCursor<S, V>
49where
50 S: PlanningSolution,
51 V: Clone + PartialEq + Send + Sync + Debug + 'static,
52{
53 inner: PrecedenceCursor<S, NativePrecedenceEmitter<S, V>>,
54}
55
56impl<S, V> ListPrecedenceMoveCursor<S, V>
57where
58 S: PlanningSolution,
59 V: Clone + PartialEq + Send + Sync + Debug + 'static,
60{
61 fn new(inner: PrecedenceCursor<S, NativePrecedenceEmitter<S, V>>) -> Self {
62 Self { inner }
63 }
64}
65
66impl<S, V> MoveCursor<S, ListMoveUnion<S, V>> for ListPrecedenceMoveCursor<S, V>
67where
68 S: PlanningSolution,
69 V: Clone + PartialEq + Send + Sync + Debug + 'static,
70{
71 fn next_candidate(&mut self, solution: &S) -> Option<CandidateId> {
72 self.inner.next_candidate(solution)
73 }
74
75 fn candidate(&self, id: CandidateId) -> Option<MoveCandidateRef<'_, S, ListMoveUnion<S, V>>> {
76 self.inner.candidate(id)
77 }
78
79 fn take_candidate(&mut self, id: CandidateId) -> ListMoveUnion<S, V> {
80 self.inner.take_candidate(id)
81 }
82
83 fn next_owned_candidate(&mut self, solution: &S) -> Option<ListMoveUnion<S, V>> {
84 self.inner.next_owned_candidate(solution)
85 }
86
87 fn next_owned_candidate_matching(
88 &mut self,
89 solution: &S,
90 predicate: for<'a> fn(MoveCandidateRef<'a, S, ListMoveUnion<S, V>>) -> bool,
91 ) -> Option<ListMoveUnion<S, V>> {
92 self.inner
93 .next_owned_candidate_matching(solution, predicate)
94 }
95
96 fn release_candidate(&mut self, id: CandidateId) -> bool {
97 self.inner.release_candidate(id)
98 }
99}
100
101impl<S, V: Debug, ES: Debug> Debug for ListPrecedenceMoveSelector<S, V, ES> {
102 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103 formatter
104 .debug_struct("ListPrecedenceMoveSelector")
105 .field("entity_selector", &self.entity_selector)
106 .field("variable_name", &self.variable_name)
107 .finish()
108 }
109}
110
111impl<S, V, ES> ListPrecedenceMoveSelector<S, V, ES> {
112 #[allow(clippy::too_many_arguments)]
113 pub fn new(
114 entity_selector: ES,
115 element_count: fn(&S) -> usize,
116 index_to_element: fn(&S, usize) -> V,
117 node_duration: fn(&S, V) -> usize,
118 fixed_successors: fn(&S, V, &mut Vec<V>),
119 entity_count: fn(&S) -> usize,
120 list_len: fn(&S, usize) -> usize,
121 list_get: fn(&S, usize, usize) -> Option<V>,
122 list_remove: fn(&mut S, usize, usize) -> Option<V>,
123 list_insert: fn(&mut S, usize, usize, V),
124 list_set: fn(&mut S, usize, usize, V),
125 list_reverse: fn(&mut S, usize, usize, usize),
126 ruin_remove: fn(&mut S, usize, usize) -> V,
127 ruin_insert: fn(&mut S, usize, usize, V),
128 element_owner_fn: Option<fn(&S, &V) -> Option<usize>>,
129 sublist_remove: fn(&mut S, usize, usize, usize) -> Vec<V>,
130 sublist_insert: fn(&mut S, usize, usize, Vec<V>),
131 variable_name: &'static str,
132 descriptor_index: usize,
133 ) -> Self {
134 Self {
135 entity_selector,
136 element_count,
137 index_to_element,
138 node_duration,
139 fixed_successors,
140 entity_count,
141 list_len,
142 list_get,
143 list_remove,
144 list_insert,
145 list_set,
146 list_reverse,
147 ruin_remove,
148 ruin_insert,
149 element_owner_fn,
150 sublist_remove,
151 sublist_insert,
152 variable_name,
153 descriptor_index,
154 }
155 }
156}
157
158impl<S, V, ES> MoveSelector<S, ListMoveUnion<S, V>> for ListPrecedenceMoveSelector<S, V, ES>
159where
160 S: PlanningSolution,
161 V: Clone + PartialEq + Send + Sync + Debug + 'static,
162 ES: EntitySelector<S>,
163{
164 type Cursor<'a>
165 = ListPrecedenceMoveCursor<S, V>
166 where
167 Self: 'a;
168
169 fn open_cursor<'a, D: Director<S>>(&'a self, score_director: &D) -> Self::Cursor<'a> {
170 self.open_cursor_with_context(score_director, MoveStreamContext::default())
171 }
172
173 fn open_cursor_with_context<'a, D: Director<S>>(
174 &'a self,
175 score_director: &D,
176 context: MoveStreamContext,
177 ) -> Self::Cursor<'a> {
178 let analysis = self.analysis(score_director);
179 let emitter = self.emitter();
180 ListPrecedenceMoveCursor::new(PrecedenceCursor::new(
181 analysis.blocks,
182 analysis.route_graph,
183 context,
184 emitter,
185 self.descriptor_index,
186 ))
187 }
188
189 fn size<D: Director<S>>(&self, score_director: &D) -> usize {
190 let mut analysis = self.analysis(score_director);
191 analysis
192 .blocks
193 .iter()
194 .copied()
195 .map(|block| filtered_move_count(block, &mut analysis.route_graph))
196 .sum::<usize>()
197 + filtered_multi_support_swap_count(&analysis.blocks, &mut analysis.route_graph)
198 + multi_critical_ruin_count(&analysis.blocks)
199 }
200}
201
202impl<S, V, ES> ListPrecedenceMoveSelector<S, V, ES>
203where
204 S: PlanningSolution,
205 V: Clone + PartialEq + Send + Sync + Debug + 'static,
206 ES: EntitySelector<S>,
207{
208 fn analysis<D: Director<S>>(&self, score_director: &D) -> CriticalAnalysis {
209 critical_analysis(
210 score_director,
211 &self.entity_selector,
212 self.element_count,
213 self.index_to_element,
214 self.node_duration,
215 self.list_len,
216 PrecedenceRouteHooks::new(
217 self.fixed_successors,
218 self.entity_count,
219 self.list_len,
220 self.list_get,
221 ),
222 )
223 }
224
225 fn emitter(&self) -> NativePrecedenceEmitter<S, V> {
226 NativePrecedenceEmitter::new(
227 self.element_count,
228 self.index_to_element,
229 self.fixed_successors,
230 self.entity_count,
231 self.list_len,
232 self.list_get,
233 self.list_remove,
234 self.list_insert,
235 self.list_set,
236 self.list_reverse,
237 self.ruin_remove,
238 self.ruin_insert,
239 self.element_owner_fn,
240 self.sublist_remove,
241 self.sublist_insert,
242 self.variable_name,
243 self.descriptor_index,
244 )
245 }
246}