use crate::{Graph, Vertex};
use std::collections::VecDeque;
use crate::error::GraphError;
use crate::algorithms::definitions::Parents;
pub fn bfs<'a, T>(graph: &'a Graph<T>, from: &'a Vertex<T>) -> Result<Parents<'a, T>, GraphError> {
let mut queue = VecDeque::new();
let mut parents = vec![None; graph.size()];
let mut visited = vec![false; graph.size()];
let from = from.id();
queue.push_back(from);
visited[from] = true;
while let Some(id) = queue.pop_front(){
for edge in &graph.adj[id].edges {
if !visited[edge.to] {
parents[edge.to] = Some(&graph.adj[id]);
queue.push_back(edge.to);
visited[edge.to] = true;
}
}
}
Ok(parents)
}
#[derive(PartialEq)]
pub enum VisitorBFSAction {
Nothing,
Break,
Error(GraphError)
}
pub trait VisitorBFS<T> {
#[allow(unused_variables)]
fn queue_extract_event(&mut self, vertex: &Vertex<T>) -> Result<VisitorBFSAction, GraphError> {
Ok(VisitorBFSAction::Nothing)
}
#[allow(unused_variables)]
fn place_in_queue_event(&mut self, vertex: &Vertex<T>, parents: &[Option<&Vertex<T>>]) -> Result<VisitorBFSAction, GraphError> {
Ok(VisitorBFSAction::Nothing)
}
#[allow(unused_variables)]
fn vertex_visited_event(&mut self, vertex: &Vertex<T>, parents: &[Option<&Vertex<T>>]) -> Result<VisitorBFSAction, GraphError> {
Ok(VisitorBFSAction::Nothing)
}
}
pub fn bfs_with_visitor<'a, 'b, T>(graph: &'a Graph<T>, from: &'a Vertex<T>, visitor: &'b mut dyn VisitorBFS<T>) -> Result<Parents<'a, T>, GraphError> {
let mut queue = VecDeque::new();
let mut parents = vec![None; graph.size()];
let mut visited = vec![false; graph.size()];
let from = from.id();
queue.push_back(from);
match visitor.place_in_queue_event(&graph.adj[from], &parents)? {
VisitorBFSAction::Nothing => {}
VisitorBFSAction::Break => {
return Ok(parents);
}
VisitorBFSAction::Error(err) => {
return Err(err);
}
}
visited[from] = true;
match visitor.vertex_visited_event(&graph.adj[from], &parents)? {
VisitorBFSAction::Nothing => {}
VisitorBFSAction::Break => {
return Ok(parents);
}
VisitorBFSAction::Error(err) => {
return Err(err);
}
}
while let Some(from) = queue.pop_front(){
match visitor.queue_extract_event(&graph.adj[from])? {
VisitorBFSAction::Nothing => {}
VisitorBFSAction::Break => {
break;
}
VisitorBFSAction::Error(err) => {
return Err(err);
}
}
for edge in &graph.adj[from].edges {
if !visited[edge.to] {
parents[edge.to] = Some(&graph.adj[from]);
queue.push_back(edge.to);
match visitor.place_in_queue_event(&graph.adj[edge.to], &parents)? {
VisitorBFSAction::Nothing => {}
VisitorBFSAction::Break => {
return Ok(parents);
}
VisitorBFSAction::Error(err) => {
return Err(err);
}
}
visited[edge.to] = true;
visited[from] = true;
match visitor.vertex_visited_event(&graph.adj[edge.to], &parents)? {
VisitorBFSAction::Nothing => {}
VisitorBFSAction::Break => {
return Ok(parents);
}
VisitorBFSAction::Error(err) => {
return Err(err);
}
}
}
}
}
Ok(parents)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bfs_algorithm() {
use crate::utils;
let mut graph = Graph::new(100);
graph.add_edge(1, 2, 0.0).unwrap();
graph.add_edge(2, 3, 0.0).unwrap();
graph.add_edge(2, 4, 0.0).unwrap();
graph.add_edge(2, 5, 0.0).unwrap();
graph.add_edge(4, 8, 0.0).unwrap();
graph.add_edge(8, 17, 0.0).unwrap();
let start = graph.get_vertex(1).unwrap();
let target = graph.get_vertex(5).unwrap();
let parents = bfs(&graph, &start).unwrap();
match utils::find_path(&graph, &target, &parents).unwrap() {
Some(path) => {
assert_eq!(path.iter().map(|vertex|vertex.id()).collect::<Vec<usize>>(), vec![1, 2, 5]);
}
None => {
println!("Path not found !!!")
}
}
let target = graph.get_vertex(17).unwrap();
let path = utils::find_path(&graph, &target, &parents).unwrap().unwrap();
assert_eq!(path.iter().map(|vertex|vertex.id()).collect::<Vec<usize>>(), vec![1, 2, 4, 8, 17]);
}
#[test]
#[should_panic]
fn test_bfs_algorithm_panic() {
let mut graph = Graph::new(100);
graph.add_edge(1, 2, 0.0).unwrap();
let start = graph.get_vertex(122).unwrap();
bfs(&graph, &start).unwrap();
}
#[test]
fn test_bfs_with_visitor_algorithm() {
struct CustomVisitor {
visiting_order: Vec<usize>
}
impl <T> VisitorBFS<T> for CustomVisitor {
fn queue_extract_event(&mut self, vertex: &Vertex<T>) -> Result<VisitorBFSAction, GraphError> {
self.visiting_order.push(vertex.id());
Ok(VisitorBFSAction::Nothing)
}
}
let mut graph = Graph::new(100);
graph.add_edge(1, 2, 0.0).unwrap();
graph.add_edge(2, 3, 0.0).unwrap();
graph.add_edge(2, 4, 0.0).unwrap();
graph.add_edge(2, 5, 0.0).unwrap();
graph.add_edge(4, 8, 0.0).unwrap();
graph.add_edge(8, 17, 0.0).unwrap();
let mut visitor = CustomVisitor{ visiting_order: vec![] };
let start = graph.get_vertex(1).unwrap();
bfs_with_visitor(&graph, &start, &mut visitor).unwrap();
assert_eq!(vec![1, 2, 3, 4, 5, 8, 17], visitor.visiting_order);
}
}