solverforge_solver/phase/exhaustive/
decider.rs1use std::fmt::Debug;
7
8use solverforge_core::domain::PlanningSolution;
9use solverforge_scoring::ScoreDirector;
10
11use super::bounder::ScoreBounder;
12use super::node::ExhaustiveSearchNode;
13
14pub trait ExhaustiveSearchDecider<S: PlanningSolution>: Send + Debug {
21 fn expand(
25 &self,
26 parent_index: usize,
27 parent: &ExhaustiveSearchNode<S>,
28 score_director: &mut dyn ScoreDirector<S>,
29 ) -> Vec<ExhaustiveSearchNode<S>>;
30
31 fn total_entities(&self, score_director: &dyn ScoreDirector<S>) -> usize;
33}
34
35pub struct SimpleDecider<S: PlanningSolution, V: Clone + Send + Sync + 'static, B = ()> {
44 descriptor_index: usize,
46 variable_name: String,
48 values: Vec<V>,
50 bounder: Option<B>,
52 setter: fn(&mut S, usize, Option<V>),
54}
55
56impl<S: PlanningSolution, V: Clone + Send + Sync + 'static> SimpleDecider<S, V, ()> {
57 pub fn new(
65 descriptor_index: usize,
66 variable_name: impl Into<String>,
67 values: Vec<V>,
68 setter: fn(&mut S, usize, Option<V>),
69 ) -> Self {
70 Self {
71 descriptor_index,
72 variable_name: variable_name.into(),
73 values,
74 bounder: None,
75 setter,
76 }
77 }
78}
79
80impl<S: PlanningSolution, V: Clone + Send + Sync + 'static, B> SimpleDecider<S, V, B> {
81 pub fn with_bounder<B2>(self, bounder: B2) -> SimpleDecider<S, V, B2> {
83 SimpleDecider {
84 descriptor_index: self.descriptor_index,
85 variable_name: self.variable_name,
86 values: self.values,
87 bounder: Some(bounder),
88 setter: self.setter,
89 }
90 }
91}
92
93impl<S: PlanningSolution, V: Clone + Send + Sync + Debug + 'static, B: Debug> Debug
94 for SimpleDecider<S, V, B>
95{
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 f.debug_struct("SimpleDecider")
98 .field("descriptor_index", &self.descriptor_index)
99 .field("variable_name", &self.variable_name)
100 .field("value_count", &self.values.len())
101 .finish()
102 }
103}
104
105impl<S, V, B> ExhaustiveSearchDecider<S> for SimpleDecider<S, V, B>
106where
107 S: PlanningSolution,
108 V: Clone + Send + Sync + Debug + 'static,
109 B: ScoreBounder<S>,
110{
111 fn expand(
112 &self,
113 parent_index: usize,
114 parent: &ExhaustiveSearchNode<S>,
115 score_director: &mut dyn ScoreDirector<S>,
116 ) -> Vec<ExhaustiveSearchNode<S>> {
117 let entity_index = parent.depth();
118 let new_depth = parent.depth() + 1;
119
120 let total = self.total_entities(score_director);
122 if entity_index >= total {
123 return Vec::new();
124 }
125
126 let mut children = Vec::with_capacity(self.values.len());
127
128 for (value_index, value) in self.values.iter().enumerate() {
129 score_director.before_variable_changed(
131 self.descriptor_index,
132 entity_index,
133 &self.variable_name,
134 );
135
136 (self.setter)(
137 score_director.working_solution_mut(),
138 entity_index,
139 Some(value.clone()),
140 );
141
142 score_director.after_variable_changed(
143 self.descriptor_index,
144 entity_index,
145 &self.variable_name,
146 );
147
148 let score = score_director.calculate_score();
150
151 let mut child = ExhaustiveSearchNode::child(
153 parent_index,
154 new_depth,
155 score,
156 entity_index,
157 value_index,
158 );
159
160 if let Some(ref bounder) = self.bounder {
162 if let Some(bound) = bounder.calculate_optimistic_bound(score_director) {
163 child.set_optimistic_bound(bound);
164 }
165 }
166
167 children.push(child);
168
169 score_director.before_variable_changed(
171 self.descriptor_index,
172 entity_index,
173 &self.variable_name,
174 );
175
176 (self.setter)(score_director.working_solution_mut(), entity_index, None);
177
178 score_director.after_variable_changed(
179 self.descriptor_index,
180 entity_index,
181 &self.variable_name,
182 );
183 }
184
185 children
186 }
187
188 fn total_entities(&self, score_director: &dyn ScoreDirector<S>) -> usize {
189 score_director
190 .entity_count(self.descriptor_index)
191 .unwrap_or(0)
192 }
193}
194
195impl<S: PlanningSolution> ScoreBounder<S> for () {
197 fn calculate_optimistic_bound(
198 &self,
199 _score_director: &dyn ScoreDirector<S>,
200 ) -> Option<S::Score> {
201 None
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 use super::*;
208 use solverforge_core::score::SimpleScore;
209
210 #[derive(Clone, Debug)]
211 struct TestSolution {
212 score: Option<SimpleScore>,
213 }
214
215 impl PlanningSolution for TestSolution {
216 type Score = SimpleScore;
217
218 fn score(&self) -> Option<Self::Score> {
219 self.score
220 }
221
222 fn set_score(&mut self, score: Option<Self::Score>) {
223 self.score = score;
224 }
225 }
226
227 fn set_row(_s: &mut TestSolution, _idx: usize, _v: Option<i32>) {
229 }
231
232 #[test]
233 fn test_simple_decider_creation() {
234 let decider: SimpleDecider<TestSolution, i32> =
235 SimpleDecider::new(0, "row", vec![0, 1, 2, 3], set_row);
236
237 let debug = format!("{:?}", decider);
238 assert!(debug.contains("SimpleDecider"));
239 assert!(debug.contains("value_count: 4"));
240 }
241}