solverforge_solver/heuristic/selector/move_selector/
iter.rs1pub struct MoveSelectorIter<S, M, C>
2where
3 S: PlanningSolution,
4 M: Move<S>,
5 C: MoveCursor<S, M>,
6{
7 cursor: C,
8 _phantom: PhantomData<(fn() -> S, fn() -> M)>,
9}
10
11#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
12pub struct MoveStreamContext {
13 step_index: u64,
14 step_seed: u64,
15 accepted_count_limit: Option<usize>,
16}
17
18impl MoveStreamContext {
19 pub const fn new(
20 step_index: u64,
21 step_seed: u64,
22 accepted_count_limit: Option<usize>,
23 ) -> Self {
24 Self {
25 step_index,
26 step_seed,
27 accepted_count_limit,
28 }
29 }
30
31 pub const fn step_index(self) -> u64 {
32 self.step_index
33 }
34
35 pub const fn step_seed(self) -> u64 {
36 self.step_seed
37 }
38
39 pub const fn accepted_count_limit(self) -> Option<usize> {
40 self.accepted_count_limit
41 }
42
43 pub fn start_offset(self, len: usize, salt: u64) -> usize {
44 if len <= 1 {
45 return 0;
46 }
47 if self.is_canonical() {
48 return 0;
49 }
50 (self.mixed_seed(salt) as usize) % len
51 }
52
53 pub fn stride(self, len: usize, salt: u64) -> usize {
54 if len <= 1 {
55 return 1;
56 }
57 if self.is_canonical() {
58 return 1;
59 }
60 let mut stride = (self.mixed_seed(salt) as usize % (len - 1)) + 1;
61 while gcd(stride, len) != 1 {
62 stride = if stride == len - 1 { 1 } else { stride + 1 };
63 }
64 stride
65 }
66
67 pub fn offset_seed(self, salt: u64) -> usize {
68 if self.is_canonical() {
69 return 0;
70 }
71 self.mixed_seed(salt) as usize
72 }
73
74 fn is_canonical(self) -> bool {
75 self.step_index == 0 && self.step_seed == 0 && self.accepted_count_limit.is_none()
76 }
77
78 fn mixed_seed(self, salt: u64) -> u64 {
79 splitmix64(self.step_seed ^ self.step_index.wrapping_mul(0x9E37_79B9_7F4A_7C15) ^ salt)
80 }
81}
82
83fn splitmix64(mut value: u64) -> u64 {
84 value = value.wrapping_add(0x9E37_79B9_7F4A_7C15);
85 value = (value ^ (value >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
86 value = (value ^ (value >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
87 value ^ (value >> 31)
88}
89
90fn gcd(mut left: usize, mut right: usize) -> usize {
91 while right != 0 {
92 let remainder = left % right;
93 left = right;
94 right = remainder;
95 }
96 left
97}
98
99impl<S, M, C> MoveSelectorIter<S, M, C>
100where
101 S: PlanningSolution,
102 M: Move<S>,
103 C: MoveCursor<S, M>,
104{
105 fn new(cursor: C) -> Self {
106 Self {
107 cursor,
108 _phantom: PhantomData,
109 }
110 }
111}
112
113impl<S, M, C> Iterator for MoveSelectorIter<S, M, C>
114where
115 S: PlanningSolution,
116 M: Move<S>,
117 C: MoveCursor<S, M>,
118{
119 type Item = M;
120
121 fn next(&mut self) -> Option<Self::Item> {
122 let id = self.cursor.next_candidate()?;
123 Some(self.cursor.take_candidate(id))
124 }
125}
126
127pub trait MoveSelector<S: PlanningSolution, M: Move<S>>: Send + Debug {
130 type Cursor<'a>: MoveCursor<S, M> + 'a
131 where
132 Self: 'a;
133
134 fn open_cursor<'a, D: Director<S>>(&'a self, score_director: &D) -> Self::Cursor<'a>;
135
136 fn open_cursor_with_context<'a, D: Director<S>>(
137 &'a self,
138 score_director: &D,
139 _context: MoveStreamContext,
140 ) -> Self::Cursor<'a> {
141 self.open_cursor(score_director)
142 }
143
144 fn iter_moves<'a, D: Director<S>>(
145 &'a self,
146 score_director: &D,
147 ) -> MoveSelectorIter<S, M, Self::Cursor<'a>> {
148 MoveSelectorIter::new(self.open_cursor(score_director))
149 }
150
151 fn size<D: Director<S>>(&self, score_director: &D) -> usize;
152
153 fn append_moves<D: Director<S>>(&self, score_director: &D, arena: &mut MoveArena<M>) {
154 let mut cursor = self.open_cursor(score_director);
155 for id in collect_cursor_indices::<S, M, _>(&mut cursor) {
156 arena.push(cursor.take_candidate(id));
157 }
158 }
159
160 fn is_never_ending(&self) -> bool {
161 false
162 }
163}