1 use super::{DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors}
;
2 use rustc_index
::bit_set
::BitSet
;
3 use rustc_index
::vec
::IndexVec
;
4 use std
::ops
::ControlFlow
;
9 pub fn post_order_from
<G
: DirectedGraph
+ WithSuccessors
+ WithNumNodes
>(
13 post_order_from_to(graph
, start_node
, None
)
16 pub fn post_order_from_to
<G
: DirectedGraph
+ WithSuccessors
+ WithNumNodes
>(
19 end_node
: Option
<G
::Node
>,
21 let mut visited
: IndexVec
<G
::Node
, bool
> = IndexVec
::from_elem_n(false, graph
.num_nodes());
22 let mut result
: Vec
<G
::Node
> = Vec
::with_capacity(graph
.num_nodes());
23 if let Some(end_node
) = end_node
{
24 visited
[end_node
] = true;
26 post_order_walk(graph
, start_node
, &mut result
, &mut visited
);
30 fn post_order_walk
<G
: DirectedGraph
+ WithSuccessors
+ WithNumNodes
>(
33 result
: &mut Vec
<G
::Node
>,
34 visited
: &mut IndexVec
<G
::Node
, bool
>,
41 for successor
in graph
.successors(node
) {
42 post_order_walk(graph
, successor
, result
, visited
);
48 pub fn reverse_post_order
<G
: DirectedGraph
+ WithSuccessors
+ WithNumNodes
>(
52 let mut vec
= post_order_from(graph
, start_node
);
57 /// A "depth-first search" iterator for a directed graph.
58 pub struct DepthFirstSearch
<'graph
, G
>
60 G
: ?Sized
+ DirectedGraph
+ WithNumNodes
+ WithSuccessors
,
64 visited
: BitSet
<G
::Node
>,
67 impl<G
> DepthFirstSearch
<'graph
, G
>
69 G
: ?Sized
+ DirectedGraph
+ WithNumNodes
+ WithSuccessors
,
71 pub fn new(graph
: &'graph G
, start_node
: G
::Node
) -> Self {
72 Self { graph, stack: vec![start_node], visited: BitSet::new_empty(graph.num_nodes()) }
76 impl<G
> Iterator
for DepthFirstSearch
<'_
, G
>
78 G
: ?Sized
+ DirectedGraph
+ WithNumNodes
+ WithSuccessors
,
82 fn next(&mut self) -> Option
<G
::Node
> {
83 let DepthFirstSearch { stack, visited, graph }
= self;
85 stack
.extend(graph
.successors(n
).filter(|&m
| visited
.insert(m
)));
90 /// The status of a node in the depth-first search.
92 /// See the documentation of `TriColorDepthFirstSearch` to see how a node's status is updated
94 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
96 /// This node has been examined by the depth-first search but is not yet `Settled`.
98 /// Also referred to as "gray" or "discovered" nodes in [CLR].
100 /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
103 /// This node and all nodes reachable from it have been examined by the depth-first search.
105 /// Also referred to as "black" or "finished" nodes in [CLR].
107 /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
116 /// A depth-first search that also tracks when all successors of a node have been examined.
118 /// This is based on the DFS described in [Introduction to Algorithms (1st ed.)][CLR], hereby
119 /// referred to as **CLR**. However, we use the terminology in [`NodeStatus`] above instead of
120 /// "discovered"/"finished" or "white"/"grey"/"black". Each node begins the search with no status,
121 /// becomes `Visited` when it is first examined by the DFS and is `Settled` when all nodes
122 /// reachable from it have been examined. This allows us to differentiate between "tree", "back"
123 /// and "forward" edges (see [`TriColorVisitor::node_examined`]).
125 /// Unlike the pseudocode in [CLR], this implementation is iterative and does not use timestamps.
126 /// We accomplish this by storing `Event`s on the stack that result in a (possible) state change
127 /// for each node. A `Visited` event signifies that we should examine this node if it has not yet
128 /// been `Visited` or `Settled`. When a node is examined for the first time, we mark it as
129 /// `Visited` and push a `Settled` event for it on stack followed by `Visited` events for all of
130 /// its predecessors, scheduling them for examination. Multiple `Visited` events for a single node
131 /// may exist on the stack simultaneously if a node has multiple predecessors, but only one
132 /// `Settled` event will ever be created for each node. After all `Visited` events for a node's
133 /// successors have been popped off the stack (as well as any new events triggered by visiting
134 /// those successors), we will pop off that node's `Settled` event.
136 /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
137 /// [`NodeStatus`]: ./enum.NodeStatus.html
138 /// [`TriColorVisitor::node_examined`]: ./trait.TriColorVisitor.html#method.node_examined
139 pub struct TriColorDepthFirstSearch
<'graph
, G
>
141 G
: ?Sized
+ DirectedGraph
+ WithNumNodes
+ WithSuccessors
,
144 stack
: Vec
<Event
<G
::Node
>>,
145 visited
: BitSet
<G
::Node
>,
146 settled
: BitSet
<G
::Node
>,
149 impl<G
> TriColorDepthFirstSearch
<'graph
, G
>
151 G
: ?Sized
+ DirectedGraph
+ WithNumNodes
+ WithSuccessors
,
153 pub fn new(graph
: &'graph G
) -> Self {
154 TriColorDepthFirstSearch
{
157 visited
: BitSet
::new_empty(graph
.num_nodes()),
158 settled
: BitSet
::new_empty(graph
.num_nodes()),
162 /// Performs a depth-first search, starting from the given `root`.
164 /// This won't visit nodes that are not reachable from `root`.
165 pub fn run_from
<V
>(mut self, root
: G
::Node
, visitor
: &mut V
) -> Option
<V
::BreakVal
>
167 V
: TriColorVisitor
<G
>,
169 use NodeStatus
::{Settled, Visited}
;
171 self.stack
.push(Event { node: root, becomes: Visited }
);
174 match self.stack
.pop()?
{
175 Event { node, becomes: Settled }
=> {
176 let not_previously_settled
= self.settled
.insert(node
);
177 assert
!(not_previously_settled
, "A node should be settled exactly once");
178 if let ControlFlow
::Break(val
) = visitor
.node_settled(node
) {
183 Event { node, becomes: Visited }
=> {
184 let not_previously_visited
= self.visited
.insert(node
);
185 let prior_status
= if not_previously_visited
{
187 } else if self.settled
.contains(node
) {
193 if let ControlFlow
::Break(val
) = visitor
.node_examined(node
, prior_status
) {
197 // If this node has already been examined, we are done.
198 if prior_status
.is_some() {
202 // Otherwise, push a `Settled` event for this node onto the stack, then
203 // schedule its successors for examination.
204 self.stack
.push(Event { node, becomes: Settled }
);
205 for succ
in self.graph
.successors(node
) {
206 if !visitor
.ignore_edge(node
, succ
) {
207 self.stack
.push(Event { node: succ, becomes: Visited }
);
216 impl<G
> TriColorDepthFirstSearch
<'graph
, G
>
218 G
: ?Sized
+ DirectedGraph
+ WithNumNodes
+ WithSuccessors
+ WithStartNode
,
220 /// Performs a depth-first search, starting from `G::start_node()`.
222 /// This won't visit nodes that are not reachable from the start node.
223 pub fn run_from_start
<V
>(self, visitor
: &mut V
) -> Option
<V
::BreakVal
>
225 V
: TriColorVisitor
<G
>,
227 let root
= self.graph
.start_node();
228 self.run_from(root
, visitor
)
232 /// What to do when a node is examined or becomes `Settled` during DFS.
233 pub trait TriColorVisitor
<G
>
235 G
: ?Sized
+ DirectedGraph
,
237 /// The value returned by this search.
240 /// Called when a node is examined by the depth-first search.
242 /// By checking the value of `prior_status`, this visitor can determine whether the edge
243 /// leading to this node was a tree edge (`None`), forward edge (`Some(Settled)`) or back edge
244 /// (`Some(Visited)`). For a full explanation of each edge type, see the "Depth-first Search"
245 /// chapter in [CLR] or [wikipedia].
247 /// If you want to know *both* nodes linked by each edge, you'll need to modify
248 /// `TriColorDepthFirstSearch` to store a `source` node for each `Visited` event.
250 /// [wikipedia]: https://en.wikipedia.org/wiki/Depth-first_search#Output_of_a_depth-first_search
251 /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
255 _prior_status
: Option
<NodeStatus
>,
256 ) -> ControlFlow
<Self::BreakVal
> {
257 ControlFlow
::CONTINUE
260 /// Called after all nodes reachable from this one have been examined.
261 fn node_settled(&mut self, _node
: G
::Node
) -> ControlFlow
<Self::BreakVal
> {
262 ControlFlow
::CONTINUE
265 /// Behave as if no edges exist from `source` to `target`.
266 fn ignore_edge(&mut self, _source
: G
::Node
, _target
: G
::Node
) -> bool
{
271 /// This `TriColorVisitor` looks for back edges in a graph, which indicate that a cycle exists.
272 pub struct CycleDetector
;
274 impl<G
> TriColorVisitor
<G
> for CycleDetector
276 G
: ?Sized
+ DirectedGraph
,
283 prior_status
: Option
<NodeStatus
>,
284 ) -> ControlFlow
<Self::BreakVal
> {
286 Some(NodeStatus
::Visited
) => ControlFlow
::BREAK
,
287 _
=> ControlFlow
::CONTINUE
,