Algorithm Search⌘K

Proofs: Gabow's path-based strong component algorithm

These are the human proofs of Gabow's path-based strong component algorithm, at full length.

The path-based method pops exactly the strong components full

This proof shows: correctness.

Let G=(V,E)G = (V, E) be a directed graph; loops and parallel edges are allowed. Write x⇝yx \leadsto y when GG has a directed path from xx to yy, with x⇝xx \leadsto x always. At any moment of PATH-BASED-SCC, a vertex is new if pre=0\mathrm{pre} = 0, active if it is on SS, and done if it has a component. The call stack is the list of vertices whose VISIT has started and not ended; it is a path p1,…,php_1, \ldots, p_h of the depth-first forest, and pre\mathrm{pre} increases along it. Let B=(b1<⋯<br)B = (b_1 < \cdots < b_r) and let ρq\rho_q be the vertex with pre[ρq]=bq\mathrm{pre}[\rho_q] = b_q. The block TqT_q is the set of active xx with bq≤pre[x]<bq+1b_q \le \mathrm{pre}[x] < b_{q+1} (with br+1=∞b_{r+1} = \infty).

We show that the following hold at each moment between lines.

  • (I1) SS holds the active vertices in increasing preorder. Each ρq\rho_q is on the call stack, and every vertex on the call stack is active. If SS is not empty, b1≤preb_1 \le \mathrm{pre} of every active vertex, so the blocks partition the active vertices.
  • (I2) Any two vertices of one block reach each other.
  • (I3) If the edge (x,w)(x, w) has been scanned at line L5 and xx is active, then ww is done or ww is in the block of xx.
  • (I4) Every edge out of a done vertex ends at a done vertex.

Also, (I5) when VISIT(v)(v) reaches line L9, top(B)≤pre[v]\mathrm{top}(B) \le \mathrm{pre}[v], and pre[v]\mathrm{pre}[v] is the only entry of BB that can be ≥pre[v]\ge \mathrm{pre}[v].

At the start every vertex is new, and all claims hold trivially.

Lines L3 and L4. The new vertex vv gets the largest preorder number so far, so pushing it keeps SS in preorder, and pushing pre[v]\mathrm{pre}[v] keeps BB increasing. The new block is {v}\{v\}, and vv is on the call stack. Since pre[v]\mathrm{pre}[v] is larger than every older number, no older vertex changes block. (I2) to (I4) are untouched.

Proof of (I5). At line L4 the top of BB is pre[v]\mathrm{pre}[v]. Each child call VISIT(w)(w) from line L6 ends, by (I5) for ww and lines L9 to L11, with every entry of BB at most pre[w]\mathrm{pre}[w] and with the entry pre[w]\mathrm{pre}[w] itself removed if it was there; so its pushes are gone and all entries are again at most the entries present before the call. Line L8 only pops. So at line L9 every entry is at most pre[v]\mathrm{pre}[v], and the entries pushed before vv are smaller. This also shows the first part of (I1) for BB: after VISIT(v)(v) ends, no entry equals pre[v]\mathrm{pre}[v], so every entry belongs to a vertex still on the call stack.

Line L8. Here vv is the current vertex, the last on the call stack, and ww is active, say w∈Tqw \in T_q. By (I1) vv is in the top block TrT_r, since pre[v]≥br\mathrm{pre}[v] \ge b_r (the entry brb_r belongs to a vertex on the call stack, which is an ancestor of vv or vv). We show that all vertices of Tq∪⋯∪TrT_q \cup \cdots \cup T_r reach each other. For each jj with q≤j<rq \le j < r, the vertex ρj+1\rho_{j+1} is a descendant of ρj\rho_j in the forest, since both are on the call stack, so ρj⇝ρj+1\rho_j \leadsto \rho_{j+1}, and also ρr⇝v\rho_r \leadsto v. By (I2) each vertex of TjT_j reaches ρj\rho_j and back. So every vertex of these blocks reaches vv through ρj⇝⋯⇝ρr⇝v\rho_j \leadsto \cdots \leadsto \rho_r \leadsto v. Conversely, v→wv \to w is an edge, w⇝ρqw \leadsto \rho_q by (I2), and ρq\rho_q reaches every ρj\rho_j with j≥qj \ge q and hence every vertex of TjT_j. So the union is mutually reachable. Line L8 pops exactly br,…,bq+1b_r, \ldots, b_{q+1}, the entries greater than pre[w]\mathrm{pre}[w], because bq≤pre[w]<bq+1b_q \le \mathrm{pre}[w] < b_{q+1}. This merges Tq,…,TrT_q, \ldots, T_r into one block and keeps (I2). Merging only unites blocks, so (I3) stays true. After this step ww is in the block of vv, which gives (I3) for the edge (v,w)(v, w).

The other cases of an edge (v,w)(v, w). If ww is done, (I3) holds for this edge. If ww was new, VISIT(w)(w) runs and returns; then ww is done, or ww is active with pre[w]>pre[v]≥top(B)\mathrm{pre}[w] > \mathrm{pre}[v] \ge \mathrm{top}(B) by (I5) for the call of ww and since all entries now belong to the call stack, which ends at vv. Then vv and ww are both in the top block, and (I3) holds.

Lines L9 to L11. Suppose top(B)=pre[v]\mathrm{top}(B) = \mathrm{pre}[v]. The top block is T={x active:pre[x]≥pre[v]}T = \{x \text{ active} : \mathrm{pre}[x] \ge \mathrm{pre}[v]\}, and by (I1) these are exactly the entries of SS from vv to the top, which line L11 pops. Each x∈Tx \in T was reached after vv and before the end of VISIT(v)(v), so x=vx = v or xx is a descendant of vv whose VISIT has ended; in both cases all edges out of xx have been scanned. By (I3), each edge out of TT ends in TT or at a done vertex, and by (I4) a done vertex reaches only done vertices. So every vertex reachable from vv is in TT or done, and no done vertex reaches vv. Hence the strong component of vv lies in TT, and by (I2) it contains TT. So line L11 gives one strong component the label cc. Afterwards (I4) holds: the edges out of the new done vertices end in TT or at done vertices. (I1) holds because the popped vertices are exactly the vertices with pre≥pre[v]\mathrm{pre} \ge \mathrm{pre}[v], and vv leaves the call stack. If top(B)<pre[v]\mathrm{top}(B) < \mathrm{pre}[v], nothing changes, and vv stays active in a block whose first vertex is a proper ancestor of vv, so (I1) still holds after vv leaves the call stack.

Theorem. PATH-BASED-SCC labels each vertex with its strong component, and the labels are in reverse topological order of the condensation.

Proof. Line L2 starts VISIT at every vertex that is still new, so every vertex is reached. When the outer call VISIT(r)(r) reaches line L9, the call stack is rr alone, so by (I1) and (I5) B=(pre[r])B = (\mathrm{pre}[r]) and the test holds; every active vertex is popped. So when line L2 ends, every vertex is done, and by the case of lines L9 to L11 each label class is one strong component. Each component gets one label, because its vertices leave SS together. If an edge leads from a component CC to a different component C′C', then at the moment CC closes, every edge out of CC ends at a done vertex, so C′C' closed earlier and has a smaller label. Each line runs a bounded number of times per vertex or per edge, so the method also ends. ■\blacksquare

Back to Gabow's path-based strong component algorithm