solverforge_solver/heuristic/selector/
value_selector.rs1use std::fmt::Debug;
8use std::marker::PhantomData;
9
10use solverforge_core::domain::PlanningSolution;
11use solverforge_scoring::Director;
12
13pub trait ValueSelector<S: PlanningSolution, V>: Send + Debug {
22 fn iter_typed<'a, D: Director<S>>(
24 &'a self,
25 score_director: &'a D,
26 descriptor_index: usize,
27 entity_index: usize,
28 ) -> impl Iterator<Item = V> + 'a;
29
30 fn size<D: Director<S>>(
31 &self,
32 score_director: &D,
33 descriptor_index: usize,
34 entity_index: usize,
35 ) -> usize;
36
37 fn is_never_ending(&self) -> bool {
39 false
40 }
41}
42
43pub struct StaticValueSelector<S, V> {
45 values: Vec<V>,
46 _phantom: PhantomData<fn() -> S>,
47}
48
49impl<S, V: Clone> Clone for StaticValueSelector<S, V> {
50 fn clone(&self) -> Self {
51 Self {
52 values: self.values.clone(),
53 _phantom: PhantomData,
54 }
55 }
56}
57
58impl<S, V: Debug> Debug for StaticValueSelector<S, V> {
59 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60 f.debug_struct("StaticValueSelector")
61 .field("values", &self.values)
62 .finish()
63 }
64}
65
66impl<S, V: Clone> StaticValueSelector<S, V> {
67 pub fn new(values: Vec<V>) -> Self {
68 Self {
69 values,
70 _phantom: PhantomData,
71 }
72 }
73
74 pub fn values(&self) -> &[V] {
75 &self.values
76 }
77}
78
79impl<S, V> ValueSelector<S, V> for StaticValueSelector<S, V>
80where
81 S: PlanningSolution,
82 V: Clone + Send + Debug + 'static,
83{
84 fn iter_typed<'a, D: Director<S>>(
85 &'a self,
86 _score_director: &'a D,
87 _descriptor_index: usize,
88 _entity_index: usize,
89 ) -> impl Iterator<Item = V> + 'a {
90 self.values.iter().cloned()
91 }
92
93 fn size<D: Director<S>>(
94 &self,
95 _score_director: &D,
96 _descriptor_index: usize,
97 _entity_index: usize,
98 ) -> usize {
99 self.values.len()
100 }
101}
102
103pub struct FromSolutionValueSelector<S, V> {
105 extractor: fn(&S) -> Vec<V>,
106 _phantom: PhantomData<(fn() -> S, fn() -> V)>,
107}
108
109impl<S, V> Debug for FromSolutionValueSelector<S, V> {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 f.debug_struct("FromSolutionValueSelector").finish()
112 }
113}
114
115impl<S, V> FromSolutionValueSelector<S, V> {
116 pub fn new(extractor: fn(&S) -> Vec<V>) -> Self {
117 Self {
118 extractor,
119 _phantom: PhantomData,
120 }
121 }
122}
123
124pub struct PerEntityValueSelector<S, V> {
125 extractor: fn(&S, usize) -> Vec<V>,
126 _phantom: PhantomData<(fn() -> S, fn() -> V)>,
127}
128
129impl<S, V> Debug for PerEntityValueSelector<S, V> {
130 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
131 f.debug_struct("PerEntityValueSelector").finish()
132 }
133}
134
135impl<S, V> PerEntityValueSelector<S, V> {
136 pub fn new(extractor: fn(&S, usize) -> Vec<V>) -> Self {
137 Self {
138 extractor,
139 _phantom: PhantomData,
140 }
141 }
142}
143
144impl<S, V> ValueSelector<S, V> for PerEntityValueSelector<S, V>
145where
146 S: PlanningSolution,
147 V: Clone + Send + Debug + 'static,
148{
149 fn iter_typed<'a, D: Director<S>>(
150 &'a self,
151 score_director: &'a D,
152 _descriptor_index: usize,
153 entity_index: usize,
154 ) -> impl Iterator<Item = V> + 'a {
155 (self.extractor)(score_director.working_solution(), entity_index).into_iter()
156 }
157
158 fn size<D: Director<S>>(
159 &self,
160 score_director: &D,
161 _descriptor_index: usize,
162 entity_index: usize,
163 ) -> usize {
164 (self.extractor)(score_director.working_solution(), entity_index).len()
165 }
166}
167
168impl<S, V> ValueSelector<S, V> for FromSolutionValueSelector<S, V>
169where
170 S: PlanningSolution,
171 V: Clone + Send + Debug + 'static,
172{
173 fn iter_typed<'a, D: Director<S>>(
174 &'a self,
175 score_director: &'a D,
176 _descriptor_index: usize,
177 _entity_index: usize,
178 ) -> impl Iterator<Item = V> + 'a {
179 let values = (self.extractor)(score_director.working_solution());
180 values.into_iter()
181 }
182
183 fn size<D: Director<S>>(
184 &self,
185 score_director: &D,
186 _descriptor_index: usize,
187 _entity_index: usize,
188 ) -> usize {
189 (self.extractor)(score_director.working_solution()).len()
190 }
191}
192
193pub struct RangeValueSelector<S> {
197 count_fn: fn(&S) -> usize,
198 _phantom: PhantomData<fn() -> S>,
199}
200
201impl<S> Debug for RangeValueSelector<S> {
202 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
203 f.debug_struct("RangeValueSelector").finish()
204 }
205}
206
207impl<S> RangeValueSelector<S> {
208 pub fn new(count_fn: fn(&S) -> usize) -> Self {
209 Self {
210 count_fn,
211 _phantom: PhantomData,
212 }
213 }
214}
215
216impl<S> ValueSelector<S, usize> for RangeValueSelector<S>
217where
218 S: PlanningSolution,
219{
220 fn iter_typed<'a, D: Director<S>>(
221 &'a self,
222 score_director: &'a D,
223 _descriptor_index: usize,
224 _entity_index: usize,
225 ) -> impl Iterator<Item = usize> + 'a {
226 let count = (self.count_fn)(score_director.working_solution());
227 0..count
228 }
229
230 fn size<D: Director<S>>(
231 &self,
232 score_director: &D,
233 _descriptor_index: usize,
234 _entity_index: usize,
235 ) -> usize {
236 (self.count_fn)(score_director.working_solution())
237 }
238}
239
240#[cfg(test)]
241mod tests {
242 use super::*;
243 use solverforge_core::domain::{
244 EntityCollectionExtractor, EntityDescriptor, SolutionDescriptor,
245 };
246 use solverforge_core::score::SoftScore;
247 use solverforge_scoring::ScoreDirector;
248 use std::any::TypeId;
249
250 #[derive(Clone, Debug)]
251 struct Task {
252 id: usize,
253 priority: Option<i32>,
254 }
255
256 #[derive(Clone, Debug)]
257 struct TaskSolution {
258 tasks: Vec<Task>,
259 score: Option<SoftScore>,
260 }
261
262 impl PlanningSolution for TaskSolution {
263 type Score = SoftScore;
264 fn score(&self) -> Option<Self::Score> {
265 self.score
266 }
267 fn set_score(&mut self, score: Option<Self::Score>) {
268 self.score = score;
269 }
270 }
271
272 fn create_director(tasks: Vec<Task>) -> ScoreDirector<TaskSolution, ()> {
273 let solution = TaskSolution { tasks, score: None };
274 let extractor = Box::new(EntityCollectionExtractor::new(
275 "Task",
276 "tasks",
277 |s: &TaskSolution| &s.tasks,
278 |s: &mut TaskSolution| &mut s.tasks,
279 ));
280 let entity_desc =
281 EntityDescriptor::new("Task", TypeId::of::<Task>(), "tasks").with_extractor(extractor);
282 let descriptor = SolutionDescriptor::new("TaskSolution", TypeId::of::<TaskSolution>())
283 .with_entity(entity_desc);
284 ScoreDirector::simple(solution, descriptor, |s, _| s.tasks.len())
285 }
286
287 #[test]
288 fn test_static_value_selector_selector() {
289 let director = create_director(vec![Task {
290 id: 0,
291 priority: None,
292 }]);
293 let selector = StaticValueSelector::<TaskSolution, i32>::new(vec![1, 2, 3, 4, 5]);
294
295 let values: Vec<_> = selector.iter_typed(&director, 0, 0).collect();
296 assert_eq!(values, vec![1, 2, 3, 4, 5]);
297 assert_eq!(selector.size(&director, 0, 0), 5);
298 }
299
300 #[test]
301 fn test_from_solution_value_selector_selector() {
302 let director = create_director(vec![
303 Task {
304 id: 0,
305 priority: Some(10),
306 },
307 Task {
308 id: 1,
309 priority: Some(20),
310 },
311 ]);
312
313 let solution = director.working_solution();
315 assert_eq!(solution.tasks[0].id, 0);
316 assert_eq!(solution.tasks[1].id, 1);
317
318 fn extract_priorities(s: &TaskSolution) -> Vec<i32> {
320 s.tasks.iter().filter_map(|t| t.priority).collect()
321 }
322
323 let selector = FromSolutionValueSelector::new(extract_priorities);
324
325 let values: Vec<_> = selector.iter_typed(&director, 0, 0).collect();
326 assert_eq!(values, vec![10, 20]);
327 }
328}