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, D: ScoreDirector<S>>: Send + Debug {
21 fn expand(
25 &self,
26 parent_index: usize,
27 parent: &ExhaustiveSearchNode<S>,
28 score_director: &mut D,
29 ) -> Vec<ExhaustiveSearchNode<S>>;
30
31 fn total_entities(&self, score_director: &D) -> 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, D> ExhaustiveSearchDecider<S, D> for SimpleDecider<S, V, B>
106where
107 S: PlanningSolution,
108 V: Clone + Send + Sync + Debug + 'static,
109 B: ScoreBounder<S, D>,
110 D: ScoreDirector<S>,
111{
112 fn expand(
113 &self,
114 parent_index: usize,
115 parent: &ExhaustiveSearchNode<S>,
116 score_director: &mut D,
117 ) -> Vec<ExhaustiveSearchNode<S>> {
118 let entity_index = parent.depth();
119 let new_depth = parent.depth() + 1;
120
121 let total = self.total_entities(score_director);
123 if entity_index >= total {
124 return Vec::new();
125 }
126
127 let mut children = Vec::with_capacity(self.values.len());
128
129 for (value_index, value) in self.values.iter().enumerate() {
130 score_director.before_variable_changed(
132 self.descriptor_index,
133 entity_index,
134 &self.variable_name,
135 );
136
137 (self.setter)(
138 score_director.working_solution_mut(),
139 entity_index,
140 Some(value.clone()),
141 );
142
143 score_director.after_variable_changed(
144 self.descriptor_index,
145 entity_index,
146 &self.variable_name,
147 );
148
149 let score = score_director.calculate_score();
151
152 let mut child = ExhaustiveSearchNode::child(
154 parent_index,
155 new_depth,
156 score,
157 entity_index,
158 value_index,
159 );
160
161 if let Some(ref bounder) = self.bounder {
163 if let Some(bound) = bounder.calculate_optimistic_bound(score_director) {
164 child.set_optimistic_bound(bound);
165 }
166 }
167
168 children.push(child);
169
170 score_director.before_variable_changed(
172 self.descriptor_index,
173 entity_index,
174 &self.variable_name,
175 );
176
177 (self.setter)(score_director.working_solution_mut(), entity_index, None);
178
179 score_director.after_variable_changed(
180 self.descriptor_index,
181 entity_index,
182 &self.variable_name,
183 );
184 }
185
186 children
187 }
188
189 fn total_entities(&self, score_director: &D) -> usize {
190 score_director
191 .entity_count(self.descriptor_index)
192 .unwrap_or(0)
193 }
194}
195
196impl<S: PlanningSolution, D: ScoreDirector<S>> ScoreBounder<S, D> for () {
198 fn calculate_optimistic_bound(&self, _score_director: &D) -> Option<S::Score> {
199 None
200 }
201}
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206 use solverforge_core::score::SimpleScore;
207
208 #[derive(Clone, Debug)]
209 struct TestSolution {
210 score: Option<SimpleScore>,
211 }
212
213 impl PlanningSolution for TestSolution {
214 type Score = SimpleScore;
215
216 fn score(&self) -> Option<Self::Score> {
217 self.score
218 }
219
220 fn set_score(&mut self, score: Option<Self::Score>) {
221 self.score = score;
222 }
223 }
224
225 fn set_row(_s: &mut TestSolution, _idx: usize, _v: Option<i32>) {
227 }
229
230 #[test]
231 fn test_simple_decider_creation() {
232 let decider: SimpleDecider<TestSolution, i32> =
233 SimpleDecider::new(0, "row", vec![0, 1, 2, 3], set_row);
234
235 let debug = format!("{:?}", decider);
236 assert!(debug.contains("SimpleDecider"));
237 assert!(debug.contains("value_count: 4"));
238 }
239}