diff options
Diffstat (limited to 'third_party/rust/petgraph/src/visit/traversal.rs')
-rw-r--r-- | third_party/rust/petgraph/src/visit/traversal.rs | 519 |
1 files changed, 519 insertions, 0 deletions
diff --git a/third_party/rust/petgraph/src/visit/traversal.rs b/third_party/rust/petgraph/src/visit/traversal.rs new file mode 100644 index 0000000000..88782fa24f --- /dev/null +++ b/third_party/rust/petgraph/src/visit/traversal.rs @@ -0,0 +1,519 @@ +use super::{GraphRef, IntoNodeIdentifiers, Reversed}; +use super::{IntoNeighbors, IntoNeighborsDirected, VisitMap, Visitable}; +use crate::Incoming; +use std::collections::VecDeque; + +/// Visit nodes of a graph in a depth-first-search (DFS) emitting nodes in +/// preorder (when they are first discovered). +/// +/// The traversal starts at a given node and only traverses nodes reachable +/// from it. +/// +/// `Dfs` is not recursive. +/// +/// `Dfs` does not itself borrow the graph, and because of this you can run +/// a traversal over a graph while still retaining mutable access to it, if you +/// use it like the following example: +/// +/// ``` +/// use petgraph::Graph; +/// use petgraph::visit::Dfs; +/// +/// let mut graph = Graph::<_,()>::new(); +/// let a = graph.add_node(0); +/// +/// let mut dfs = Dfs::new(&graph, a); +/// while let Some(nx) = dfs.next(&graph) { +/// // we can access `graph` mutably here still +/// graph[nx] += 1; +/// } +/// +/// assert_eq!(graph[a], 1); +/// ``` +/// +/// **Note:** The algorithm may not behave correctly if nodes are removed +/// during iteration. It may not necessarily visit added nodes or edges. +#[derive(Clone, Debug)] +pub struct Dfs<N, VM> { + /// The stack of nodes to visit + pub stack: Vec<N>, + /// The map of discovered nodes + pub discovered: VM, +} + +impl<N, VM> Default for Dfs<N, VM> +where + VM: Default, +{ + fn default() -> Self { + Dfs { + stack: Vec::new(), + discovered: VM::default(), + } + } +} + +impl<N, VM> Dfs<N, VM> +where + N: Copy + PartialEq, + VM: VisitMap<N>, +{ + /// Create a new **Dfs**, using the graph's visitor map, and put **start** + /// in the stack of nodes to visit. + pub fn new<G>(graph: G, start: N) -> Self + where + G: GraphRef + Visitable<NodeId = N, Map = VM>, + { + let mut dfs = Dfs::empty(graph); + dfs.move_to(start); + dfs + } + + /// Create a `Dfs` from a vector and a visit map + pub fn from_parts(stack: Vec<N>, discovered: VM) -> Self { + Dfs { stack, discovered } + } + + /// Clear the visit state + pub fn reset<G>(&mut self, graph: G) + where + G: GraphRef + Visitable<NodeId = N, Map = VM>, + { + graph.reset_map(&mut self.discovered); + self.stack.clear(); + } + + /// Create a new **Dfs** using the graph's visitor map, and no stack. + pub fn empty<G>(graph: G) -> Self + where + G: GraphRef + Visitable<NodeId = N, Map = VM>, + { + Dfs { + stack: Vec::new(), + discovered: graph.visit_map(), + } + } + + /// Keep the discovered map, but clear the visit stack and restart + /// the dfs from a particular node. + pub fn move_to(&mut self, start: N) { + self.stack.clear(); + self.stack.push(start); + } + + /// Return the next node in the dfs, or **None** if the traversal is done. + pub fn next<G>(&mut self, graph: G) -> Option<N> + where + G: IntoNeighbors<NodeId = N>, + { + while let Some(node) = self.stack.pop() { + if self.discovered.visit(node) { + for succ in graph.neighbors(node) { + if !self.discovered.is_visited(&succ) { + self.stack.push(succ); + } + } + return Some(node); + } + } + None + } +} + +/// Visit nodes in a depth-first-search (DFS) emitting nodes in postorder +/// (each node after all its descendants have been emitted). +/// +/// `DfsPostOrder` is not recursive. +/// +/// The traversal starts at a given node and only traverses nodes reachable +/// from it. +#[derive(Clone, Debug)] +pub struct DfsPostOrder<N, VM> { + /// The stack of nodes to visit + pub stack: Vec<N>, + /// The map of discovered nodes + pub discovered: VM, + /// The map of finished nodes + pub finished: VM, +} + +impl<N, VM> Default for DfsPostOrder<N, VM> +where + VM: Default, +{ + fn default() -> Self { + DfsPostOrder { + stack: Vec::new(), + discovered: VM::default(), + finished: VM::default(), + } + } +} + +impl<N, VM> DfsPostOrder<N, VM> +where + N: Copy + PartialEq, + VM: VisitMap<N>, +{ + /// Create a new `DfsPostOrder` using the graph's visitor map, and put + /// `start` in the stack of nodes to visit. + pub fn new<G>(graph: G, start: N) -> Self + where + G: GraphRef + Visitable<NodeId = N, Map = VM>, + { + let mut dfs = Self::empty(graph); + dfs.move_to(start); + dfs + } + + /// Create a new `DfsPostOrder` using the graph's visitor map, and no stack. + pub fn empty<G>(graph: G) -> Self + where + G: GraphRef + Visitable<NodeId = N, Map = VM>, + { + DfsPostOrder { + stack: Vec::new(), + discovered: graph.visit_map(), + finished: graph.visit_map(), + } + } + + /// Clear the visit state + pub fn reset<G>(&mut self, graph: G) + where + G: GraphRef + Visitable<NodeId = N, Map = VM>, + { + graph.reset_map(&mut self.discovered); + graph.reset_map(&mut self.finished); + self.stack.clear(); + } + + /// Keep the discovered and finished map, but clear the visit stack and restart + /// the dfs from a particular node. + pub fn move_to(&mut self, start: N) { + self.stack.clear(); + self.stack.push(start); + } + + /// Return the next node in the traversal, or `None` if the traversal is done. + pub fn next<G>(&mut self, graph: G) -> Option<N> + where + G: IntoNeighbors<NodeId = N>, + { + while let Some(&nx) = self.stack.last() { + if self.discovered.visit(nx) { + // First time visiting `nx`: Push neighbors, don't pop `nx` + for succ in graph.neighbors(nx) { + if !self.discovered.is_visited(&succ) { + self.stack.push(succ); + } + } + } else { + self.stack.pop(); + if self.finished.visit(nx) { + // Second time: All reachable nodes must have been finished + return Some(nx); + } + } + } + None + } +} + +/// A breadth first search (BFS) of a graph. +/// +/// The traversal starts at a given node and only traverses nodes reachable +/// from it. +/// +/// `Bfs` is not recursive. +/// +/// `Bfs` does not itself borrow the graph, and because of this you can run +/// a traversal over a graph while still retaining mutable access to it, if you +/// use it like the following example: +/// +/// ``` +/// use petgraph::Graph; +/// use petgraph::visit::Bfs; +/// +/// let mut graph = Graph::<_,()>::new(); +/// let a = graph.add_node(0); +/// +/// let mut bfs = Bfs::new(&graph, a); +/// while let Some(nx) = bfs.next(&graph) { +/// // we can access `graph` mutably here still +/// graph[nx] += 1; +/// } +/// +/// assert_eq!(graph[a], 1); +/// ``` +/// +/// **Note:** The algorithm may not behave correctly if nodes are removed +/// during iteration. It may not necessarily visit added nodes or edges. +#[derive(Clone)] +pub struct Bfs<N, VM> { + /// The queue of nodes to visit + pub stack: VecDeque<N>, + /// The map of discovered nodes + pub discovered: VM, +} + +impl<N, VM> Default for Bfs<N, VM> +where + VM: Default, +{ + fn default() -> Self { + Bfs { + stack: VecDeque::new(), + discovered: VM::default(), + } + } +} + +impl<N, VM> Bfs<N, VM> +where + N: Copy + PartialEq, + VM: VisitMap<N>, +{ + /// Create a new **Bfs**, using the graph's visitor map, and put **start** + /// in the stack of nodes to visit. + pub fn new<G>(graph: G, start: N) -> Self + where + G: GraphRef + Visitable<NodeId = N, Map = VM>, + { + let mut discovered = graph.visit_map(); + discovered.visit(start); + let mut stack = VecDeque::new(); + stack.push_front(start); + Bfs { stack, discovered } + } + + /// Return the next node in the bfs, or **None** if the traversal is done. + pub fn next<G>(&mut self, graph: G) -> Option<N> + where + G: IntoNeighbors<NodeId = N>, + { + if let Some(node) = self.stack.pop_front() { + for succ in graph.neighbors(node) { + if self.discovered.visit(succ) { + self.stack.push_back(succ); + } + } + + return Some(node); + } + None + } +} + +/// A topological order traversal for a graph. +/// +/// **Note** that `Topo` only visits nodes that are not part of cycles, +/// i.e. nodes in a true DAG. Use other visitors like `DfsPostOrder` or +/// algorithms like kosaraju_scc to handle graphs with possible cycles. +#[derive(Clone)] +pub struct Topo<N, VM> { + tovisit: Vec<N>, + ordered: VM, +} + +impl<N, VM> Default for Topo<N, VM> +where + VM: Default, +{ + fn default() -> Self { + Topo { + tovisit: Vec::new(), + ordered: VM::default(), + } + } +} + +impl<N, VM> Topo<N, VM> +where + N: Copy + PartialEq, + VM: VisitMap<N>, +{ + /// Create a new `Topo`, using the graph's visitor map, and put all + /// initial nodes in the to visit list. + pub fn new<G>(graph: G) -> Self + where + G: IntoNodeIdentifiers + IntoNeighborsDirected + Visitable<NodeId = N, Map = VM>, + { + let mut topo = Self::empty(graph); + topo.extend_with_initials(graph); + topo + } + + fn extend_with_initials<G>(&mut self, g: G) + where + G: IntoNodeIdentifiers + IntoNeighborsDirected<NodeId = N>, + { + // find all initial nodes (nodes without incoming edges) + self.tovisit.extend( + g.node_identifiers() + .filter(move |&a| g.neighbors_directed(a, Incoming).next().is_none()), + ); + } + + /* Private until it has a use */ + /// Create a new `Topo`, using the graph's visitor map with *no* starting + /// index specified. + fn empty<G>(graph: G) -> Self + where + G: GraphRef + Visitable<NodeId = N, Map = VM>, + { + Topo { + ordered: graph.visit_map(), + tovisit: Vec::new(), + } + } + + /// Clear visited state, and put all initial nodes in the to visit list. + pub fn reset<G>(&mut self, graph: G) + where + G: IntoNodeIdentifiers + IntoNeighborsDirected + Visitable<NodeId = N, Map = VM>, + { + graph.reset_map(&mut self.ordered); + self.tovisit.clear(); + self.extend_with_initials(graph); + } + + /// Return the next node in the current topological order traversal, or + /// `None` if the traversal is at the end. + /// + /// *Note:* The graph may not have a complete topological order, and the only + /// way to know is to run the whole traversal and make sure it visits every node. + pub fn next<G>(&mut self, g: G) -> Option<N> + where + G: IntoNeighborsDirected + Visitable<NodeId = N, Map = VM>, + { + // Take an unvisited element and find which of its neighbors are next + while let Some(nix) = self.tovisit.pop() { + if self.ordered.is_visited(&nix) { + continue; + } + self.ordered.visit(nix); + for neigh in g.neighbors(nix) { + // Look at each neighbor, and those that only have incoming edges + // from the already ordered list, they are the next to visit. + if Reversed(g) + .neighbors(neigh) + .all(|b| self.ordered.is_visited(&b)) + { + self.tovisit.push(neigh); + } + } + return Some(nix); + } + None + } +} + +/// A walker is a traversal state, but where part of the traversal +/// information is supplied manually to each next call. +/// +/// This for example allows graph traversals that don't hold a borrow of the +/// graph they are traversing. +pub trait Walker<Context> { + type Item; + /// Advance to the next item + fn walk_next(&mut self, context: Context) -> Option<Self::Item>; + + /// Create an iterator out of the walker and given `context`. + fn iter(self, context: Context) -> WalkerIter<Self, Context> + where + Self: Sized, + Context: Clone, + { + WalkerIter { + walker: self, + context, + } + } +} + +/// A walker and its context wrapped into an iterator. +#[derive(Clone, Debug)] +pub struct WalkerIter<W, C> { + walker: W, + context: C, +} + +impl<W, C> WalkerIter<W, C> +where + W: Walker<C>, + C: Clone, +{ + pub fn context(&self) -> C { + self.context.clone() + } + + pub fn inner_ref(&self) -> &W { + &self.walker + } + + pub fn inner_mut(&mut self) -> &mut W { + &mut self.walker + } +} + +impl<W, C> Iterator for WalkerIter<W, C> +where + W: Walker<C>, + C: Clone, +{ + type Item = W::Item; + fn next(&mut self) -> Option<Self::Item> { + self.walker.walk_next(self.context.clone()) + } +} + +impl<'a, C, W: ?Sized> Walker<C> for &'a mut W +where + W: Walker<C>, +{ + type Item = W::Item; + fn walk_next(&mut self, context: C) -> Option<Self::Item> { + (**self).walk_next(context) + } +} + +impl<G> Walker<G> for Dfs<G::NodeId, G::Map> +where + G: IntoNeighbors + Visitable, +{ + type Item = G::NodeId; + fn walk_next(&mut self, context: G) -> Option<Self::Item> { + self.next(context) + } +} + +impl<G> Walker<G> for DfsPostOrder<G::NodeId, G::Map> +where + G: IntoNeighbors + Visitable, +{ + type Item = G::NodeId; + fn walk_next(&mut self, context: G) -> Option<Self::Item> { + self.next(context) + } +} + +impl<G> Walker<G> for Bfs<G::NodeId, G::Map> +where + G: IntoNeighbors + Visitable, +{ + type Item = G::NodeId; + fn walk_next(&mut self, context: G) -> Option<Self::Item> { + self.next(context) + } +} + +impl<G> Walker<G> for Topo<G::NodeId, G::Map> +where + G: IntoNeighborsDirected + Visitable, +{ + type Item = G::NodeId; + fn walk_next(&mut self, context: G) -> Option<Self::Item> { + self.next(context) + } +} |