sinistra 0.1.0-202603071957

A generic graph framework with pluggable storage and topology and streaming graph algorithms.
Documentation
use std::collections::VecDeque;

use crate::graph::{
    EdgeHandle, EndpointTopology, Graph, GraphEdgesExt, GraphEndpointsExt, Policy, PropertySet,
    Traversal, TraversalEvent, VertexHandle,
};

pub struct Bfs<'graph, G, V> {
    graph: &'graph G,
    frontier: VecDeque<VertexHandle>,
    visited: V,
}

impl<'graph, G, V> Bfs<'graph, G, V>
where
    G: Graph,
    V: PropertySet<Key = VertexHandle> + Default,
    G::Topology: EndpointTopology,
{
    pub fn new(graph: &'graph G, start: VertexHandle, visited: V) -> Traversal<Self> {
        let bfs = Self {
            graph,
            frontier: VecDeque::new(),
            visited,
        };

        Traversal::new(bfs, start)
    }
}

impl<'graph, G, V> Policy for Bfs<'graph, G, V>
where
    G: Graph,
    V: PropertySet<Key = VertexHandle>,
    G::Topology: EndpointTopology,
{
    type Event = Event;
    type Item = VertexHandle;

    fn start(&mut self, start: VertexHandle) {
        self.frontier.push_back(start);
    }

    fn pop(&mut self) -> Option<Self::Item> {
        self.frontier.pop_front()
    }

    fn process(&mut self, source: VertexHandle, pending: &mut VecDeque<Self::Event>) {
        for edge in self.graph.out_edges(source) {
            let (_, target) = self.graph.edge_endpoints(edge).unwrap();

            pending.push_back(Event::Core(TraversalEvent::Examine {
                source,
                target,
                edge,
            }));

            if self.visited.mark(target, true) {
                self.frontier.push_back(target);

                pending.push_back(Event::TreeEdge {
                    source,
                    edge,
                    target,
                });

                pending.push_back(Event::Core(TraversalEvent::Discover { vertex: target }));
            }
        }

        pending.push_back(Event::Core(TraversalEvent::Finish { vertex: source }));
    }
}

#[derive(Debug, Clone, Copy)]
pub enum Event {
    Core(TraversalEvent),

    TreeEdge {
        source: VertexHandle,
        edge: EdgeHandle,
        target: VertexHandle,
    },
}

pub fn bfs<G, V>(graph: &G, start: VertexHandle) -> Traversal<Bfs<'_, G, V>>
where
    G: Graph,
    V: PropertySet<Key = VertexHandle> + Default,
    G::Topology: EndpointTopology,
{
    Bfs::new(graph, start, V::default())
}

pub fn bfs_vertices<G, V>(graph: &G, start: VertexHandle) -> impl Iterator<Item = VertexHandle>
where
    G: Graph,
    V: PropertySet<Key = VertexHandle> + Default,
    G::Topology: EndpointTopology,
{
    bfs::<G, V>(graph, start).filter_map(|event| {
        if let Event::Core(TraversalEvent::Discover { vertex }) = event {
            Some(vertex)
        } else {
            None
        }
    })
}

pub fn bfs_tree_edges<G, V>(
    graph: &G,
    start: VertexHandle,
) -> impl Iterator<Item = (VertexHandle, EdgeHandle, VertexHandle)>
where
    G: Graph,
    V: PropertySet<Key = VertexHandle> + Default,
    G::Topology: EndpointTopology,
{
    bfs::<G, V>(graph, start).filter_map(|event| {
        if let Event::TreeEdge {
            source,
            edge,
            target,
        } = event
        {
            Some((source, edge, target))
        } else {
            None
        }
    })
}