Skip to main content

solverforge_solver/heuristic/selector/move_selector/
change.rs

1/// A change move selector that generates `ChangeMove` instances.
2pub struct ChangeMoveSelector<S, V, ES, VS> {
3    entity_selector: ES,
4    value_selector: VS,
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    allows_unassigned: bool,
11    _phantom: PhantomData<(fn() -> S, fn() -> V)>,
12}
13
14struct ChangeEntityValues<V> {
15    entity_ref: super::entity::EntityReference,
16    values: Vec<V>,
17    current_assigned: bool,
18}
19
20pub struct ChangeMoveCursor<S, V>
21where
22    S: PlanningSolution,
23    V: Clone + PartialEq + Send + Sync + Debug + 'static,
24{
25    store: CandidateStore<S, ChangeMove<S, V>>,
26    entity_values: Vec<ChangeEntityValues<V>>,
27    entity_offset: usize,
28    value_offset: usize,
29    getter: fn(&S, usize, usize) -> Option<V>,
30    setter: fn(&mut S, usize, usize, Option<V>),
31    descriptor_index: usize,
32    variable_index: usize,
33    variable_name: &'static str,
34    allows_unassigned: bool,
35}
36
37impl<S, V> ChangeMoveCursor<S, V>
38where
39    S: PlanningSolution,
40    V: Clone + PartialEq + Send + Sync + Debug + 'static,
41{
42    fn new(
43        entity_values: Vec<ChangeEntityValues<V>>,
44        getter: fn(&S, usize, usize) -> Option<V>,
45        setter: fn(&mut S, usize, usize, Option<V>),
46        descriptor_index: usize,
47        variable_index: usize,
48        variable_name: &'static str,
49        allows_unassigned: bool,
50    ) -> Self {
51        Self {
52            store: CandidateStore::new(),
53            entity_values,
54            entity_offset: 0,
55            value_offset: 0,
56            getter,
57            setter,
58            descriptor_index,
59            variable_index,
60            variable_name,
61            allows_unassigned,
62        }
63    }
64
65    #[inline(always)]
66    fn next_move(&mut self) -> Option<ChangeMove<S, V>> {
67        while self.entity_offset < self.entity_values.len() {
68            let entity_values = &self.entity_values[self.entity_offset];
69            if self.value_offset < entity_values.values.len() {
70                let value = entity_values.values[self.value_offset].clone();
71                self.value_offset += 1;
72                return Some(ChangeMove::new(
73                    entity_values.entity_ref.entity_index,
74                    Some(value),
75                    self.getter,
76                    self.setter,
77                    self.variable_index,
78                    self.variable_name,
79                    self.descriptor_index,
80                ));
81            }
82
83            let to_none_offset = entity_values.values.len();
84            if self.allows_unassigned
85                && entity_values.current_assigned
86                && self.value_offset == to_none_offset
87            {
88                self.value_offset += 1;
89                return Some(ChangeMove::new(
90                    entity_values.entity_ref.entity_index,
91                    None,
92                    self.getter,
93                    self.setter,
94                    self.variable_index,
95                    self.variable_name,
96                    self.descriptor_index,
97                ));
98            }
99
100            self.entity_offset += 1;
101            self.value_offset = 0;
102        }
103        None
104    }
105}
106
107impl<S, V> MoveCursor<S, ChangeMove<S, V>> for ChangeMoveCursor<S, V>
108where
109    S: PlanningSolution,
110    V: Clone + PartialEq + Send + Sync + Debug + 'static,
111{
112    fn next_candidate(&mut self) -> Option<CandidateId> {
113        let mov = self.next_move()?;
114        Some(self.store.push(mov))
115    }
116
117    fn candidate(
118        &self,
119        id: CandidateId,
120    ) -> Option<MoveCandidateRef<'_, S, ChangeMove<S, V>>> {
121        self.store.candidate(id)
122    }
123
124    fn take_candidate(&mut self, id: CandidateId) -> ChangeMove<S, V> {
125        self.store.take_candidate(id)
126    }
127
128    #[inline(always)]
129    fn next_owned_candidate(&mut self) -> Option<ChangeMove<S, V>> {
130        self.next_move()
131    }
132
133    #[inline(always)]
134    fn next_owned_candidate_inspected<T, F>(&mut self, mut inspect: F) -> Option<(ChangeMove<S, V>, T)>
135    where
136        F: for<'a> FnMut(MoveCandidateRef<'a, S, ChangeMove<S, V>>) -> Option<T>,
137    {
138        loop {
139            let mov = self.next_move()?;
140            if let Some(metadata) = inspect(MoveCandidateRef::Borrowed(&mov)) {
141                return Some((mov, metadata));
142            }
143        }
144    }
145
146    fn release_candidate(&mut self, id: CandidateId) -> bool {
147        self.store.release_candidate(id)
148    }
149}
150
151impl<S, V> Iterator for ChangeMoveCursor<S, V>
152where
153    S: PlanningSolution,
154    V: Clone + PartialEq + Send + Sync + Debug + 'static,
155{
156    type Item = ChangeMove<S, V>;
157
158    fn next(&mut self) -> Option<Self::Item> {
159        self.next_move()
160    }
161}
162
163impl<S, V: Debug, ES: Debug, VS: Debug> Debug for ChangeMoveSelector<S, V, ES, VS> {
164    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165        f.debug_struct("ChangeMoveSelector")
166            .field("entity_selector", &self.entity_selector)
167            .field("value_selector", &self.value_selector)
168            .field("descriptor_index", &self.descriptor_index)
169            .field("variable_index", &self.variable_index)
170            .field("variable_name", &self.variable_name)
171            .field("allows_unassigned", &self.allows_unassigned)
172            .finish()
173    }
174}
175
176impl<S: PlanningSolution, V: Clone, ES, VS> ChangeMoveSelector<S, V, ES, VS> {
177    pub fn new(
178        entity_selector: ES,
179        value_selector: VS,
180        getter: fn(&S, usize, usize) -> Option<V>,
181        setter: fn(&mut S, usize, usize, Option<V>),
182        descriptor_index: usize,
183        variable_index: usize,
184        variable_name: &'static str,
185    ) -> Self {
186        Self {
187            entity_selector,
188            value_selector,
189            getter,
190            setter,
191            descriptor_index,
192            variable_index,
193            variable_name,
194            allows_unassigned: false,
195            _phantom: PhantomData,
196        }
197    }
198
199    pub fn with_allows_unassigned(mut self, allows_unassigned: bool) -> Self {
200        self.allows_unassigned = allows_unassigned;
201        self
202    }
203}
204
205impl<S: PlanningSolution, V: Clone + Send + Sync + Debug + 'static>
206    ChangeMoveSelector<S, V, FromSolutionEntitySelector, StaticValueSelector<S, V>>
207{
208    pub fn simple(
209        getter: fn(&S, usize, usize) -> Option<V>,
210        setter: fn(&mut S, usize, usize, Option<V>),
211        descriptor_index: usize,
212        variable_index: usize,
213        variable_name: &'static str,
214        values: Vec<V>,
215    ) -> Self {
216        Self {
217            entity_selector: FromSolutionEntitySelector::new(descriptor_index),
218            value_selector: StaticValueSelector::new(values),
219            getter,
220            setter,
221            descriptor_index,
222            variable_index,
223            variable_name,
224            allows_unassigned: false,
225            _phantom: PhantomData,
226        }
227    }
228}
229
230impl<S, V, ES, VS> MoveSelector<S, ChangeMove<S, V>> for ChangeMoveSelector<S, V, ES, VS>
231where
232    S: PlanningSolution,
233    V: Clone + PartialEq + Send + Sync + Debug + 'static,
234    ES: EntitySelector<S>,
235    VS: ValueSelector<S, V>,
236{
237    type Cursor<'a>
238        = ChangeMoveCursor<S, V>
239    where
240        Self: 'a;
241
242    fn open_cursor<'a, D: Director<S>>(&'a self, score_director: &D) -> Self::Cursor<'a> {
243        self.open_cursor_with_context(score_director, MoveStreamContext::default())
244    }
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        let solution = score_director.working_solution();
252        let canonical_entities = self.entity_selector.iter(score_director).collect::<Vec<_>>();
253        let entity_count = canonical_entities.len();
254        let entity_salt = 0xC4A4_6E00_0000_0001
255            ^ ((self.descriptor_index as u64) << 32)
256            ^ self.variable_index as u64;
257        let entity_values = (0..entity_count)
258            .map(|entity_offset| {
259                let entity_ref = canonical_entities
260                    [context.selection_index(entity_offset, entity_count, entity_salt)];
261                let current_assigned = (self.getter)(
262                    solution,
263                    entity_ref.entity_index,
264                    self.variable_index,
265                )
266                .is_some();
267                let canonical_values = self
268                    .value_selector
269                    .iter(
270                        score_director,
271                        entity_ref.descriptor_index,
272                        entity_ref.entity_index,
273                    )
274                    .collect::<Vec<_>>();
275                let value_count = canonical_values.len();
276                let value_salt = 0xC4A4_6E00_0000_0000
277                    ^ entity_ref.entity_index as u64
278                    ^ ((self.descriptor_index as u64) << 32)
279                    ^ self.variable_index as u64;
280                let values = if context.is_canonical() {
281                    canonical_values
282                } else {
283                    (0..value_count)
284                        .map(|value_offset| {
285                            canonical_values
286                                [context.selection_index(value_offset, value_count, value_salt)]
287                            .clone()
288                        })
289                        .collect()
290                };
291                ChangeEntityValues {
292                    entity_ref,
293                    values,
294                    current_assigned,
295                }
296            })
297            .collect();
298        ChangeMoveCursor::new(
299            entity_values,
300            self.getter,
301            self.setter,
302            self.descriptor_index,
303            self.variable_index,
304            self.variable_name,
305            self.allows_unassigned,
306        )
307    }
308
309    fn size<D: Director<S>>(&self, score_director: &D) -> usize {
310        self.entity_selector
311            .iter(score_director)
312            .map(|entity_ref| {
313                self.value_selector.size(
314                    score_director,
315                    entity_ref.descriptor_index,
316                    entity_ref.entity_index,
317                ) + usize::from(
318                    self.allows_unassigned
319                        && (self.getter)(
320                            score_director.working_solution(),
321                            entity_ref.entity_index,
322                            self.variable_index,
323                        )
324                        .is_some(),
325                )
326            })
327            .sum()
328    }
329}