use super::TreeStorage;
use super::{EdgeTraversal, SearchTreeNode};
use crate::model::network::{EdgeId, EdgeListId, Graph, NetworkError, VertexId};
use crate::model::unit::Cost;
use crate::{algorithm::search::Direction, model::label::Label};
use allocative::Allocative;
use std::collections::HashSet;
use std::sync::Arc;
#[derive(Clone, Debug, Allocative)]
pub struct SearchTree {
storage: TreeStorage,
root: Option<Label>,
direction: Direction,
}
impl Default for SearchTree {
fn default() -> Self {
Self::new_stateful(Direction::Forward)
}
}
impl SearchTree {
pub fn new_stateful(direction: Direction) -> Self {
Self {
storage: TreeStorage::new_stateful(),
root: None,
direction,
}
}
pub fn new_vertex_oriented(direction: Direction) -> Self {
Self {
storage: TreeStorage::new_vertex_oriented(),
root: None,
direction,
}
}
pub fn with_root(root_label: Label, orientation: Direction) -> Result<Self, SearchTreeError> {
let mut tree = match root_label {
Label::Vertex(_) => Self::new_vertex_oriented(orientation),
_ => Self::new_stateful(orientation),
};
tree.set_root(root_label)?;
Ok(tree)
}
pub fn set_root(&mut self, root_label: Label) -> Result<(), SearchTreeError> {
if self.is_empty() {
self.storage = match root_label {
Label::Vertex(_) => TreeStorage::new_vertex_oriented(),
_ => TreeStorage::new_stateful(),
};
}
let root_node = SearchTreeNode::new_root(self.direction);
self.storage.insert_node(root_label.clone(), root_node)?;
self.root = Some(root_label);
Ok(())
}
pub fn insert_trajectory(
&mut self,
parent_label: Label,
edge_traversal: EdgeTraversal,
child_label: Label,
) -> Result<(), SearchTreeError> {
if !self.storage.contains_key(&parent_label) {
if self.is_empty() {
self.set_root(parent_label.clone())?;
} else {
return Err(SearchTreeError::ParentNotFound(parent_label));
}
}
let new_node =
SearchTreeNode::new_child(edge_traversal, parent_label.clone(), self.direction);
self.storage.insert_node(child_label, new_node)?;
Ok(())
}
pub fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (Label, &'a SearchTreeNode)> + 'a> {
Box::new(self.storage.branch_iter())
}
pub fn keys<'a>(&'a self) -> Box<dyn Iterator<Item = Label> + 'a> {
Box::new(self.storage.label_iter())
}
pub fn values<'a>(&'a self) -> Box<dyn Iterator<Item = &'a SearchTreeNode> + 'a> {
Box::new(self.storage.node_iter())
}
pub fn get(&self, label: &Label) -> Option<&SearchTreeNode> {
self.storage.get(label)
}
pub fn get_min_accumulated_cost_label(
&self,
destination_vertex: VertexId,
) -> Result<(Label, Cost), SearchTreeError> {
let labels: Vec<Label> = self.get_labels(destination_vertex).collect();
if labels.is_empty() {
return Err(SearchTreeError::VertexNotFound(destination_vertex));
}
let mut min_cost: Option<(Label, Cost)> = None;
for label in labels.iter() {
let cost = self.calculate_total_objective_cost(label)?;
let improves_cost = min_cost.as_ref().map(|(_, c)| cost < *c).unwrap_or(true);
if improves_cost {
min_cost = Some((label.clone(), cost));
}
}
min_cost.ok_or(SearchTreeError::MissingLabelsForDestinationVertex(
destination_vertex,
))
}
pub fn get_labels(&self, vertex: VertexId) -> Box<dyn Iterator<Item = Label> + '_> {
self.storage.get_labels(vertex)
}
pub fn calculate_total_objective_cost(&self, label: &Label) -> Result<Cost, SearchTreeError> {
let mut total = Cost::ZERO;
let mut current_label = label;
let mut steps: usize = 0;
let max_steps = self.storage.len();
loop {
if steps > max_steps {
return Err(SearchTreeError::InvalidBranchStructure(format!(
"Cycle detected: exceeded tree size {} while calculating cost from {}",
max_steps, label
)));
}
let node = self
.get(current_label)
.ok_or_else(|| SearchTreeError::LabelNotFound(current_label.clone()))?;
match node {
SearchTreeNode::Root { .. } => break,
SearchTreeNode::Branch {
incoming_edge,
parent,
..
} => {
total += incoming_edge.cost.objective_cost;
current_label = parent;
}
}
steps += 1;
}
Ok(total)
}
pub fn get_mut(&mut self, label: &Label) -> Option<&mut SearchTreeNode> {
self.storage.get_mut(label)
}
pub fn root(&self) -> Option<&Label> {
self.root.as_ref()
}
pub fn get_parent(&self, label: &Label) -> Option<&SearchTreeNode> {
let node = self.get(label)?;
let parent_label = node.parent_label()?;
self.get(parent_label)
}
pub fn contains(&self, label: &Label) -> bool {
self.storage.contains_key(label)
}
pub fn len(&self) -> usize {
self.storage.len()
}
pub fn is_empty(&self) -> bool {
self.storage.is_empty()
}
pub fn direction(&self) -> Direction {
self.direction
}
pub fn backtrack_with_depth(
&self,
leaf_vertex: VertexId,
depth: u64,
) -> Result<Vec<EdgeTraversal>, SearchTreeError> {
let (target_label, _) = self.get_min_accumulated_cost_label(leaf_vertex)?;
self.reconstruct_path(&target_label, Some(depth))
}
pub fn backtrack(&self, leaf_vertex: VertexId) -> Result<Vec<EdgeTraversal>, SearchTreeError> {
let (target_label, _) = self.get_min_accumulated_cost_label(leaf_vertex)?;
self.reconstruct_path(&target_label, None)
}
pub fn backtrack_label(&self, label: &Label) -> Result<Vec<EdgeTraversal>, SearchTreeError> {
self.reconstruct_path(label, None)
}
pub fn backtrack_label_with_depth(
&self,
label: &Label,
depth: u64,
) -> Result<Vec<EdgeTraversal>, SearchTreeError> {
self.reconstruct_path(label, Some(depth))
}
pub fn backtrack_edge_oriented_route(
&self,
target: (EdgeListId, EdgeId),
graph: Arc<Graph>,
) -> Result<Vec<EdgeTraversal>, SearchTreeError> {
let (d_el, d_e) = target;
let d_v = graph.src_vertex_id(&d_el, &d_e)?;
self.backtrack(d_v)
}
pub fn reconstruct_path(
&self,
target_label: &Label,
depth: Option<u64>,
) -> Result<Vec<EdgeTraversal>, SearchTreeError> {
let mut path = Vec::new();
let mut current_label = target_label;
let mut steps: u64 = 0;
let mut visited = HashSet::new();
loop {
if !visited.insert(current_label.clone()) {
return Err(SearchTreeError::InvalidBranchStructure(format!(
"Cycle detected at label: {}",
current_label
)));
}
if steps > self.storage.len() as u64 {
return Err(SearchTreeError::InvalidBranchStructure(format!(
"Exceeded tree size {} while backtracking from {}",
self.storage.len(),
target_label
)));
}
let exceeds_depth = depth.map(|l| steps >= l).unwrap_or_default();
if exceeds_depth {
break;
}
let predecessor = self.predecessor(current_label)?;
match predecessor {
Some((incoming_edge, parent)) => {
path.push(incoming_edge.clone());
current_label = parent;
}
None => break,
}
steps += 1;
}
match self.direction {
Direction::Forward => {
path.reverse();
Ok(path)
}
Direction::Reverse => Ok(path),
}
}
pub fn predecessor(
&self,
child: &Label,
) -> Result<Option<(&EdgeTraversal, &Label)>, SearchTreeError> {
let current_node = self
.get(child)
.ok_or_else(|| SearchTreeError::LabelNotFound(child.clone()))?;
match current_node {
SearchTreeNode::Root { .. } => Ok(None),
SearchTreeNode::Branch {
incoming_edge,
parent,
..
} => Ok(Some((incoming_edge, parent))),
}
}
pub fn labels(&self) -> impl Iterator<Item = Label> + '_ {
self.storage.label_iter()
}
pub fn nodes(&self) -> impl Iterator<Item = &SearchTreeNode> {
self.storage.node_iter()
}
}
#[derive(Debug, thiserror::Error)]
pub enum SearchTreeError {
#[error("parent not found for label {0}")]
ParentNotFound(Label),
#[error("Label not found in tree: {0}")]
LabelNotFound(Label),
#[error("Label '{0}' exists in tree without matching SearchTreeNode")]
MissingNodeForLabel(Label),
#[error("Destination vertex '{0}' has no labels at end of search")]
MissingLabelsForDestinationVertex(VertexId),
#[error("Node is missing parent reference: {0}")]
MissingParent(Label),
#[error("Invalid branch structure: {0}")]
InvalidBranchStructure(String),
#[error("Vertex not found in tree: {0}")]
VertexNotFound(VertexId),
#[error("while backtracking from '{0}', {1}")]
BacktrackingError(Label, String),
#[error("Search tree error while interacting with Graph: {source}")]
NetworkError {
#[from]
source: NetworkError,
},
#[error("LabelModel must produce a consistent Label type, but produced {1} after initially producing {0}")]
HeterogeneousLabelTypes(String, String),
}
#[cfg(test)]
mod tests {
use std::collections::HashSet;
use super::*;
use crate::model::{
cost::TraversalCost,
network::{EdgeId, EdgeListId, VertexId},
unit::Cost,
};
#[test]
fn test_new_empty_tree() {
let tree = SearchTree::new_stateful(Direction::Forward);
assert!(tree.is_empty());
assert_eq!(tree.len(), 0);
assert_eq!(tree.direction(), Direction::Forward);
assert!(tree.root().is_none());
}
#[test]
fn test_tree_with_root() {
let root_label = create_test_label(0);
let tree = SearchTree::with_root(root_label.clone(), Direction::Forward).unwrap();
assert!(!tree.is_empty());
assert_eq!(tree.len(), 1);
assert_eq!(tree.root(), Some(&root_label));
assert!(tree.contains(&root_label));
let root_node = tree.get(&root_label).unwrap();
assert!(root_node.is_root());
}
#[test]
fn test_insert_child_nodes() {
let root_label = create_test_label(0);
let mut tree = SearchTree::with_root(root_label.clone(), Direction::Forward).unwrap();
let child1_label = create_test_label(1);
let child1_traversal = create_test_edge_traversal(1, 10.0);
tree.insert_trajectory(
root_label.clone(),
child1_traversal.clone(),
child1_label.clone(),
)
.unwrap();
let child2_label = create_test_label(2);
let child2_traversal = create_test_edge_traversal(2, 15.0);
tree.insert_trajectory(
root_label.clone(),
child2_traversal.clone(),
child2_label.clone(),
)
.unwrap();
assert_eq!(tree.len(), 3);
let child1_node = tree.get(&child1_label).unwrap();
assert!(!child1_node.is_root());
assert_eq!(child1_node.parent_label(), Some(&root_label));
assert_eq!(child1_node.incoming_edge().unwrap().edge_id, EdgeId(1));
let child2_node = tree.get(&child2_label).unwrap();
assert!(!child2_node.is_root());
assert_eq!(child2_node.parent_label(), Some(&root_label));
assert_eq!(child2_node.incoming_edge().unwrap().edge_id, EdgeId(2));
}
#[test]
fn test_insert_with_nonexistent_parent() {
let root_label = create_test_label(0);
let mut tree = SearchTree::with_root(root_label, Direction::Forward).unwrap();
let child_label = create_test_label(1);
let child_traversal = create_test_edge_traversal(1, 10.0);
let nonexistent_parent = create_test_label(99);
let result =
tree.insert_trajectory(nonexistent_parent.clone(), child_traversal, child_label);
assert!(matches!(result, Err(SearchTreeError::ParentNotFound(_))));
}
#[test]
fn test_get_parent() {
let root_label = create_test_label(0);
let mut tree = SearchTree::with_root(root_label.clone(), Direction::Forward).unwrap();
let child_label = create_test_label(1);
let child_traversal = create_test_edge_traversal(1, 10.0);
tree.insert_trajectory(root_label.clone(), child_traversal, child_label.clone())
.unwrap();
assert!(tree.get_parent(&root_label).is_none());
let parent = tree.get(&child_label).unwrap().parent_label().unwrap();
assert_eq!(parent, &root_label);
}
#[test]
fn test_reconstruct_path_forward_orientation() {
let root_label = create_test_label(0);
let mut tree = SearchTree::with_root(root_label.clone(), Direction::Forward).unwrap();
let child1_label = create_test_label(1);
let child1_traversal = create_test_edge_traversal(1, 10.0);
tree.insert_trajectory(
root_label.clone(),
child1_traversal.clone(),
child1_label.clone(),
)
.unwrap();
let child2_label = create_test_label(2);
let child2_traversal = create_test_edge_traversal(2, 15.0);
tree.insert_trajectory(
child1_label.clone(),
child2_traversal.clone(),
child2_label.clone(),
)
.unwrap();
let child3_label = create_test_label(3);
let child3_traversal = create_test_edge_traversal(3, 20.0);
tree.insert_trajectory(
child2_label.clone(),
child3_traversal.clone(),
child3_label.clone(),
)
.unwrap();
let path = tree.reconstruct_path(&child3_label, None).unwrap();
assert_eq!(path.len(), 3);
assert_eq!(path[0].edge_id, EdgeId(1)); assert_eq!(path[1].edge_id, EdgeId(2)); assert_eq!(path[2].edge_id, EdgeId(3)); }
#[test]
fn test_reconstruct_path_reverse_orientation() {
let root_label = create_test_label(0);
let mut tree = SearchTree::with_root(root_label.clone(), Direction::Reverse).unwrap();
let child1_label = create_test_label(1);
let child1_traversal = create_test_edge_traversal(1, 10.0);
tree.insert_trajectory(
root_label.clone(),
child1_traversal.clone(),
child1_label.clone(),
)
.unwrap();
let child2_label = create_test_label(2);
let child2_traversal = create_test_edge_traversal(2, 15.0);
tree.insert_trajectory(
child1_label.clone(),
child2_traversal.clone(),
child2_label.clone(),
)
.unwrap();
let child3_label = create_test_label(3);
let child3_traversal = create_test_edge_traversal(3, 20.0);
tree.insert_trajectory(
child2_label.clone(),
child3_traversal.clone(),
child3_label.clone(),
)
.unwrap();
let path = tree.reconstruct_path(&child3_label, None).unwrap();
assert_eq!(path.len(), 3);
assert_eq!(path[0].edge_id, EdgeId(3)); assert_eq!(path[1].edge_id, EdgeId(2)); assert_eq!(path[2].edge_id, EdgeId(1)); }
#[test]
fn test_reconstruct_path_nonexistent_label() {
let root_label = create_test_label(0);
let tree = SearchTree::with_root(root_label, Direction::Forward).unwrap();
let nonexistent_label = create_test_label(99);
let result = tree.reconstruct_path(&nonexistent_label, None);
assert!(matches!(result, Err(SearchTreeError::LabelNotFound(_))));
}
#[test]
fn test_iterators() {
let root_label = create_test_label(0);
let mut tree = SearchTree::with_root(root_label.clone(), Direction::Forward).unwrap();
let child1_label = create_test_label(1);
let child1_traversal = create_test_edge_traversal(1, 10.0);
tree.insert_trajectory(root_label.clone(), child1_traversal, child1_label.clone())
.unwrap();
let child2_label = create_test_label(2);
let child2_traversal = create_test_edge_traversal(2, 15.0);
tree.insert_trajectory(root_label.clone(), child2_traversal, child2_label.clone())
.unwrap();
let labels: HashSet<_> = tree.labels().collect();
assert_eq!(labels.len(), 3);
assert!(labels.contains(&root_label));
assert!(labels.contains(&child1_label));
assert!(labels.contains(&child2_label));
let node_count = tree.nodes().count();
assert_eq!(node_count, 3);
let vertex_ids: HashSet<_> = tree.labels().map(|l| l.vertex_id().clone()).collect();
assert_eq!(vertex_ids.len(), 3);
assert!(vertex_ids.contains(&VertexId(0)));
assert!(vertex_ids.contains(&VertexId(1)));
assert!(vertex_ids.contains(&VertexId(2)));
}
#[test]
fn test_backtrack_forward_tree() {
let root_label = create_test_label(0);
let mut tree = SearchTree::with_root(root_label.clone(), Direction::Forward).unwrap();
let child1_label = create_test_label(1);
let child1_traversal = create_test_edge_traversal(1, 10.0);
tree.insert_trajectory(
root_label.clone(),
child1_traversal.clone(),
child1_label.clone(),
)
.unwrap();
let child2_label = create_test_label(2);
let child2_traversal = create_test_edge_traversal(2, 15.0);
tree.insert_trajectory(
child1_label.clone(),
child2_traversal.clone(),
child2_label.clone(),
)
.unwrap();
let child3_label = create_test_label(3);
let child3_traversal = create_test_edge_traversal(3, 20.0);
tree.insert_trajectory(
child2_label.clone(),
child3_traversal.clone(),
child3_label.clone(),
)
.unwrap();
let path = tree.backtrack(VertexId(3)).unwrap();
assert_eq!(path.len(), 3);
assert_eq!(path[0].edge_id, EdgeId(1)); assert_eq!(path[1].edge_id, EdgeId(2)); assert_eq!(path[2].edge_id, EdgeId(3)); }
#[test]
fn test_backtrack_reverse_tree() {
let root_label = create_test_label(0);
let mut tree = SearchTree::with_root(root_label.clone(), Direction::Reverse).unwrap();
let child1_label = create_test_label(1);
let child1_traversal = create_test_edge_traversal(1, 10.0);
tree.insert_trajectory(
root_label.clone(),
child1_traversal.clone(),
child1_label.clone(),
)
.unwrap();
let child2_label = create_test_label(2);
let child2_traversal = create_test_edge_traversal(2, 15.0);
tree.insert_trajectory(
child1_label.clone(),
child2_traversal.clone(),
child2_label.clone(),
)
.unwrap();
let child3_label = create_test_label(3);
let child3_traversal = create_test_edge_traversal(3, 20.0);
tree.insert_trajectory(
child2_label.clone(),
child3_traversal.clone(),
child3_label.clone(),
)
.unwrap();
let path = tree.backtrack(VertexId(3)).unwrap();
assert_eq!(path.len(), 3);
assert_eq!(path[0].edge_id, EdgeId(3)); assert_eq!(path[1].edge_id, EdgeId(2)); assert_eq!(path[2].edge_id, EdgeId(1)); }
#[test]
fn test_backtrack_nonexistent_vertex() {
let root_label = create_test_label(0);
let tree = SearchTree::with_root(root_label, Direction::Forward).unwrap();
let result = tree.backtrack(VertexId(99));
assert!(matches!(
result,
Err(SearchTreeError::VertexNotFound(VertexId(99)))
));
}
#[test]
fn test_backtrack_root_vertex() {
let root_label = create_test_label(0);
let tree = SearchTree::with_root(root_label.clone(), Direction::Forward).unwrap();
let path = tree.backtrack(VertexId(0)).unwrap();
assert_eq!(path.len(), 0);
}
#[test]
fn test_auto_root_creation() {
let mut tree = SearchTree::new_stateful(Direction::Forward);
assert!(tree.is_empty());
assert!(tree.root().is_none());
let parent_label = create_test_label(0);
let child_label = create_test_label(1);
let edge_traversal = create_test_edge_traversal(1, 10.0);
tree.insert_trajectory(
parent_label.clone(),
edge_traversal.clone(),
child_label.clone(),
)
.unwrap();
assert!(!tree.is_empty());
assert_eq!(tree.len(), 2); assert_eq!(tree.root(), Some(&parent_label));
let root_node = tree.get(&parent_label).unwrap();
assert!(root_node.is_root());
assert!(tree.storage.contains_key(&parent_label));
let child_node = tree.get(&child_label).unwrap();
assert!(!child_node.is_root());
assert_eq!(child_node.parent_label(), Some(&parent_label));
assert_eq!(child_node.incoming_edge().unwrap().edge_id, EdgeId(1));
}
#[test]
fn test_auto_root_creation_chain() {
let mut tree = SearchTree::new_stateful(Direction::Forward);
let label0 = create_test_label(0);
let label1 = create_test_label(1);
let label2 = create_test_label(2);
let label3 = create_test_label(3);
tree.insert_trajectory(
label0.clone(),
create_test_edge_traversal(1, 10.0),
label1.clone(),
)
.unwrap();
tree.insert_trajectory(
label1.clone(),
create_test_edge_traversal(2, 15.0),
label2.clone(),
)
.unwrap();
tree.insert_trajectory(
label2.clone(),
create_test_edge_traversal(3, 20.0),
label3.clone(),
)
.unwrap();
assert_eq!(tree.len(), 4);
assert_eq!(tree.root(), Some(&label0));
let path = tree.backtrack(VertexId(3)).unwrap();
assert_eq!(path.len(), 3);
assert_eq!(path[0].edge_id, EdgeId(1)); assert_eq!(path[1].edge_id, EdgeId(2)); assert_eq!(path[2].edge_id, EdgeId(3)); }
#[test]
fn test_insert_without_auto_root_when_parent_exists() {
let mut tree = SearchTree::new_stateful(Direction::Forward);
let root_label = create_test_label(0);
tree.set_root(root_label.clone()).unwrap();
let child_label = create_test_label(1);
let edge_traversal = create_test_edge_traversal(1, 10.0);
tree.insert_trajectory(root_label.clone(), edge_traversal, child_label.clone())
.unwrap();
assert_eq!(tree.len(), 2);
assert_eq!(tree.root(), Some(&root_label));
let orphan_label = create_test_label(99);
let nonexistent_parent = create_test_label(999);
let result = tree.insert_trajectory(
orphan_label,
create_test_edge_traversal(99, 5.0),
nonexistent_parent.clone(),
);
assert!(matches!(result, Err(SearchTreeError::ParentNotFound(_))));
}
#[test]
fn test_backtrack_with_depth_forward_tree_full_path() {
let root_label = create_test_label(0);
let mut tree = SearchTree::with_root(root_label.clone(), Direction::Forward).unwrap();
let child1_label = create_test_label(1);
let child1_traversal = create_test_edge_traversal(1, 10.0);
tree.insert_trajectory(root_label.clone(), child1_traversal, child1_label.clone())
.unwrap();
let child2_label = create_test_label(2);
let child2_traversal = create_test_edge_traversal(2, 15.0);
tree.insert_trajectory(child1_label.clone(), child2_traversal, child2_label.clone())
.unwrap();
let child3_label = create_test_label(3);
let child3_traversal = create_test_edge_traversal(3, 20.0);
tree.insert_trajectory(child2_label.clone(), child3_traversal, child3_label.clone())
.unwrap();
let child4_label = create_test_label(4);
let child4_traversal = create_test_edge_traversal(4, 25.0);
tree.insert_trajectory(child3_label.clone(), child4_traversal, child4_label.clone())
.unwrap();
let path = tree.backtrack_with_depth(VertexId(4), 4).unwrap();
assert_eq!(path.len(), 4);
assert_eq!(path[0].edge_id, EdgeId(1)); assert_eq!(path[1].edge_id, EdgeId(2)); assert_eq!(path[2].edge_id, EdgeId(3)); assert_eq!(path[3].edge_id, EdgeId(4)); }
#[test]
fn test_backtrack_with_depth_forward_tree_limited_depth() {
let root_label = create_test_label(0);
let mut tree = SearchTree::with_root(root_label.clone(), Direction::Forward).unwrap();
let child1_label = create_test_label(1);
let child1_traversal = create_test_edge_traversal(1, 10.0);
tree.insert_trajectory(root_label.clone(), child1_traversal, child1_label.clone())
.unwrap();
let child2_label = create_test_label(2);
let child2_traversal = create_test_edge_traversal(2, 15.0);
tree.insert_trajectory(child1_label.clone(), child2_traversal, child2_label.clone())
.unwrap();
let child3_label = create_test_label(3);
let child3_traversal = create_test_edge_traversal(3, 20.0);
tree.insert_trajectory(child2_label.clone(), child3_traversal, child3_label.clone())
.unwrap();
let child4_label = create_test_label(4);
let child4_traversal = create_test_edge_traversal(4, 25.0);
tree.insert_trajectory(child3_label.clone(), child4_traversal, child4_label.clone())
.unwrap();
let path = tree.backtrack_with_depth(VertexId(4), 2).unwrap();
assert_eq!(path.len(), 2);
assert_eq!(path[0].edge_id, EdgeId(3)); assert_eq!(path[1].edge_id, EdgeId(4)); }
#[test]
fn test_backtrack_with_depth_forward_tree_depth_one() {
let root_label = create_test_label(0);
let mut tree = SearchTree::with_root(root_label.clone(), Direction::Forward).unwrap();
let child1_label = create_test_label(1);
let child1_traversal = create_test_edge_traversal(1, 10.0);
tree.insert_trajectory(root_label.clone(), child1_traversal, child1_label.clone())
.unwrap();
let child2_label = create_test_label(2);
let child2_traversal = create_test_edge_traversal(2, 15.0);
tree.insert_trajectory(child1_label.clone(), child2_traversal, child2_label.clone())
.unwrap();
let child3_label = create_test_label(3);
let child3_traversal = create_test_edge_traversal(3, 20.0);
tree.insert_trajectory(child2_label.clone(), child3_traversal, child3_label.clone())
.unwrap();
let path = tree.backtrack_with_depth(VertexId(3), 1).unwrap();
assert_eq!(path.len(), 1);
assert_eq!(path[0].edge_id, EdgeId(3)); }
#[test]
fn test_backtrack_with_depth_reverse_tree_full_path() {
let root_label = create_test_label(0);
let mut tree = SearchTree::with_root(root_label.clone(), Direction::Reverse).unwrap();
let child1_label = create_test_label(1);
let child1_traversal = create_test_edge_traversal(1, 10.0);
tree.insert_trajectory(root_label.clone(), child1_traversal, child1_label.clone())
.unwrap();
let child2_label = create_test_label(2);
let child2_traversal = create_test_edge_traversal(2, 15.0);
tree.insert_trajectory(child1_label.clone(), child2_traversal, child2_label.clone())
.unwrap();
let child3_label = create_test_label(3);
let child3_traversal = create_test_edge_traversal(3, 20.0);
tree.insert_trajectory(child2_label.clone(), child3_traversal, child3_label.clone())
.unwrap();
let child4_label = create_test_label(4);
let child4_traversal = create_test_edge_traversal(4, 25.0);
tree.insert_trajectory(child3_label.clone(), child4_traversal, child4_label.clone())
.unwrap();
let path = tree.backtrack_with_depth(VertexId(4), 4).unwrap();
assert_eq!(path.len(), 4);
assert_eq!(path[0].edge_id, EdgeId(4)); assert_eq!(path[1].edge_id, EdgeId(3)); assert_eq!(path[2].edge_id, EdgeId(2)); assert_eq!(path[3].edge_id, EdgeId(1)); }
#[test]
fn test_backtrack_with_depth_reverse_tree_limited_depth() {
let root_label = create_test_label(0);
let mut tree = SearchTree::with_root(root_label.clone(), Direction::Reverse).unwrap();
let child1_label = create_test_label(1);
let child1_traversal = create_test_edge_traversal(1, 10.0);
tree.insert_trajectory(root_label.clone(), child1_traversal, child1_label.clone())
.unwrap();
let child2_label = create_test_label(2);
let child2_traversal = create_test_edge_traversal(2, 15.0);
tree.insert_trajectory(child1_label.clone(), child2_traversal, child2_label.clone())
.unwrap();
let child3_label = create_test_label(3);
let child3_traversal = create_test_edge_traversal(3, 20.0);
tree.insert_trajectory(child2_label.clone(), child3_traversal, child3_label.clone())
.unwrap();
let child4_label = create_test_label(4);
let child4_traversal = create_test_edge_traversal(4, 25.0);
tree.insert_trajectory(child3_label.clone(), child4_traversal, child4_label.clone())
.unwrap();
let path = tree.backtrack_with_depth(VertexId(4), 2).unwrap();
assert_eq!(path.len(), 2);
assert_eq!(path[0].edge_id, EdgeId(4)); assert_eq!(path[1].edge_id, EdgeId(3)); }
#[test]
fn test_backtrack_with_depth_from_root() {
let root_label = create_test_label(0);
let tree = SearchTree::with_root(root_label.clone(), Direction::Forward).unwrap();
let path = tree.backtrack_with_depth(VertexId(0), 5).unwrap();
assert_eq!(path.len(), 0);
}
#[test]
fn test_backtrack_with_depth_nonexistent_vertex() {
let root_label = create_test_label(0);
let tree = SearchTree::with_root(root_label, Direction::Forward).unwrap();
let result = tree.backtrack_with_depth(VertexId(99), 1);
assert!(matches!(
result,
Err(SearchTreeError::VertexNotFound(VertexId(99)))
));
}
#[test]
fn test_backtrack_with_depth_exceeds_available_path() {
let root_label = create_test_label(0);
let mut tree = SearchTree::with_root(root_label.clone(), Direction::Forward).unwrap();
let child1_label = create_test_label(1);
let child1_traversal = create_test_edge_traversal(1, 10.0);
tree.insert_trajectory(root_label.clone(), child1_traversal, child1_label.clone())
.unwrap();
let child2_label = create_test_label(2);
let child2_traversal = create_test_edge_traversal(2, 15.0);
tree.insert_trajectory(child1_label.clone(), child2_traversal, child2_label.clone())
.unwrap();
let path = tree.backtrack_with_depth(VertexId(2), 10).unwrap();
assert_eq!(path.len(), 2);
assert_eq!(path[0].edge_id, EdgeId(1)); assert_eq!(path[1].edge_id, EdgeId(2)); }
#[test]
fn test_backtrack_with_depth_branching_tree() {
let root_label = create_test_label(0);
let mut tree = SearchTree::with_root(root_label.clone(), Direction::Forward).unwrap();
let child1_label = create_test_label(1);
let child1_traversal = create_test_edge_traversal(1, 10.0);
tree.insert_trajectory(root_label.clone(), child1_traversal, child1_label.clone())
.unwrap();
let child2_label = create_test_label(2);
let child2_traversal = create_test_edge_traversal(2, 15.0);
tree.insert_trajectory(root_label.clone(), child2_traversal, child2_label.clone())
.unwrap();
let child3_label = create_test_label(3);
let child3_traversal = create_test_edge_traversal(3, 20.0);
tree.insert_trajectory(child1_label.clone(), child3_traversal, child3_label.clone())
.unwrap();
let child4_label = create_test_label(4);
let child4_traversal = create_test_edge_traversal(4, 25.0);
tree.insert_trajectory(child2_label.clone(), child4_traversal, child4_label.clone())
.unwrap();
let child5_label = create_test_label(5);
let child5_traversal = create_test_edge_traversal(5, 30.0);
tree.insert_trajectory(child4_label.clone(), child5_traversal, child5_label.clone())
.unwrap();
let path = tree.backtrack_with_depth(VertexId(3), 1).unwrap();
assert_eq!(path.len(), 1);
assert_eq!(path[0].edge_id, EdgeId(3));
let path = tree.backtrack_with_depth(VertexId(5), 2).unwrap();
assert_eq!(path.len(), 2);
assert_eq!(path[0].edge_id, EdgeId(4)); assert_eq!(path[1].edge_id, EdgeId(5));
let path = tree.backtrack_with_depth(VertexId(5), 3).unwrap();
assert_eq!(path.len(), 3);
assert_eq!(path[0].edge_id, EdgeId(2)); assert_eq!(path[1].edge_id, EdgeId(4)); assert_eq!(path[2].edge_id, EdgeId(5)); }
fn create_test_edge_traversal(edge_id: usize, cost: f64) -> EdgeTraversal {
EdgeTraversal {
edge_id: EdgeId(edge_id),
edge_list_id: EdgeListId(0),
cost: TraversalCost::mock(Cost::new(cost), Cost::new(cost)),
result_state: vec![],
}
}
fn create_test_label(vertex_id: usize) -> Label {
Label::Vertex(VertexId(vertex_id))
}
#[test]
fn test_backtrack_mixed_labels_bug() {
let mut tree = SearchTree::new_stateful(Direction::Forward);
let root_label = Label::Vertex(VertexId(0));
let child_label = Label::VertexWithIntState {
vertex_id: VertexId(1),
state: 1,
};
let result = tree.insert_trajectory(
root_label.clone(),
create_test_edge_traversal(1, 10.0),
child_label.clone(),
);
assert!(
matches!(result, Err(SearchTreeError::HeterogeneousLabelTypes(_, _))),
"Tree must reject heterogeneous label types"
);
}
#[test]
fn test_reconstruct_path_cycle_detection() {
let root_label = create_test_label(0);
let mut tree = SearchTree::with_root(root_label.clone(), Direction::Forward).unwrap();
let child_label = create_test_label(1);
let traversal = create_test_edge_traversal(1, 10.0);
tree.insert_trajectory(root_label.clone(), traversal.clone(), child_label.clone())
.unwrap();
let bad_root_node =
SearchTreeNode::new_child(traversal, child_label.clone(), Direction::Forward);
tree.storage
.insert_node(root_label.clone(), bad_root_node)
.unwrap();
let result = tree.backtrack(VertexId(1));
assert!(matches!(
result,
Err(SearchTreeError::InvalidBranchStructure(_))
));
}
}