Skip to main content

solverforge_solver/heuristic/selector/move_selector/
swap.rs

1/// A swap move selector that generates `SwapMove` instances.
2pub struct SwapMoveSelector<S, V, LES, RES> {
3    left_entity_selector: LES,
4    right_entity_selector: RES,
5    getter: fn(&S, usize, usize) -> Option<V>,
6    setter: fn(&mut S, usize, usize, Option<V>),
7    descriptor_index: usize,
8    variable_index: usize,
9    variable_name: &'static str,
10    _phantom: PhantomData<(fn() -> S, fn() -> V)>,
11}
12
13pub struct SwapMoveCursor<S, V>
14where
15    S: PlanningSolution,
16    V: Clone + PartialEq + Send + Sync + Debug + 'static,
17{
18    store: CandidateStore<S, SwapMove<S, V>>,
19    left_entities: Vec<super::entity::EntityReference>,
20    right_entities: Vec<super::entity::EntityReference>,
21    left_offset: usize,
22    right_offset: usize,
23    getter: fn(&S, usize, usize) -> Option<V>,
24    setter: fn(&mut S, usize, usize, Option<V>),
25    descriptor_index: usize,
26    variable_index: usize,
27    variable_name: &'static str,
28}
29
30impl<S, V> SwapMoveCursor<S, V>
31where
32    S: PlanningSolution,
33    V: Clone + PartialEq + Send + Sync + Debug + 'static,
34{
35    fn new(
36        left_entities: Vec<super::entity::EntityReference>,
37        right_entities: Vec<super::entity::EntityReference>,
38        getter: fn(&S, usize, usize) -> Option<V>,
39        setter: fn(&mut S, usize, usize, Option<V>),
40        descriptor_index: usize,
41        variable_index: usize,
42        variable_name: &'static str,
43    ) -> Self {
44        Self {
45            store: CandidateStore::new(),
46            left_entities,
47            right_entities,
48            left_offset: 0,
49            right_offset: 0,
50            getter,
51            setter,
52            descriptor_index,
53            variable_index,
54            variable_name,
55        }
56    }
57}
58
59impl<S, V> MoveCursor<S, SwapMove<S, V>> for SwapMoveCursor<S, V>
60where
61    S: PlanningSolution,
62    V: Clone + PartialEq + Send + Sync + Debug + 'static,
63{
64    fn next_candidate(&mut self) -> Option<CandidateId> {
65        while self.left_offset < self.left_entities.len() {
66            while self.right_offset < self.right_entities.len() {
67                let left_entity_ref = self.left_entities[self.left_offset];
68                let right_entity_ref = self.right_entities[self.right_offset];
69                self.right_offset += 1;
70
71                if left_entity_ref.entity_index >= right_entity_ref.entity_index {
72                    continue;
73                }
74
75                return Some(self.store.push(SwapMove::new(
76                    left_entity_ref.entity_index,
77                    right_entity_ref.entity_index,
78                    self.getter,
79                    self.setter,
80                    self.variable_index,
81                    self.variable_name,
82                    self.descriptor_index,
83                )));
84            }
85
86            self.left_offset += 1;
87            self.right_offset = 0;
88        }
89
90        None
91    }
92
93    fn candidate(
94        &self,
95        id: CandidateId,
96    ) -> Option<MoveCandidateRef<'_, S, SwapMove<S, V>>> {
97        self.store.candidate(id)
98    }
99
100    fn take_candidate(&mut self, id: CandidateId) -> SwapMove<S, V> {
101        self.store.take_candidate(id)
102    }
103
104    fn release_candidate(&mut self, id: CandidateId) -> bool {
105        self.store.release_candidate(id)
106    }
107}
108
109impl<S, V> Iterator for SwapMoveCursor<S, V>
110where
111    S: PlanningSolution,
112    V: Clone + PartialEq + Send + Sync + Debug + 'static,
113{
114    type Item = SwapMove<S, V>;
115
116    fn next(&mut self) -> Option<Self::Item> {
117        let id = self.next_candidate()?;
118        Some(self.take_candidate(id))
119    }
120}
121
122impl<S, V, LES: Debug, RES: Debug> Debug for SwapMoveSelector<S, V, LES, RES> {
123    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124        f.debug_struct("SwapMoveSelector")
125            .field("left_entity_selector", &self.left_entity_selector)
126            .field("right_entity_selector", &self.right_entity_selector)
127            .field("descriptor_index", &self.descriptor_index)
128            .field("variable_index", &self.variable_index)
129            .field("variable_name", &self.variable_name)
130            .finish()
131    }
132}
133
134impl<S: PlanningSolution, V, LES, RES> SwapMoveSelector<S, V, LES, RES> {
135    pub fn new(
136        left_entity_selector: LES,
137        right_entity_selector: RES,
138        getter: fn(&S, usize, usize) -> Option<V>,
139        setter: fn(&mut S, usize, usize, Option<V>),
140        descriptor_index: usize,
141        variable_index: usize,
142        variable_name: &'static str,
143    ) -> Self {
144        Self {
145            left_entity_selector,
146            right_entity_selector,
147            getter,
148            setter,
149            descriptor_index,
150            variable_index,
151            variable_name,
152            _phantom: PhantomData,
153        }
154    }
155}
156
157impl<S: PlanningSolution, V>
158    SwapMoveSelector<S, V, FromSolutionEntitySelector, FromSolutionEntitySelector>
159{
160    pub fn simple(
161        getter: fn(&S, usize, usize) -> Option<V>,
162        setter: fn(&mut S, usize, usize, Option<V>),
163        descriptor_index: usize,
164        variable_index: usize,
165        variable_name: &'static str,
166    ) -> Self {
167        Self {
168            left_entity_selector: FromSolutionEntitySelector::new(descriptor_index),
169            right_entity_selector: FromSolutionEntitySelector::new(descriptor_index),
170            getter,
171            setter,
172            descriptor_index,
173            variable_index,
174            variable_name,
175            _phantom: PhantomData,
176        }
177    }
178}
179
180impl<S, V, LES, RES> MoveSelector<S, SwapMove<S, V>> for SwapMoveSelector<S, V, LES, RES>
181where
182    S: PlanningSolution,
183    V: Clone + PartialEq + Send + Sync + Debug + 'static,
184    LES: EntitySelector<S>,
185    RES: EntitySelector<S>,
186{
187    type Cursor<'a>
188        = SwapMoveCursor<S, V>
189    where
190        Self: 'a;
191
192    fn open_cursor<'a, D: Director<S>>(&'a self, score_director: &D) -> Self::Cursor<'a> {
193        self.open_cursor_with_context(score_director, MoveStreamContext::default())
194    }
195
196    fn open_cursor_with_context<'a, D: Director<S>>(
197        &'a self,
198        score_director: &D,
199        context: MoveStreamContext,
200    ) -> Self::Cursor<'a> {
201        let canonical_right: Vec<_> = self.right_entity_selector.iter(score_director).collect();
202        let canonical_left: Vec<_> = self.left_entity_selector.iter(score_director).collect();
203        let salt = ((self.descriptor_index as u64) << 32) ^ self.variable_index as u64;
204        let left_entities = (0..canonical_left.len())
205            .map(|offset| {
206                canonical_left[context.selection_index(
207                    offset,
208                    canonical_left.len(),
209                    0x5A09_0000_0000_0001 ^ salt,
210                )]
211            })
212            .collect();
213        let right_entities = (0..canonical_right.len())
214            .map(|offset| {
215                canonical_right[context.selection_index(
216                    offset,
217                    canonical_right.len(),
218                    0x5A09_0000_0000_0002 ^ salt,
219                )]
220            })
221            .collect();
222        SwapMoveCursor::new(
223            left_entities,
224            right_entities,
225            self.getter,
226            self.setter,
227            self.descriptor_index,
228            self.variable_index,
229            self.variable_name,
230        )
231    }
232
233    fn size<D: Director<S>>(&self, score_director: &D) -> usize {
234        let left_count = self.left_entity_selector.iter(score_director).count();
235        let right_count = self.right_entity_selector.iter(score_director).count();
236        left_count.saturating_mul(right_count.saturating_sub(1)) / 2
237    }
238}