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
>,
36 struct PostOrderFrame
<Node
, Iter
> {
45 let mut stack
= vec
![PostOrderFrame { node, iter: graph.successors(node) }
];
47 'recurse
: while let Some(frame
) = stack
.last_mut() {
48 let node
= frame
.node
;
51 while let Some(successor
) = frame
.iter
.next() {
52 if !visited
[successor
] {
53 stack
.push(PostOrderFrame { node: successor, iter: graph.successors(successor) }
);
63 pub fn reverse_post_order
<G
: DirectedGraph
+ WithSuccessors
+ WithNumNodes
>(
67 let mut vec
= post_order_from(graph
, start_node
);
72 /// A "depth-first search" iterator for a directed graph.
73 pub struct DepthFirstSearch
<'graph
, G
>
75 G
: ?Sized
+ DirectedGraph
+ WithNumNodes
+ WithSuccessors
,
79 visited
: BitSet
<G
::Node
>,
82 impl<G
> DepthFirstSearch
<'graph
, G
>
84 G
: ?Sized
+ DirectedGraph
+ WithNumNodes
+ WithSuccessors
,
86 pub fn new(graph
: &'graph G
, start_node
: G
::Node
) -> Self {
87 Self { graph, stack: vec![start_node], visited: BitSet::new_empty(graph.num_nodes()) }
91 impl<G
> Iterator
for DepthFirstSearch
<'_
, G
>
93 G
: ?Sized
+ DirectedGraph
+ WithNumNodes
+ WithSuccessors
,
97 fn next(&mut self) -> Option
<G
::Node
> {
98 let DepthFirstSearch { stack, visited, graph }
= self;
100 stack
.extend(graph
.successors(n
).filter(|&m
| visited
.insert(m
)));
105 /// The status of a node in the depth-first search.
107 /// See the documentation of `TriColorDepthFirstSearch` to see how a node's status is updated
109 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
110 pub enum NodeStatus
{
111 /// This node has been examined by the depth-first search but is not yet `Settled`.
113 /// Also referred to as "gray" or "discovered" nodes in [CLR].
115 /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
118 /// This node and all nodes reachable from it have been examined by the depth-first search.
120 /// Also referred to as "black" or "finished" nodes in [CLR].
122 /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
131 /// A depth-first search that also tracks when all successors of a node have been examined.
133 /// This is based on the DFS described in [Introduction to Algorithms (1st ed.)][CLR], hereby
134 /// referred to as **CLR**. However, we use the terminology in [`NodeStatus`] above instead of
135 /// "discovered"/"finished" or "white"/"grey"/"black". Each node begins the search with no status,
136 /// becomes `Visited` when it is first examined by the DFS and is `Settled` when all nodes
137 /// reachable from it have been examined. This allows us to differentiate between "tree", "back"
138 /// and "forward" edges (see [`TriColorVisitor::node_examined`]).
140 /// Unlike the pseudocode in [CLR], this implementation is iterative and does not use timestamps.
141 /// We accomplish this by storing `Event`s on the stack that result in a (possible) state change
142 /// for each node. A `Visited` event signifies that we should examine this node if it has not yet
143 /// been `Visited` or `Settled`. When a node is examined for the first time, we mark it as
144 /// `Visited` and push a `Settled` event for it on stack followed by `Visited` events for all of
145 /// its predecessors, scheduling them for examination. Multiple `Visited` events for a single node
146 /// may exist on the stack simultaneously if a node has multiple predecessors, but only one
147 /// `Settled` event will ever be created for each node. After all `Visited` events for a node's
148 /// successors have been popped off the stack (as well as any new events triggered by visiting
149 /// those successors), we will pop off that node's `Settled` event.
151 /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
152 /// [`NodeStatus`]: ./enum.NodeStatus.html
153 /// [`TriColorVisitor::node_examined`]: ./trait.TriColorVisitor.html#method.node_examined
154 pub struct TriColorDepthFirstSearch
<'graph
, G
>
156 G
: ?Sized
+ DirectedGraph
+ WithNumNodes
+ WithSuccessors
,
159 stack
: Vec
<Event
<G
::Node
>>,
160 visited
: BitSet
<G
::Node
>,
161 settled
: BitSet
<G
::Node
>,
164 impl<G
> TriColorDepthFirstSearch
<'graph
, G
>
166 G
: ?Sized
+ DirectedGraph
+ WithNumNodes
+ WithSuccessors
,
168 pub fn new(graph
: &'graph G
) -> Self {
169 TriColorDepthFirstSearch
{
172 visited
: BitSet
::new_empty(graph
.num_nodes()),
173 settled
: BitSet
::new_empty(graph
.num_nodes()),
177 /// Performs a depth-first search, starting from the given `root`.
179 /// This won't visit nodes that are not reachable from `root`.
180 pub fn run_from
<V
>(mut self, root
: G
::Node
, visitor
: &mut V
) -> Option
<V
::BreakVal
>
182 V
: TriColorVisitor
<G
>,
184 use NodeStatus
::{Settled, Visited}
;
186 self.stack
.push(Event { node: root, becomes: Visited }
);
189 match self.stack
.pop()?
{
190 Event { node, becomes: Settled }
=> {
191 let not_previously_settled
= self.settled
.insert(node
);
192 assert
!(not_previously_settled
, "A node should be settled exactly once");
193 if let ControlFlow
::Break(val
) = visitor
.node_settled(node
) {
198 Event { node, becomes: Visited }
=> {
199 let not_previously_visited
= self.visited
.insert(node
);
200 let prior_status
= if not_previously_visited
{
202 } else if self.settled
.contains(node
) {
208 if let ControlFlow
::Break(val
) = visitor
.node_examined(node
, prior_status
) {
212 // If this node has already been examined, we are done.
213 if prior_status
.is_some() {
217 // Otherwise, push a `Settled` event for this node onto the stack, then
218 // schedule its successors for examination.
219 self.stack
.push(Event { node, becomes: Settled }
);
220 for succ
in self.graph
.successors(node
) {
221 if !visitor
.ignore_edge(node
, succ
) {
222 self.stack
.push(Event { node: succ, becomes: Visited }
);
231 impl<G
> TriColorDepthFirstSearch
<'graph
, G
>
233 G
: ?Sized
+ DirectedGraph
+ WithNumNodes
+ WithSuccessors
+ WithStartNode
,
235 /// Performs a depth-first search, starting from `G::start_node()`.
237 /// This won't visit nodes that are not reachable from the start node.
238 pub fn run_from_start
<V
>(self, visitor
: &mut V
) -> Option
<V
::BreakVal
>
240 V
: TriColorVisitor
<G
>,
242 let root
= self.graph
.start_node();
243 self.run_from(root
, visitor
)
247 /// What to do when a node is examined or becomes `Settled` during DFS.
248 pub trait TriColorVisitor
<G
>
250 G
: ?Sized
+ DirectedGraph
,
252 /// The value returned by this search.
255 /// Called when a node is examined by the depth-first search.
257 /// By checking the value of `prior_status`, this visitor can determine whether the edge
258 /// leading to this node was a tree edge (`None`), forward edge (`Some(Settled)`) or back edge
259 /// (`Some(Visited)`). For a full explanation of each edge type, see the "Depth-first Search"
260 /// chapter in [CLR] or [wikipedia].
262 /// If you want to know *both* nodes linked by each edge, you'll need to modify
263 /// `TriColorDepthFirstSearch` to store a `source` node for each `Visited` event.
265 /// [wikipedia]: https://en.wikipedia.org/wiki/Depth-first_search#Output_of_a_depth-first_search
266 /// [CLR]: https://en.wikipedia.org/wiki/Introduction_to_Algorithms
270 _prior_status
: Option
<NodeStatus
>,
271 ) -> ControlFlow
<Self::BreakVal
> {
272 ControlFlow
::CONTINUE
275 /// Called after all nodes reachable from this one have been examined.
276 fn node_settled(&mut self, _node
: G
::Node
) -> ControlFlow
<Self::BreakVal
> {
277 ControlFlow
::CONTINUE
280 /// Behave as if no edges exist from `source` to `target`.
281 fn ignore_edge(&mut self, _source
: G
::Node
, _target
: G
::Node
) -> bool
{
286 /// This `TriColorVisitor` looks for back edges in a graph, which indicate that a cycle exists.
287 pub struct CycleDetector
;
289 impl<G
> TriColorVisitor
<G
> for CycleDetector
291 G
: ?Sized
+ DirectedGraph
,
298 prior_status
: Option
<NodeStatus
>,
299 ) -> ControlFlow
<Self::BreakVal
> {
301 Some(NodeStatus
::Visited
) => ControlFlow
::BREAK
,
302 _
=> ControlFlow
::CONTINUE
,