use std::collections::{BinaryHeap, HashSet, VecDeque};
use crate::base::{DiGraph, EdgeWeight, Graph, Node};
use crate::error::{GraphError, Result};
#[allow(dead_code)]
pub fn breadth_first_search<N, E, Ix>(graph: &Graph<N, E, Ix>, source: &N) -> Result<Vec<N>>
where
N: Node + std::fmt::Debug,
E: EdgeWeight,
Ix: petgraph::graph::IndexType,
{
if !graph.has_node(source) {
return Err(GraphError::InvalidGraph(format!(
"Source node {source:?} not found"
)));
}
let mut visited = HashSet::new();
let mut queue = VecDeque::new();
let mut result = Vec::new();
let start_idx = graph
.inner()
.node_indices()
.find(|&idx| graph.inner()[idx] == *source)
.expect("Operation failed");
queue.push_back(start_idx);
visited.insert(start_idx);
while let Some(current_idx) = queue.pop_front() {
result.push(graph.inner()[current_idx].clone());
for neighbor_idx in graph.inner().neighbors(current_idx) {
if !visited.contains(&neighbor_idx) {
visited.insert(neighbor_idx);
queue.push_back(neighbor_idx);
}
}
}
Ok(result)
}
#[allow(dead_code)]
pub fn breadth_first_search_digraph<N, E, Ix>(
graph: &DiGraph<N, E, Ix>,
source: &N,
) -> Result<Vec<N>>
where
N: Node + std::fmt::Debug,
E: EdgeWeight,
Ix: petgraph::graph::IndexType,
{
if !graph.has_node(source) {
return Err(GraphError::InvalidGraph(format!(
"Source node {source:?} not found"
)));
}
let mut visited = HashSet::new();
let mut queue = VecDeque::new();
let mut result = Vec::new();
let start_idx = graph
.inner()
.node_indices()
.find(|&idx| graph.inner()[idx] == *source)
.expect("Operation failed");
queue.push_back(start_idx);
visited.insert(start_idx);
while let Some(current_idx) = queue.pop_front() {
result.push(graph.inner()[current_idx].clone());
for neighbor_idx in graph
.inner()
.neighbors_directed(current_idx, petgraph::Direction::Outgoing)
{
if !visited.contains(&neighbor_idx) {
visited.insert(neighbor_idx);
queue.push_back(neighbor_idx);
}
}
}
Ok(result)
}
#[allow(dead_code)]
pub fn depth_first_search<N, E, Ix>(graph: &Graph<N, E, Ix>, source: &N) -> Result<Vec<N>>
where
N: Node + std::fmt::Debug,
E: EdgeWeight,
Ix: petgraph::graph::IndexType,
{
if !graph.has_node(source) {
return Err(GraphError::InvalidGraph(format!(
"Source node {source:?} not found"
)));
}
let mut visited = HashSet::new();
let mut stack = Vec::new();
let mut result = Vec::new();
let start_idx = graph
.inner()
.node_indices()
.find(|&idx| graph.inner()[idx] == *source)
.expect("Operation failed");
stack.push(start_idx);
while let Some(current_idx) = stack.pop() {
if !visited.contains(¤t_idx) {
visited.insert(current_idx);
result.push(graph.inner()[current_idx].clone());
let mut neighbors: Vec<_> = graph.inner().neighbors(current_idx).collect();
neighbors.reverse();
for neighbor_idx in neighbors {
if !visited.contains(&neighbor_idx) {
stack.push(neighbor_idx);
}
}
}
}
Ok(result)
}
#[allow(dead_code)]
pub fn depth_first_search_digraph<N, E, Ix>(graph: &DiGraph<N, E, Ix>, source: &N) -> Result<Vec<N>>
where
N: Node + std::fmt::Debug,
E: EdgeWeight,
Ix: petgraph::graph::IndexType,
{
if !graph.has_node(source) {
return Err(GraphError::InvalidGraph(format!(
"Source node {source:?} not found"
)));
}
let mut visited = HashSet::new();
let mut stack = Vec::new();
let mut result = Vec::new();
let start_idx = graph
.inner()
.node_indices()
.find(|&idx| graph.inner()[idx] == *source)
.expect("Operation failed");
stack.push(start_idx);
while let Some(current_idx) = stack.pop() {
if !visited.contains(¤t_idx) {
visited.insert(current_idx);
result.push(graph.inner()[current_idx].clone());
let mut neighbors: Vec<_> = graph
.inner()
.neighbors_directed(current_idx, petgraph::Direction::Outgoing)
.collect();
neighbors.reverse();
for neighbor_idx in neighbors {
if !visited.contains(&neighbor_idx) {
stack.push(neighbor_idx);
}
}
}
}
Ok(result)
}
#[derive(Clone)]
struct PriorityState<N: Node + std::fmt::Debug, P: PartialOrd> {
node: N,
priority: P,
}
impl<N: Node + std::fmt::Debug, P: PartialOrd> PartialEq for PriorityState<N, P> {
fn eq(&self, other: &Self) -> bool {
self.node == other.node
}
}
impl<N: Node + std::fmt::Debug, P: PartialOrd> Eq for PriorityState<N, P> {}
impl<N: Node + std::fmt::Debug, P: PartialOrd> PartialOrd for PriorityState<N, P> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<N: Node + std::fmt::Debug, P: PartialOrd> Ord for PriorityState<N, P> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
other
.priority
.partial_cmp(&self.priority)
.unwrap_or(std::cmp::Ordering::Equal)
}
}
#[allow(dead_code)]
pub fn priority_first_search<N, E, Ix, P, F>(
graph: &Graph<N, E, Ix>,
source: &N,
priority_fn: F,
) -> Result<Vec<N>>
where
N: Node + std::fmt::Debug + Clone,
E: EdgeWeight,
Ix: petgraph::graph::IndexType,
P: PartialOrd + Clone + Copy,
F: Fn(&N) -> P,
{
if !graph.has_node(source) {
return Err(GraphError::InvalidGraph(format!(
"Source node {source:?} not found"
)));
}
let mut visited = HashSet::new();
let mut priority_queue = BinaryHeap::new();
let mut result = Vec::new();
let _start_idx = graph
.inner()
.node_indices()
.find(|&idx| graph.inner()[idx] == *source)
.expect("Operation failed");
priority_queue.push(PriorityState {
node: source.clone(),
priority: priority_fn(source),
});
while let Some(current_state) = priority_queue.pop() {
let current_node = ¤t_state.node;
if visited.contains(current_node) {
continue;
}
visited.insert(current_node.clone());
result.push(current_node.clone());
let current_idx = graph
.inner()
.node_indices()
.find(|&idx| graph.inner()[idx] == *current_node)
.expect("Operation failed");
for neighbor_idx in graph.inner().neighbors(current_idx) {
let neighbor_node = &graph.inner()[neighbor_idx];
if !visited.contains(neighbor_node) {
priority_queue.push(PriorityState {
node: neighbor_node.clone(),
priority: priority_fn(neighbor_node),
});
}
}
}
Ok(result)
}
#[allow(dead_code)]
pub fn priority_first_search_digraph<N, E, Ix, P, F>(
graph: &DiGraph<N, E, Ix>,
source: &N,
priority_fn: F,
) -> Result<Vec<N>>
where
N: Node + std::fmt::Debug + Clone,
E: EdgeWeight,
Ix: petgraph::graph::IndexType,
P: PartialOrd + Clone + Copy,
F: Fn(&N) -> P,
{
if !graph.has_node(source) {
return Err(GraphError::InvalidGraph(format!(
"Source node {source:?} not found"
)));
}
let mut visited = HashSet::new();
let mut priority_queue = BinaryHeap::new();
let mut result = Vec::new();
priority_queue.push(PriorityState {
node: source.clone(),
priority: priority_fn(source),
});
while let Some(current_state) = priority_queue.pop() {
let current_node = ¤t_state.node;
if visited.contains(current_node) {
continue;
}
visited.insert(current_node.clone());
result.push(current_node.clone());
let current_idx = graph
.inner()
.node_indices()
.find(|&idx| graph.inner()[idx] == *current_node)
.expect("Operation failed");
for neighbor_idx in graph
.inner()
.neighbors_directed(current_idx, petgraph::Direction::Outgoing)
{
let neighbor_node = &graph.inner()[neighbor_idx];
if !visited.contains(neighbor_node) {
priority_queue.push(PriorityState {
node: neighbor_node.clone(),
priority: priority_fn(neighbor_node),
});
}
}
}
Ok(result)
}
#[allow(dead_code)]
pub fn bidirectional_search<N, E, Ix>(
graph: &Graph<N, E, Ix>,
source: &N,
goal: &N,
) -> Result<Option<Vec<N>>>
where
N: Node + std::fmt::Debug + Clone + std::hash::Hash + Eq,
E: EdgeWeight,
Ix: petgraph::graph::IndexType,
{
if !graph.has_node(source) || !graph.has_node(goal) {
return Err(GraphError::InvalidGraph(
"Source or goal node not found".to_string(),
));
}
if source == goal {
return Ok(Some(vec![source.clone()]));
}
let start_idx = graph
.inner()
.node_indices()
.find(|&idx| graph.inner()[idx] == *source)
.expect("Operation failed");
let goal_idx = graph
.inner()
.node_indices()
.find(|&idx| graph.inner()[idx] == *goal)
.expect("Operation failed");
let mut forward_queue = VecDeque::new();
let mut backward_queue = VecDeque::new();
let mut forward_visited = HashSet::new();
let mut backward_visited = HashSet::new();
let mut forward_parent: std::collections::HashMap<
petgraph::graph::NodeIndex<Ix>,
petgraph::graph::NodeIndex<Ix>,
> = std::collections::HashMap::new();
let mut backward_parent: std::collections::HashMap<
petgraph::graph::NodeIndex<Ix>,
petgraph::graph::NodeIndex<Ix>,
> = std::collections::HashMap::new();
forward_queue.push_back(start_idx);
backward_queue.push_back(goal_idx);
forward_visited.insert(start_idx);
backward_visited.insert(goal_idx);
while !forward_queue.is_empty() || !backward_queue.is_empty() {
if !forward_queue.is_empty() {
let current = forward_queue.pop_front().expect("Operation failed");
if backward_visited.contains(¤t) {
return Ok(Some(reconstruct_bidirectional_path(
graph,
start_idx,
goal_idx,
current,
&forward_parent,
&backward_parent,
)));
}
for neighbor in graph.inner().neighbors(current) {
if !forward_visited.contains(&neighbor) {
forward_visited.insert(neighbor);
forward_parent.insert(neighbor, current);
forward_queue.push_back(neighbor);
}
}
}
if !backward_queue.is_empty() {
let current = backward_queue.pop_front().expect("Operation failed");
if forward_visited.contains(¤t) {
return Ok(Some(reconstruct_bidirectional_path(
graph,
start_idx,
goal_idx,
current,
&forward_parent,
&backward_parent,
)));
}
for neighbor in graph.inner().neighbors(current) {
if !backward_visited.contains(&neighbor) {
backward_visited.insert(neighbor);
backward_parent.insert(neighbor, current);
backward_queue.push_back(neighbor);
}
}
}
}
Ok(None)
}
#[allow(dead_code)]
pub fn bidirectional_search_digraph<N, E, Ix>(
graph: &DiGraph<N, E, Ix>,
source: &N,
goal: &N,
) -> Result<Option<Vec<N>>>
where
N: Node + std::fmt::Debug + Clone + std::hash::Hash + Eq,
E: EdgeWeight,
Ix: petgraph::graph::IndexType,
{
if !graph.has_node(source) || !graph.has_node(goal) {
return Err(GraphError::InvalidGraph(
"Source or goal node not found".to_string(),
));
}
if source == goal {
return Ok(Some(vec![source.clone()]));
}
let start_idx = graph
.inner()
.node_indices()
.find(|&idx| graph.inner()[idx] == *source)
.expect("Operation failed");
let goal_idx = graph
.inner()
.node_indices()
.find(|&idx| graph.inner()[idx] == *goal)
.expect("Operation failed");
let mut forward_queue = VecDeque::new();
let mut backward_queue = VecDeque::new();
let mut forward_visited = HashSet::new();
let mut backward_visited = HashSet::new();
let mut forward_parent: std::collections::HashMap<
petgraph::graph::NodeIndex<Ix>,
petgraph::graph::NodeIndex<Ix>,
> = std::collections::HashMap::new();
let mut backward_parent: std::collections::HashMap<
petgraph::graph::NodeIndex<Ix>,
petgraph::graph::NodeIndex<Ix>,
> = std::collections::HashMap::new();
forward_queue.push_back(start_idx);
backward_queue.push_back(goal_idx);
forward_visited.insert(start_idx);
backward_visited.insert(goal_idx);
while !forward_queue.is_empty() || !backward_queue.is_empty() {
if !forward_queue.is_empty() {
let current = forward_queue.pop_front().expect("Operation failed");
if backward_visited.contains(¤t) {
return Ok(Some(reconstruct_bidirectional_path_digraph(
graph,
start_idx,
goal_idx,
current,
&forward_parent,
&backward_parent,
)));
}
for neighbor in graph
.inner()
.neighbors_directed(current, petgraph::Direction::Outgoing)
{
if !forward_visited.contains(&neighbor) {
forward_visited.insert(neighbor);
forward_parent.insert(neighbor, current);
forward_queue.push_back(neighbor);
}
}
}
if !backward_queue.is_empty() {
let current = backward_queue.pop_front().expect("Operation failed");
if forward_visited.contains(¤t) {
return Ok(Some(reconstruct_bidirectional_path_digraph(
graph,
start_idx,
goal_idx,
current,
&forward_parent,
&backward_parent,
)));
}
for neighbor in graph
.inner()
.neighbors_directed(current, petgraph::Direction::Incoming)
{
if !backward_visited.contains(&neighbor) {
backward_visited.insert(neighbor);
backward_parent.insert(neighbor, current);
backward_queue.push_back(neighbor);
}
}
}
}
Ok(None)
}
#[allow(dead_code)]
fn reconstruct_bidirectional_path<N, E, Ix>(
graph: &Graph<N, E, Ix>,
start_idx: petgraph::graph::NodeIndex<Ix>,
goal_idx: petgraph::graph::NodeIndex<Ix>,
meeting_point: petgraph::graph::NodeIndex<Ix>,
forward_parent: &std::collections::HashMap<
petgraph::graph::NodeIndex<Ix>,
petgraph::graph::NodeIndex<Ix>,
>,
backward_parent: &std::collections::HashMap<
petgraph::graph::NodeIndex<Ix>,
petgraph::graph::NodeIndex<Ix>,
>,
) -> Vec<N>
where
N: Node + std::fmt::Debug + Clone,
E: EdgeWeight,
Ix: petgraph::graph::IndexType,
{
let mut forward_path = Vec::new();
let mut current = meeting_point;
while current != start_idx {
forward_path.push(graph.inner()[current].clone());
current = forward_parent[¤t];
}
forward_path.push(graph.inner()[start_idx].clone());
forward_path.reverse();
let mut backward_path = Vec::new();
current = meeting_point;
while current != goal_idx {
if let Some(&parent) = backward_parent.get(¤t) {
current = parent;
backward_path.push(graph.inner()[current].clone());
} else {
break;
}
}
let mut full_path = forward_path;
full_path.extend(backward_path);
full_path
}
#[allow(dead_code)]
fn reconstruct_bidirectional_path_digraph<N, E, Ix>(
graph: &DiGraph<N, E, Ix>,
start_idx: petgraph::graph::NodeIndex<Ix>,
goal_idx: petgraph::graph::NodeIndex<Ix>,
meeting_point: petgraph::graph::NodeIndex<Ix>,
forward_parent: &std::collections::HashMap<
petgraph::graph::NodeIndex<Ix>,
petgraph::graph::NodeIndex<Ix>,
>,
backward_parent: &std::collections::HashMap<
petgraph::graph::NodeIndex<Ix>,
petgraph::graph::NodeIndex<Ix>,
>,
) -> Vec<N>
where
N: Node + std::fmt::Debug + Clone,
E: EdgeWeight,
Ix: petgraph::graph::IndexType,
{
let mut forward_path = Vec::new();
let mut current = meeting_point;
while current != start_idx {
forward_path.push(graph.inner()[current].clone());
current = forward_parent[¤t];
}
forward_path.push(graph.inner()[start_idx].clone());
forward_path.reverse();
let mut backward_path = Vec::new();
current = meeting_point;
while current != goal_idx {
if let Some(&parent) = backward_parent.get(¤t) {
current = parent;
backward_path.push(graph.inner()[current].clone());
} else {
break;
}
}
let mut full_path = forward_path;
full_path.extend(backward_path);
full_path
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_breadth_first_search() {
let mut graph: Graph<i32, f64> = Graph::new();
graph.add_edge(1, 2, 1.0).expect("Operation failed");
graph.add_edge(2, 3, 1.0).expect("Operation failed");
graph.add_edge(2, 4, 1.0).expect("Operation failed");
let result = breadth_first_search(&graph, &1).expect("Operation failed");
assert_eq!(result[0], 1);
assert_eq!(result[1], 2);
assert!(result.contains(&3));
assert!(result.contains(&4));
assert_eq!(result.len(), 4);
}
#[test]
fn test_breadth_first_search_digraph() {
let mut graph: DiGraph<i32, f64> = DiGraph::new();
graph.add_edge(1, 2, 1.0).expect("Operation failed");
graph.add_edge(2, 3, 1.0).expect("Operation failed");
graph.add_edge(2, 4, 1.0).expect("Operation failed");
let result = breadth_first_search_digraph(&graph, &1).expect("Operation failed");
assert_eq!(result[0], 1);
assert_eq!(result[1], 2);
assert!(result.contains(&3));
assert!(result.contains(&4));
assert_eq!(result.len(), 4);
}
#[test]
fn test_depth_first_search() {
let mut graph: Graph<i32, f64> = Graph::new();
graph.add_edge(1, 2, 1.0).expect("Operation failed");
graph.add_edge(1, 3, 1.0).expect("Operation failed");
graph.add_edge(2, 4, 1.0).expect("Operation failed");
let result = depth_first_search(&graph, &1).expect("Operation failed");
assert_eq!(result[0], 1);
assert_eq!(result.len(), 4);
assert!(result.contains(&2));
assert!(result.contains(&3));
assert!(result.contains(&4));
}
#[test]
fn test_depth_first_search_digraph() {
let mut graph: DiGraph<i32, f64> = DiGraph::new();
graph.add_edge(1, 2, 1.0).expect("Operation failed");
graph.add_edge(1, 3, 1.0).expect("Operation failed");
graph.add_edge(2, 4, 1.0).expect("Operation failed");
let result = depth_first_search_digraph(&graph, &1).expect("Operation failed");
assert_eq!(result[0], 1);
assert_eq!(result.len(), 4);
assert!(result.contains(&2));
assert!(result.contains(&3));
assert!(result.contains(&4));
}
#[test]
fn test_bidirectional_search() {
let mut graph: Graph<i32, f64> = Graph::new();
graph.add_edge(1, 2, 1.0).expect("Operation failed");
graph.add_edge(2, 3, 1.0).expect("Operation failed");
graph.add_edge(3, 4, 1.0).expect("Operation failed");
graph.add_edge(4, 5, 1.0).expect("Operation failed");
let path = bidirectional_search(&graph, &1, &5)
.expect("Path search failed")
.expect("No path found");
assert_eq!(path[0], 1);
assert_eq!(path[path.len() - 1], 5);
assert!(path.len() <= 5);
let same_path = bidirectional_search(&graph, &3, &3)
.expect("Path search failed")
.expect("No path found");
assert_eq!(same_path, vec![3]);
let mut disconnected: Graph<i32, f64> = Graph::new();
disconnected.add_node(1);
disconnected.add_node(2);
let no_path = bidirectional_search(&disconnected, &1, &2).expect("Operation failed");
assert_eq!(no_path, None);
}
#[test]
fn test_bidirectional_search_digraph() {
let mut graph: DiGraph<i32, f64> = DiGraph::new();
graph.add_edge(1, 2, 1.0).expect("Operation failed");
graph.add_edge(2, 3, 1.0).expect("Operation failed");
graph.add_edge(3, 4, 1.0).expect("Operation failed");
graph.add_edge(4, 5, 1.0).expect("Operation failed");
let path = bidirectional_search_digraph(&graph, &1, &5)
.expect("Operation failed")
.expect("Operation failed");
assert_eq!(path[0], 1);
assert_eq!(path[path.len() - 1], 5);
let no_path = bidirectional_search_digraph(&graph, &5, &1).expect("Operation failed");
assert_eq!(no_path, None);
}
#[test]
fn test_priority_first_search() {
let mut graph: Graph<i32, f64> = Graph::new();
graph.add_edge(1, 2, 1.0).expect("Operation failed");
graph.add_edge(2, 3, 1.0).expect("Operation failed");
graph.add_edge(2, 4, 1.0).expect("Operation failed");
let result = priority_first_search(&graph, &1, |node| *node).expect("Operation failed");
assert_eq!(result[0], 1);
assert_eq!(result[1], 2);
assert!(result.contains(&3));
assert!(result.contains(&4));
assert_eq!(result.len(), 4);
let result_reverse =
priority_first_search(&graph, &1, |node| -node).expect("Operation failed");
assert_eq!(result_reverse[0], 1);
assert_eq!(result_reverse[1], 2);
assert!(
result_reverse.iter().position(|&x| x == 4)
< result_reverse.iter().position(|&x| x == 3)
);
}
#[test]
fn test_priority_first_search_digraph() {
let mut graph: DiGraph<i32, f64> = DiGraph::new();
graph.add_edge(1, 2, 1.0).expect("Operation failed");
graph.add_edge(2, 3, 1.0).expect("Operation failed");
graph.add_edge(2, 4, 1.0).expect("Operation failed");
let result =
priority_first_search_digraph(&graph, &1, |node| *node).expect("Operation failed");
assert_eq!(result[0], 1);
assert_eq!(result[1], 2);
assert!(result.contains(&3));
assert!(result.contains(&4));
assert_eq!(result.len(), 4);
let result_constant =
priority_first_search_digraph(&graph, &1, |_| 1).expect("Operation failed");
assert_eq!(result_constant[0], 1);
assert_eq!(result_constant[1], 2);
assert_eq!(result_constant.len(), 4);
}
}