Proofs: DFS-based cycle detection
These are the human proofs of DFS-based cycle detection, at full length.
DFS-CYCLE returns a cycle if and only if the graph has one full
This proof shows: correctness, termination.
Let have vertices and edges, directed or undirected, with parallel edges and self-loops allowed. We use the facts proved for depth-first search: each vertex goes from white to gray to black, VISIT runs at most once for each vertex, and a call that starts while another call is active ends before it. The extra line L8 only stops the run early, so these facts hold until the run stops.
Termination. VISIT is called only when is white, and line L6 makes it gray, so there are at most calls, each with a finite loop. CYCLE stops by Lemma 1 below. So DFS-CYCLE stops.
Lemma 1 (the gray path). At each moment, let be the gray vertices in the order in which they became gray. Then was called at line L4, and for , is an edge from to . The vertex whose loop runs now is .
Proof. The gray vertices are the vertices with an active call, and the active calls form the call stack, with at the bottom and at the top. The bottom call comes from line L4. For , the call of was made at line L9 in the loop of , the call just below it, while scanning a pair , and line L9 set . So goes from to .
Lemma 2 (the output is a cycle). If line L8 returns CYCLE, the result is a cycle.
Proof. At that moment by Lemma 1, and for some , because is gray. Starting at , each step of line L12 sets to the tail of , which is when . So the loop runs times, stops at , and . This walk goes . Its vertices are distinct. Its tree edges are distinct, because each one was the discovery edge of a different vertex.
It remains to see that is not one of the tree edges. If , then , and goes from to , so it is a self-loop and the walk is a cycle of length 1. If , then starts at . In the directed case each tree edge starts at , so is not a tree edge. In the undirected case, among the tree edges of the walk only has as an end, because joins and . Line L7 skips in the loop of , so . If , the walk is along two different edges, which is a cycle of length 2. In all cases the edges of are distinct and the vertices are distinct, so is a cycle.
Lemma 3 (directed: a cycle is found). If is directed and has a cycle, DFS-CYCLE does not return NIL.
Proof. Suppose it returns NIL. Then line L8 never fired, so every vertex was visited and every list was scanned in full. Let be a cycle of and let be the vertex of that became gray first. At that moment, all other vertices of are white, so minus its last edge is a path of white vertices from to the vertex whose edge goes to . By the white-path theorem, becomes gray during the call of (if , the edge is a self-loop). While the call of runs, the call of is still active, so is gray, and the loop of scans before the call of ends. At that scan, line L8 sees gray and returns. This contradicts the assumption.
Lemma 4 (undirected: a cycle is found). If is undirected and has a cycle, DFS-CYCLE does not return NIL.
Proof. Suppose it returns NIL, so every list was scanned in full. Take any edge that is not a tree edge, with ends and , and say became gray no later than . If is a self-loop at , its scan from sees gray and returns, a contradiction. Otherwise, consider the scan of in the loop of . If is white then, line L9 makes the tree edge , a contradiction. If is gray then, line L8 returns, a contradiction. If is black then, became gray and black while was gray, so the loop of scanned while was gray. That scan was not skipped, since is not a tree edge, and line L8 returns, a contradiction. So every edge is a tree edge. Tree edges form a forest (Lemma 3 of the depth-first search proof), so is a forest and has no cycle.
Theorem. DFS-CYCLE stops. It returns a list of edges that forms a cycle if has a cycle, and it returns NIL if has none. It works on directed and undirected multigraphs with self-loops.
Proof. Termination is shown above. If the run returns a list, the list comes from line L8 and is a cycle by Lemma 2, so has a cycle. If it returns NIL, then has no cycle by Lemma 3 in the directed case and Lemma 4 in the undirected case.