solverforge_solver/heuristic/selector/
entity.rs1use std::fmt::Debug;
4
5use solverforge_core::domain::PlanningSolution;
6use solverforge_scoring::ScoreDirector;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub struct EntityReference {
11 pub descriptor_index: usize,
13 pub entity_index: usize,
15}
16
17impl EntityReference {
18 pub fn new(descriptor_index: usize, entity_index: usize) -> Self {
20 Self {
21 descriptor_index,
22 entity_index,
23 }
24 }
25}
26
27pub trait EntitySelector<S: PlanningSolution>: Send + Debug {
35 fn iter<'a, D: ScoreDirector<S>>(
40 &'a self,
41 score_director: &'a D,
42 ) -> Box<dyn Iterator<Item = EntityReference> + 'a>;
43
44 fn size<D: ScoreDirector<S>>(&self, score_director: &D) -> usize;
46
47 fn is_never_ending(&self) -> bool {
49 false
50 }
51}
52
53#[derive(Debug, Clone)]
55pub struct FromSolutionEntitySelector {
56 descriptor_index: usize,
58 skip_pinned: bool,
60}
61
62impl FromSolutionEntitySelector {
63 pub fn new(descriptor_index: usize) -> Self {
65 Self {
66 descriptor_index,
67 skip_pinned: false,
68 }
69 }
70
71 pub fn with_skip_pinned(mut self, skip: bool) -> Self {
73 self.skip_pinned = skip;
74 self
75 }
76}
77
78impl<S: PlanningSolution> EntitySelector<S> for FromSolutionEntitySelector {
79 fn iter<'a, D: ScoreDirector<S>>(
80 &'a self,
81 score_director: &'a D,
82 ) -> Box<dyn Iterator<Item = EntityReference> + 'a> {
83 let count = score_director
84 .entity_count(self.descriptor_index)
85 .unwrap_or(0);
86
87 let desc_idx = self.descriptor_index;
88
89 Box::new((0..count).map(move |i| EntityReference::new(desc_idx, i)))
90 }
91
92 fn size<D: ScoreDirector<S>>(&self, score_director: &D) -> usize {
93 score_director
94 .entity_count(self.descriptor_index)
95 .unwrap_or(0)
96 }
97}
98
99#[derive(Debug, Clone, Default)]
101pub struct AllEntitiesSelector;
102
103impl AllEntitiesSelector {
104 pub fn new() -> Self {
106 Self
107 }
108}
109
110impl<S: PlanningSolution> EntitySelector<S> for AllEntitiesSelector {
111 fn iter<'a, D: ScoreDirector<S>>(
112 &'a self,
113 score_director: &'a D,
114 ) -> Box<dyn Iterator<Item = EntityReference> + 'a> {
115 let desc = score_director.solution_descriptor();
116 let descriptor_count = desc.entity_descriptors.len();
117
118 let mut refs = Vec::new();
119 for desc_idx in 0..descriptor_count {
120 let count = score_director.entity_count(desc_idx).unwrap_or(0);
121 for entity_idx in 0..count {
122 refs.push(EntityReference::new(desc_idx, entity_idx));
123 }
124 }
125
126 Box::new(refs.into_iter())
127 }
128
129 fn size<D: ScoreDirector<S>>(&self, score_director: &D) -> usize {
130 score_director.total_entity_count().unwrap_or(0)
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137 use solverforge_core::domain::{EntityDescriptor, SolutionDescriptor, TypedEntityExtractor};
138 use solverforge_core::score::SimpleScore;
139 use solverforge_scoring::SimpleScoreDirector;
140 use std::any::TypeId;
141
142 #[derive(Clone, Debug)]
143 struct Queen {
144 id: i64,
145 }
146
147 #[derive(Clone, Debug)]
148 struct NQueensSolution {
149 queens: Vec<Queen>,
150 score: Option<SimpleScore>,
151 }
152
153 impl PlanningSolution for NQueensSolution {
154 type Score = SimpleScore;
155
156 fn score(&self) -> Option<Self::Score> {
157 self.score
158 }
159
160 fn set_score(&mut self, score: Option<Self::Score>) {
161 self.score = score;
162 }
163 }
164
165 fn get_queens(s: &NQueensSolution) -> &Vec<Queen> {
166 &s.queens
167 }
168
169 fn get_queens_mut(s: &mut NQueensSolution) -> &mut Vec<Queen> {
170 &mut s.queens
171 }
172
173 fn create_test_director(
174 n: usize,
175 ) -> SimpleScoreDirector<NQueensSolution, impl Fn(&NQueensSolution) -> SimpleScore> {
176 let queens: Vec<_> = (0..n).map(|i| Queen { id: i as i64 }).collect();
177
178 let solution = NQueensSolution {
179 queens,
180 score: None,
181 };
182
183 let extractor = Box::new(TypedEntityExtractor::new(
184 "Queen",
185 "queens",
186 get_queens,
187 get_queens_mut,
188 ));
189 let entity_desc = EntityDescriptor::new("Queen", TypeId::of::<Queen>(), "queens")
190 .with_extractor(extractor);
191
192 let descriptor =
193 SolutionDescriptor::new("NQueensSolution", TypeId::of::<NQueensSolution>())
194 .with_entity(entity_desc);
195
196 SimpleScoreDirector::with_calculator(solution, descriptor, |_| SimpleScore::of(0))
197 }
198
199 #[test]
200 fn test_from_solution_entity_selector() {
201 let director = create_test_director(4);
202
203 let solution = director.working_solution();
205 for (i, queen) in solution.queens.iter().enumerate() {
206 assert_eq!(queen.id, i as i64);
207 }
208
209 let selector = FromSolutionEntitySelector::new(0);
210
211 let refs: Vec<_> = selector.iter(&director).collect();
212 assert_eq!(refs.len(), 4);
213 assert_eq!(refs[0], EntityReference::new(0, 0));
214 assert_eq!(refs[1], EntityReference::new(0, 1));
215 assert_eq!(refs[2], EntityReference::new(0, 2));
216 assert_eq!(refs[3], EntityReference::new(0, 3));
217
218 assert_eq!(selector.size(&director), 4);
219 }
220
221 #[test]
222 fn test_all_entities_selector() {
223 let director = create_test_director(3);
224
225 let selector = AllEntitiesSelector::new();
226
227 let refs: Vec<_> = selector.iter(&director).collect();
228 assert_eq!(refs.len(), 3);
229
230 assert_eq!(selector.size(&director), 3);
231 }
232}