use solverforge_core::domain::PlanningSolution;
#[derive(Clone, Debug)]
pub struct ExhaustiveSearchNode<S: PlanningSolution> {
depth: usize,
score: S::Score,
optimistic_bound: Option<S::Score>,
descriptor_index: Option<usize>,
variable_index: Option<usize>,
entity_index: Option<usize>,
candidate_value_index: Option<usize>,
parent_index: Option<usize>,
expanded: bool,
}
impl<S: PlanningSolution> ExhaustiveSearchNode<S> {
pub fn root(score: S::Score) -> Self {
Self {
depth: 0,
score,
optimistic_bound: None,
descriptor_index: None,
variable_index: None,
entity_index: None,
candidate_value_index: None,
parent_index: None,
expanded: false,
}
}
pub fn child(
parent_index: usize,
depth: usize,
score: S::Score,
descriptor_index: usize,
variable_index: usize,
entity_index: usize,
candidate_value_index: usize,
) -> Self {
Self {
depth,
score,
optimistic_bound: None,
descriptor_index: Some(descriptor_index),
variable_index: Some(variable_index),
entity_index: Some(entity_index),
candidate_value_index: Some(candidate_value_index),
parent_index: Some(parent_index),
expanded: false,
}
}
#[inline]
pub fn depth(&self) -> usize {
self.depth
}
#[inline]
pub fn score(&self) -> &S::Score {
&self.score
}
pub fn set_score(&mut self, score: S::Score) {
self.score = score;
}
#[inline]
pub fn optimistic_bound(&self) -> Option<&S::Score> {
self.optimistic_bound.as_ref()
}
pub fn set_optimistic_bound(&mut self, bound: S::Score) {
self.optimistic_bound = Some(bound);
}
#[inline]
pub fn descriptor_index(&self) -> Option<usize> {
self.descriptor_index
}
#[inline]
pub fn variable_index(&self) -> Option<usize> {
self.variable_index
}
#[inline]
pub fn entity_index(&self) -> Option<usize> {
self.entity_index
}
#[inline]
pub fn candidate_value_index(&self) -> Option<usize> {
self.candidate_value_index
}
#[inline]
pub fn parent_index(&self) -> Option<usize> {
self.parent_index
}
#[inline]
pub fn is_expanded(&self) -> bool {
self.expanded
}
pub fn mark_expanded(&mut self) {
self.expanded = true;
}
pub fn is_leaf(&self, total_entities: usize) -> bool {
self.depth >= total_entities
}
pub fn can_prune(&self, best_score: &S::Score) -> bool {
match &self.optimistic_bound {
Some(bound) => bound <= best_score,
None => false,
}
}
pub fn assignment_path<'a>(&'a self, all_nodes: &'a [Self]) -> Vec<&'a Self> {
let mut path = Vec::with_capacity(self.depth);
let mut current = Some(self);
while let Some(node) = current {
if node.parent_index.is_some() {
path.push(node);
}
current = node.parent_index.and_then(|index| all_nodes.get(index));
}
path.reverse();
path
}
}
#[cfg(test)]
#[path = "node_tests.rs"]
mod tests;