solverforge_solver/heuristic/selector/selection_order.rs
1/* Selection order configuration for selectors.
2
3Defines the order in which elements are selected from a selector.
4*/
5
6/* Defines the order in which elements are selected from a selector.
7
8This enum controls how entities, values, or moves are ordered when
9iterating through a selector.
10*/
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
12pub enum SelectionOrder {
13 /* Inherit the selection order from the parent configuration.
14
15 If the parent is cached, defaults to `Original`.
16 If there is no parent, defaults to `Random`.
17 */
18 #[default]
19 Inherit,
20
21 /* Select elements in their original order.
22
23 Elements are returned in the order they appear in the underlying
24 collection. This is deterministic and reproducible.
25 */
26 Original,
27
28 /* Select elements in random order without shuffling.
29
30 Elements are selected randomly from the pool on each call to next().
31 The same element may be selected multiple times.
32 This scales well because it does not require caching.
33 */
34 Random,
35
36 /* Select elements in random order by shuffling.
37
38 Elements are shuffled when a selection iterator is created.
39 Each element will be selected exactly once (if all elements are consumed).
40 Requires caching (at least step-level).
41 */
42 Shuffled,
43
44 /* Select elements in sorted order.
45
46 Elements are sorted according to a sorter before iteration.
47 Each element will be selected exactly once (if all elements are consumed).
48 Requires caching (at least step-level).
49 */
50 Sorted,
51
52 /* Select elements based on probability weights.
53
54 Elements with higher probability have a greater chance of being selected.
55 The same element may be selected multiple times.
56 Requires caching (at least step-level).
57 */
58 Probabilistic,
59}
60
61impl SelectionOrder {
62 /// Resolves the selection order by inheriting from a parent if necessary.
63 ///
64 /// # Arguments
65 ///
66 /// * `inherited` - The selection order to inherit from if this is `Inherit`
67 ///
68 /// # Returns
69 ///
70 /// The resolved selection order (never `Inherit`)
71 pub fn resolve(self, inherited: SelectionOrder) -> SelectionOrder {
72 match self {
73 SelectionOrder::Inherit => {
74 if inherited == SelectionOrder::Inherit {
75 SelectionOrder::Random
76 } else {
77 inherited
78 }
79 }
80 other => other,
81 }
82 }
83
84 /// Returns `true` if this selection order implies random selection.
85 ///
86 /// This is used to determine whether a selector should use random iteration
87 /// or deterministic iteration.
88 pub fn is_random(&self) -> bool {
89 matches!(
90 self,
91 SelectionOrder::Random | SelectionOrder::Shuffled | SelectionOrder::Probabilistic
92 )
93 }
94
95 /// Returns `true` if this selection order requires caching.
96 ///
97 /// Some selection orders need to collect all elements before iteration
98 /// can begin (e.g., Shuffled, Sorted, Probabilistic).
99 pub fn requires_caching(&self) -> bool {
100 matches!(
101 self,
102 SelectionOrder::Shuffled | SelectionOrder::Sorted | SelectionOrder::Probabilistic
103 )
104 }
105
106 /// Converts from a boolean random selection flag.
107 ///
108 /// # Arguments
109 ///
110 /// * `random` - `true` for `Random`, `false` for `Original`
111 pub fn from_random_selection(random: bool) -> Self {
112 if random {
113 SelectionOrder::Random
114 } else {
115 SelectionOrder::Original
116 }
117 }
118
119 /// Converts to a boolean random selection flag.
120 ///
121 /// # Panics
122 ///
123 /// Panics if this is not `Random` or `Original`.
124 pub fn to_random_selection(&self) -> bool {
125 match self {
126 SelectionOrder::Random => true,
127 SelectionOrder::Original => false,
128 _ => panic!(
129 "Selection order {:?} cannot be converted to a random selection boolean",
130 self
131 ),
132 }
133 }
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 #[test]
141 fn test_resolve_inherit_from_random() {
142 let order = SelectionOrder::Inherit;
143 assert_eq!(
144 order.resolve(SelectionOrder::Random),
145 SelectionOrder::Random
146 );
147 }
148
149 #[test]
150 fn test_resolve_inherit_from_original() {
151 let order = SelectionOrder::Inherit;
152 assert_eq!(
153 order.resolve(SelectionOrder::Original),
154 SelectionOrder::Original
155 );
156 }
157
158 #[test]
159 fn test_resolve_inherit_from_inherit() {
160 let order = SelectionOrder::Inherit;
161 // When inheriting from Inherit, default to Random
162 assert_eq!(
163 order.resolve(SelectionOrder::Inherit),
164 SelectionOrder::Random
165 );
166 }
167
168 #[test]
169 fn test_resolve_non_inherit() {
170 let order = SelectionOrder::Original;
171 // Non-inherit should not change
172 assert_eq!(
173 order.resolve(SelectionOrder::Random),
174 SelectionOrder::Original
175 );
176 }
177
178 #[test]
179 fn test_is_random() {
180 assert!(SelectionOrder::Random.is_random());
181 assert!(SelectionOrder::Shuffled.is_random());
182 assert!(SelectionOrder::Probabilistic.is_random());
183
184 assert!(!SelectionOrder::Original.is_random());
185 assert!(!SelectionOrder::Sorted.is_random());
186 assert!(!SelectionOrder::Inherit.is_random());
187 }
188
189 #[test]
190 fn test_requires_caching() {
191 assert!(SelectionOrder::Shuffled.requires_caching());
192 assert!(SelectionOrder::Sorted.requires_caching());
193 assert!(SelectionOrder::Probabilistic.requires_caching());
194
195 assert!(!SelectionOrder::Original.requires_caching());
196 assert!(!SelectionOrder::Random.requires_caching());
197 assert!(!SelectionOrder::Inherit.requires_caching());
198 }
199
200 #[test]
201 fn test_from_random_selection() {
202 assert_eq!(
203 SelectionOrder::from_random_selection(true),
204 SelectionOrder::Random
205 );
206 assert_eq!(
207 SelectionOrder::from_random_selection(false),
208 SelectionOrder::Original
209 );
210 }
211
212 #[test]
213 fn test_to_random_selection() {
214 assert!(SelectionOrder::Random.to_random_selection());
215 assert!(!SelectionOrder::Original.to_random_selection());
216 }
217
218 #[test]
219 #[should_panic(expected = "cannot be converted")]
220 fn test_to_random_selection_panics_on_shuffled() {
221 SelectionOrder::Shuffled.to_random_selection();
222 }
223
224 #[test]
225 fn test_default() {
226 assert_eq!(SelectionOrder::default(), SelectionOrder::Inherit);
227 }
228}