solverforge_solver/heuristic/selector/
list_swap.rs1use std::fmt::Debug;
58use std::marker::PhantomData;
59
60use solverforge_core::domain::PlanningSolution;
61use solverforge_scoring::Director;
62
63use crate::heuristic::r#move::{ListMoveImpl, ListSwapMove};
64
65use super::entity::EntitySelector;
66use super::list_support::collect_selected_entities;
67use super::move_selector::MoveSelector;
68
69pub struct ListSwapMoveSelector<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_set: fn(&mut S, usize, usize, V),
84 variable_name: &'static str,
85 descriptor_index: usize,
86 _phantom: PhantomData<(fn() -> S, fn() -> V)>,
87}
88
89impl<S, V: Debug, ES: Debug> Debug for ListSwapMoveSelector<S, V, ES> {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91 f.debug_struct("ListSwapMoveSelector")
92 .field("entity_selector", &self.entity_selector)
93 .field("variable_name", &self.variable_name)
94 .field("descriptor_index", &self.descriptor_index)
95 .finish()
96 }
97}
98
99impl<S, V, ES> ListSwapMoveSelector<S, V, ES> {
100 pub fn new(
110 entity_selector: ES,
111 list_len: fn(&S, usize) -> usize,
112 list_get: fn(&S, usize, usize) -> Option<V>,
113 list_set: fn(&mut S, usize, usize, V),
114 variable_name: &'static str,
115 descriptor_index: usize,
116 ) -> Self {
117 Self {
118 entity_selector,
119 list_len,
120 list_get,
121 list_set,
122 variable_name,
123 descriptor_index,
124 _phantom: PhantomData,
125 }
126 }
127}
128
129impl<S, V, ES> MoveSelector<S, ListSwapMove<S, V>> for ListSwapMoveSelector<S, V, ES>
130where
131 S: PlanningSolution,
132 V: Clone + PartialEq + Send + Sync + Debug + 'static,
133 ES: EntitySelector<S>,
134{
135 fn open_cursor<'a, D: Director<S>>(
136 &'a self,
137 score_director: &D,
138 ) -> impl Iterator<Item = ListSwapMove<S, V>> + 'a {
139 let list_len = self.list_len;
140 let list_get = self.list_get;
141 let list_set = self.list_set;
142 let variable_name = self.variable_name;
143 let descriptor_index = self.descriptor_index;
144
145 let selected = collect_selected_entities(&self.entity_selector, score_director, list_len);
146 let move_capacity = selected.list_swap_move_capacity();
147 let entities = selected.entities;
148 let route_lens = selected.route_lens;
149
150 let mut moves = Vec::with_capacity(move_capacity);
151
152 for (i, &entity_a) in entities.iter().enumerate() {
153 let len_a = route_lens[i];
154 if len_a == 0 {
155 continue;
156 }
157
158 for pos_a in 0..len_a {
160 for pos_b in pos_a + 1..len_a {
161 moves.push(ListSwapMove::new(
162 entity_a,
163 pos_a,
164 entity_a,
165 pos_b,
166 list_len,
167 list_get,
168 list_set,
169 variable_name,
170 descriptor_index,
171 ));
172 }
173 }
174
175 for (j, &entity_b) in entities.iter().enumerate() {
177 if j <= i {
178 continue;
179 }
180 let len_b = route_lens[j];
181 if len_b == 0 {
182 continue;
183 }
184
185 for pos_a in 0..len_a {
186 for pos_b in 0..len_b {
187 moves.push(ListSwapMove::new(
188 entity_a,
189 pos_a,
190 entity_b,
191 pos_b,
192 list_len,
193 list_get,
194 list_set,
195 variable_name,
196 descriptor_index,
197 ));
198 }
199 }
200 }
201 }
202
203 moves.into_iter()
204 }
205
206 fn size<D: Director<S>>(&self, score_director: &D) -> usize {
207 collect_selected_entities(&self.entity_selector, score_director, self.list_len)
208 .list_swap_move_capacity()
209 }
210}
211
212pub struct ListMoveListSwapSelector<S, V, ES> {
214 inner: ListSwapMoveSelector<S, V, ES>,
215}
216
217impl<S, V: Debug, ES: Debug> Debug for ListMoveListSwapSelector<S, V, ES> {
218 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219 f.debug_struct("ListMoveListSwapSelector")
220 .field("inner", &self.inner)
221 .finish()
222 }
223}
224
225impl<S, V, ES> ListMoveListSwapSelector<S, V, ES> {
226 pub fn new(inner: ListSwapMoveSelector<S, V, ES>) -> Self {
228 Self { inner }
229 }
230}
231
232impl<S, V, ES> MoveSelector<S, ListMoveImpl<S, V>> for ListMoveListSwapSelector<S, V, ES>
233where
234 S: PlanningSolution,
235 V: Clone + PartialEq + Send + Sync + Debug + 'static,
236 ES: EntitySelector<S>,
237{
238 fn open_cursor<'a, D: Director<S>>(
239 &'a self,
240 score_director: &D,
241 ) -> impl Iterator<Item = ListMoveImpl<S, V>> + 'a {
242 self.inner
243 .open_cursor(score_director)
244 .map(ListMoveImpl::ListSwap)
245 }
246
247 fn size<D: Director<S>>(&self, score_director: &D) -> usize {
248 self.inner.size(score_director)
249 }
250}