solverforge_solver/phase/exhaustive/
node.rs1use std::marker::PhantomData;
7
8use crate::heuristic::Move;
9use solverforge_core::domain::PlanningSolution;
10
11#[derive(Debug, Clone)]
20pub struct ExhaustiveSearchNode<S: PlanningSolution> {
21 depth: usize,
23
24 score: S::Score,
26
27 optimistic_bound: Option<S::Score>,
30
31 entity_index: Option<usize>,
33
34 value_index: Option<usize>,
36
37 parent_index: Option<usize>,
39
40 expanded: bool,
42}
43
44impl<S: PlanningSolution> ExhaustiveSearchNode<S> {
45 pub fn root(score: S::Score) -> Self {
46 Self {
47 depth: 0,
48 score,
49 optimistic_bound: None,
50 entity_index: None,
51 value_index: None,
52 parent_index: None,
53 expanded: false,
54 }
55 }
56
57 pub fn child(
58 parent_index: usize,
59 depth: usize,
60 score: S::Score,
61 entity_index: usize,
62 value_index: usize,
63 ) -> Self {
64 Self {
65 depth,
66 score,
67 optimistic_bound: None,
68 entity_index: Some(entity_index),
69 value_index: Some(value_index),
70 parent_index: Some(parent_index),
71 expanded: false,
72 }
73 }
74
75 #[inline]
76 pub fn depth(&self) -> usize {
77 self.depth
78 }
79
80 #[inline]
81 pub fn score(&self) -> &S::Score {
82 &self.score
83 }
84
85 pub fn set_score(&mut self, score: S::Score) {
86 self.score = score;
87 }
88
89 #[inline]
90 pub fn optimistic_bound(&self) -> Option<&S::Score> {
91 self.optimistic_bound.as_ref()
92 }
93
94 pub fn set_optimistic_bound(&mut self, bound: S::Score) {
95 self.optimistic_bound = Some(bound);
96 }
97
98 #[inline]
99 pub fn entity_index(&self) -> Option<usize> {
100 self.entity_index
101 }
102
103 #[inline]
104 pub fn value_index(&self) -> Option<usize> {
105 self.value_index
106 }
107
108 #[inline]
109 pub fn parent_index(&self) -> Option<usize> {
110 self.parent_index
111 }
112
113 #[inline]
115 pub fn is_expanded(&self) -> bool {
116 self.expanded
117 }
118
119 pub fn mark_expanded(&mut self) {
121 self.expanded = true;
122 }
123
124 pub fn is_leaf(&self, total_entities: usize) -> bool {
125 self.depth >= total_entities
126 }
127
128 pub fn can_prune(&self, best_score: &S::Score) -> bool {
129 match &self.optimistic_bound {
130 Some(bound) => bound <= best_score,
131 None => false,
132 }
133 }
134}
135
136#[derive(Debug, Clone)]
143pub struct MoveSequence<S, M>
144where
145 S: PlanningSolution,
146 M: Move<S>,
147{
148 moves: Vec<M>,
150 _phantom: PhantomData<fn() -> S>,
151}
152
153impl<S, M> MoveSequence<S, M>
154where
155 S: PlanningSolution,
156 M: Move<S>,
157{
158 pub fn new() -> Self {
159 Self {
160 moves: Vec::new(),
161 _phantom: PhantomData,
162 }
163 }
164
165 pub fn with_capacity(capacity: usize) -> Self {
166 Self {
167 moves: Vec::with_capacity(capacity),
168 _phantom: PhantomData,
169 }
170 }
171
172 pub fn push(&mut self, m: M) {
173 self.moves.push(m);
174 }
175
176 pub fn pop(&mut self) -> Option<M> {
178 self.moves.pop()
179 }
180
181 pub fn len(&self) -> usize {
182 self.moves.len()
183 }
184
185 pub fn is_empty(&self) -> bool {
186 self.moves.is_empty()
187 }
188
189 pub fn iter(&self) -> impl Iterator<Item = &M> {
191 self.moves.iter()
192 }
193
194 pub fn clear(&mut self) {
196 self.moves.clear();
197 }
198}
199
200impl<S, M> Default for MoveSequence<S, M>
201where
202 S: PlanningSolution,
203 M: Move<S>,
204{
205 fn default() -> Self {
206 Self::new()
207 }
208}
209
210#[cfg(test)]
211#[path = "node_tests.rs"]
212mod tests;