solverforge_solver/phase/exhaustive/
decider.rs1use std::fmt::Debug;
8
9use solverforge_core::domain::PlanningSolution;
10use solverforge_scoring::Director;
11
12use super::bounder::ScoreBounder;
13use super::node::ExhaustiveSearchNode;
14
15pub trait ExhaustiveSearchDecider<S: PlanningSolution, D: Director<S>>: Send + Debug {
22 fn expand(
27 &self,
28 parent_index: usize,
29 parent: &ExhaustiveSearchNode<S>,
30 score_director: &mut D,
31 ) -> Vec<ExhaustiveSearchNode<S>>;
32
33 fn total_entities(&self, score_director: &D) -> usize;
34}
35
36pub struct SimpleDecider<S: PlanningSolution, V: Clone + Send + Sync + 'static, B = ()> {
45 descriptor_index: usize,
47 variable_name: String,
49 values: Vec<V>,
51 bounder: Option<B>,
53 setter: fn(&mut S, usize, Option<V>),
55}
56
57impl<S: PlanningSolution, V: Clone + Send + Sync + 'static> SimpleDecider<S, V, ()> {
58 pub fn new(
66 descriptor_index: usize,
67 variable_name: impl Into<String>,
68 values: Vec<V>,
69 setter: fn(&mut S, usize, Option<V>),
70 ) -> Self {
71 Self {
72 descriptor_index,
73 variable_name: variable_name.into(),
74 values,
75 bounder: None,
76 setter,
77 }
78 }
79}
80
81impl<S: PlanningSolution, V: Clone + Send + Sync + 'static, B> SimpleDecider<S, V, B> {
82 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: Director<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(self.descriptor_index, entity_index);
132
133 (self.setter)(
134 score_director.working_solution_mut(),
135 entity_index,
136 Some(value.clone()),
137 );
138
139 score_director.after_variable_changed(self.descriptor_index, entity_index);
140
141 let score = score_director.calculate_score();
143
144 let mut child = ExhaustiveSearchNode::child(
146 parent_index,
147 new_depth,
148 score,
149 entity_index,
150 value_index,
151 );
152
153 if let Some(ref bounder) = self.bounder {
155 if let Some(bound) = bounder.calculate_optimistic_bound(score_director) {
156 child.set_optimistic_bound(bound);
157 }
158 }
159
160 children.push(child);
161
162 score_director.before_variable_changed(self.descriptor_index, entity_index);
164
165 (self.setter)(score_director.working_solution_mut(), entity_index, None);
166
167 score_director.after_variable_changed(self.descriptor_index, entity_index);
168 }
169
170 children
171 }
172
173 fn total_entities(&self, score_director: &D) -> usize {
174 score_director
175 .entity_count(self.descriptor_index)
176 .unwrap_or(0)
177 }
178}
179
180impl<S: PlanningSolution, D: Director<S>> ScoreBounder<S, D> for () {
182 fn calculate_optimistic_bound(&self, _score_director: &D) -> Option<S::Score> {
183 None
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190 use solverforge_core::score::SoftScore;
191
192 #[derive(Clone, Debug)]
193 struct TestSolution {
194 score: Option<SoftScore>,
195 }
196
197 impl PlanningSolution for TestSolution {
198 type Score = SoftScore;
199
200 fn score(&self) -> Option<Self::Score> {
201 self.score
202 }
203
204 fn set_score(&mut self, score: Option<Self::Score>) {
205 self.score = score;
206 }
207 }
208
209 fn set_row(_s: &mut TestSolution, _idx: usize, _v: Option<i32>) {
211 }
213
214 #[test]
215 fn test_simple_decider_creation() {
216 let decider: SimpleDecider<TestSolution, i32> =
217 SimpleDecider::new(0, "row", vec![0, 1, 2, 3], set_row);
218
219 let debug = format!("{:?}", decider);
220 assert!(debug.contains("SimpleDecider"));
221 assert!(debug.contains("value_count: 4"));
222 }
223}