luka 0.4.0

Library for working with graphs
Documentation
use crate::{Graph, Vertex};
use crate::error::GraphError;
use crate::algorithms::{VisitorDFS, VisitorDFSAction, dfs_with_visitor};
use std::cmp::min;

pub struct Bridge<'a, T> {
    pub from: &'a Vertex<T>,
    pub to: &'a Vertex<T>,
}

struct CustomVisitor {
    visited: Vec<bool>,
    tin: Vec<usize>,
    d: Vec<usize>,
    bridges: Vec<(usize, usize)>,
    timer: usize,
}

impl <T> VisitorDFS<T> for CustomVisitor {
    fn entry_to_vertex_event(&mut self, vertex: &Vertex<T>) -> Result<VisitorDFSAction, GraphError> {
        self.visited[vertex.id] = true;
        self.tin[vertex.id] = self.timer;
        self.d[vertex.id] = self.timer;
        self.timer += 1;
        Ok(VisitorDFSAction::Nothing)
    }
    fn entry_to_white_vertex_event(&mut self, vertex: &Vertex<T>, _parent: &Vertex<T>, grand_parent: Option<&Vertex<T>>) -> Result<VisitorDFSAction, GraphError> {
        if let Some(value) = grand_parent {
            if value.id == vertex.id {
                return Ok(VisitorDFSAction::Break);
            }
        }
        Ok(VisitorDFSAction::Nothing)
    }
    fn exit_from_white_vertex_event(&mut self, vertex: &Vertex<T>, parent: &Vertex<T>, _grand_parent: Option<&Vertex<T>>) -> Result<VisitorDFSAction, GraphError> {
        self.d[parent.id] = min(self.d[parent.id], self.d[vertex.id]);
        if self.d[vertex.id] > self.tin[parent.id] {
            self.bridges.push((parent.id, vertex.id));
        }
        Ok(VisitorDFSAction::Nothing)
    }
    fn entry_to_grey_vertex_event(&mut self, vertex: &Vertex<T>, parent: &Vertex<T>, grand_parent: Option<&Vertex<T>>) -> Result<VisitorDFSAction, GraphError> {
        if let Some(value) = grand_parent {
            if value.id != vertex.id {
                self.d[parent.id] = min(self.d[parent.id], self.tin[vertex.id]);
            }
        }
        Ok(VisitorDFSAction::Nothing)
    }
}

/// Finding bridges in an undirected graph
///
/// ```
/// use luka::{Graph, algorithms};
///
/// let mut graph = Graph::new(7);
/// graph.add_edge(1, 2, 0).unwrap();
/// graph.add_edge(2, 1, 0).unwrap();
/// graph.add_edge(2, 3, 0).unwrap();
/// graph.add_edge(3, 2, 0).unwrap();
/// graph.add_edge(3, 1, 0).unwrap();
/// graph.add_edge(1, 3, 0).unwrap();
/// graph.add_edge(3, 4, 0).unwrap();
/// graph.add_edge(4, 3, 0).unwrap();
/// graph.add_edge(4, 5, 0).unwrap();
/// graph.add_edge(5, 4, 0).unwrap();
/// graph.add_edge(4, 6, 0).unwrap();
/// graph.add_edge(6, 4, 0).unwrap();
/// graph.add_edge(6, 5, 0).unwrap();
/// graph.add_edge(5, 6, 0).unwrap();
/// graph.add_edge(5, 7, 0).unwrap();
/// graph.add_edge(7, 5, 0).unwrap();
///
/// let mut bridges = vec![];
/// let res = algorithms::find_bridges(&graph).unwrap();
/// for bridge in res {
///     bridges.push((bridge.from.id(), bridge.to.id()));
/// }
/// assert_eq!(bridges, vec![(5, 7), (3, 4)]);
/// ```

pub fn find_bridges<T>(graph: &Graph<T>) -> Result<Vec<Bridge<T>>, GraphError> {
    let mut visitor = CustomVisitor { visited: vec![false; graph.size()], tin: vec![0; graph.size()], d: vec![0; graph.size()], bridges: vec![], timer: 1};
    for from in 1..graph.size() {
        if !visitor.visited[from] {
            dfs_with_visitor(graph, graph.get_vertex(from)?, &mut visitor)?;
        }
    }
    let mut bridges = vec![];
    for pair in visitor.bridges {
        bridges.push(Bridge{from: graph.get_vertex(pair.0)?, to: graph.get_vertex(pair.1)?});
    }
    Ok(bridges)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_find_bridges() {
        let mut graph = Graph::new(7);
        graph.add_edge(1, 2, 0).unwrap();
        graph.add_edge(2, 1, 0).unwrap();
        graph.add_edge(2, 3, 0).unwrap();
        graph.add_edge(3, 2, 0).unwrap();
        graph.add_edge(3, 1, 0).unwrap();
        graph.add_edge(1, 3, 0).unwrap();
        graph.add_edge(3, 4, 0).unwrap();
        graph.add_edge(4, 3, 0).unwrap();
        graph.add_edge(4, 5, 0).unwrap();
        graph.add_edge(5, 4, 0).unwrap();
        graph.add_edge(4, 6, 0).unwrap();
        graph.add_edge(6, 4, 0).unwrap();
        graph.add_edge(6, 5, 0).unwrap();
        graph.add_edge(5, 6, 0).unwrap();
        graph.add_edge(5, 7, 0).unwrap();
        graph.add_edge(7, 5, 0).unwrap();

        let mut bridges = vec![];
        let res = find_bridges(&graph).unwrap();
        for bridge in res {
            bridges.push((bridge.from.id, bridge.to.id));
        }
        assert_eq!(bridges, vec![(5, 7), (3, 4)]);
    }
}