solverforge_solver/heuristic/selector/move_selector/
iter.rs1use solverforge_config::SelectionOrder;
2
3pub struct MoveSelectorIter<S, M, C>
4where
5 S: PlanningSolution,
6 M: Move<S>,
7 C: MoveCursor<S, M>,
8{
9 cursor: C,
10 _phantom: PhantomData<(fn() -> S, fn() -> M)>,
11}
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq)]
14pub struct MoveStreamContext {
15 step_index: u64,
16 step_seed: u64,
17 accepted_count_limit: Option<usize>,
18 selection_order: SelectionOrder,
19}
20
21impl MoveStreamContext {
22 pub const fn new(
23 step_index: u64,
24 step_seed: u64,
25 accepted_count_limit: Option<usize>,
26 ) -> Self {
27 Self {
28 step_index,
29 step_seed,
30 accepted_count_limit,
31 selection_order: SelectionOrder::Original,
32 }
33 }
34
35 pub const fn with_selection_order(mut self, selection_order: SelectionOrder) -> Self {
36 self.selection_order = selection_order;
37 self
38 }
39
40 pub const fn selection_order(self) -> SelectionOrder {
41 self.selection_order
42 }
43
44 pub const fn step_index(self) -> u64 {
45 self.step_index
46 }
47
48 pub const fn step_seed(self) -> u64 {
49 self.step_seed
50 }
51
52 pub const fn accepted_count_limit(self) -> Option<usize> {
53 self.accepted_count_limit
54 }
55
56 pub fn start_offset(self, len: usize, salt: u64) -> usize {
57 if len <= 1 {
58 return 0;
59 }
60 if self.is_canonical() {
61 return 0;
62 }
63 (self.mixed_seed(salt) as usize) % len
64 }
65
66 pub fn stride(self, len: usize, salt: u64) -> usize {
67 if len <= 1 {
68 return 1;
69 }
70 if self.is_canonical() {
71 return 1;
72 }
73 let mut stride = (self.mixed_seed(salt) as usize % (len - 1)) + 1;
74 while gcd(stride, len) != 1 {
75 stride = if stride == len - 1 { 1 } else { stride + 1 };
76 }
77 stride
78 }
79
80 pub fn offset_seed(self, salt: u64) -> usize {
81 if self.is_canonical() {
82 return 0;
83 }
84 self.mixed_seed(salt) as usize
85 }
86
87 pub(crate) fn random_index(self, len: usize, salt: u64) -> usize {
88 if len <= 1 {
89 return 0;
90 }
91 (self.mixed_seed(salt) as usize) % len
92 }
93
94 pub(crate) fn random_stride(self, len: usize, salt: u64) -> usize {
95 if len <= 1 {
96 return 1;
97 }
98 let mut stride = (self.mixed_seed(salt) as usize % (len - 1)) + 1;
99 while gcd(stride, len) != 1 {
100 stride = if stride == len - 1 { 1 } else { stride + 1 };
101 }
102 stride
103 }
104
105 pub(crate) fn random_seed(self, salt: u64) -> u64 {
106 self.mixed_seed(salt)
107 }
108
109 pub(crate) fn selection_index(self, offset: usize, len: usize, salt: u64) -> usize {
110 debug_assert!(offset < len);
111 match self.selection_order {
112 SelectionOrder::Original | SelectionOrder::Sorted | SelectionOrder::Probabilistic => {
113 offset
114 }
115 SelectionOrder::Random => self.random_index(
116 len,
117 salt ^ (offset as u64).wrapping_mul(0xD1B5_4A32_D192_ED03),
118 ),
119 SelectionOrder::Shuffled => {
120 let start = self.random_index(len, salt);
121 let stride = self.random_stride(len, salt ^ 0xA24B_AED4_963E_E407);
122 (start + offset * stride) % len
123 }
124 }
125 }
126
127 pub(crate) fn selection_index_without_replacement(
131 self,
132 offset: usize,
133 len: usize,
134 salt: u64,
135 ) -> usize {
136 debug_assert!(offset < len);
137 match self.selection_order {
138 SelectionOrder::Original | SelectionOrder::Sorted | SelectionOrder::Probabilistic => {
139 offset
140 }
141 SelectionOrder::Random | SelectionOrder::Shuffled => {
142 let start = self.random_index(len, salt);
143 let stride = self.random_stride(len, salt ^ 0xA24B_AED4_963E_E407);
144 (start + offset * stride) % len
145 }
146 }
147 }
148
149 pub(crate) fn apply_selection_order<T: Clone>(self, values: &mut [T], salt: u64) {
150 if self.is_canonical() {
151 return;
152 }
153 let canonical = values.to_vec();
154 for (offset, value) in values.iter_mut().enumerate() {
155 *value = canonical[self.selection_index(offset, canonical.len(), salt)].clone();
156 }
157 }
158
159 pub(crate) fn apply_selection_order_without_replacement<T: Clone>(
160 self,
161 values: &mut [T],
162 salt: u64,
163 ) {
164 if self.is_canonical() {
165 return;
166 }
167 let canonical = values.to_vec();
168 for (offset, value) in values.iter_mut().enumerate() {
169 *value = canonical
170 [self.selection_index_without_replacement(offset, canonical.len(), salt)]
171 .clone();
172 }
173 }
174
175 pub(crate) const fn is_canonical(self) -> bool {
176 matches!(
177 self.selection_order,
178 SelectionOrder::Original | SelectionOrder::Sorted | SelectionOrder::Probabilistic
179 )
180 }
181
182 fn mixed_seed(self, salt: u64) -> u64 {
183 splitmix64(self.step_seed ^ self.step_index.wrapping_mul(0x9E37_79B9_7F4A_7C15) ^ salt)
184 }
185}
186
187impl Default for MoveStreamContext {
188 fn default() -> Self {
189 Self::new(0, 0, None)
190 }
191}
192
193fn splitmix64(mut value: u64) -> u64 {
194 value = value.wrapping_add(0x9E37_79B9_7F4A_7C15);
195 value = (value ^ (value >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
196 value = (value ^ (value >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
197 value ^ (value >> 31)
198}
199
200fn gcd(mut left: usize, mut right: usize) -> usize {
201 while right != 0 {
202 let remainder = left % right;
203 left = right;
204 right = remainder;
205 }
206 left
207}
208
209impl<S, M, C> MoveSelectorIter<S, M, C>
210where
211 S: PlanningSolution,
212 M: Move<S>,
213 C: MoveCursor<S, M>,
214{
215 fn new(cursor: C) -> Self {
216 Self {
217 cursor,
218 _phantom: PhantomData,
219 }
220 }
221}
222
223impl<S, M, C> Iterator for MoveSelectorIter<S, M, C>
224where
225 S: PlanningSolution,
226 M: Move<S>,
227 C: MoveCursor<S, M>,
228{
229 type Item = M;
230
231 #[inline(always)]
232 fn next(&mut self) -> Option<Self::Item> {
233 self.cursor.next_owned_candidate()
234 }
235}
236
237pub trait MoveSelector<S: PlanningSolution, M: Move<S>>: Send + Debug {
240 type Cursor<'a>: MoveCursor<S, M> + 'a
241 where
242 Self: 'a;
243
244 fn open_cursor<'a, D: Director<S>>(&'a self, score_director: &D) -> Self::Cursor<'a>;
245
246 fn open_cursor_with_context<'a, D: Director<S>>(
247 &'a self,
248 score_director: &D,
249 _context: MoveStreamContext,
250 ) -> Self::Cursor<'a> {
251 self.open_cursor(score_director)
252 }
253
254 fn validate_cursor<D: Director<S>>(&self, _score_director: &D) {}
259
260 fn iter_moves<'a, D: Director<S>>(
261 &'a self,
262 score_director: &D,
263 ) -> MoveSelectorIter<S, M, Self::Cursor<'a>> {
264 MoveSelectorIter::new(self.open_cursor(score_director))
265 }
266
267 fn size<D: Director<S>>(&self, score_director: &D) -> usize;
268
269 fn append_moves<D: Director<S>>(&self, score_director: &D, arena: &mut MoveArena<M>) {
270 let mut cursor = self.open_cursor(score_director);
271 for id in collect_cursor_indices::<S, M, _>(&mut cursor) {
272 arena.push(cursor.take_candidate(id));
273 }
274 }
275
276 fn is_never_ending(&self) -> bool {
277 false
278 }
279}