Algorithm Search⌘K

Proofs: Kosaraju-Sharir algorithm

These are the human proofs of Kosaraju-Sharir algorithm, at full length.

The Kosaraju-Sharir algorithm labels each strongly connected component with its own number full

This proof shows: correctness, termination.

Let G=(V,E)G = (V, E) be a directed graph, where parallel arcs and loops are allowed. Write u⇝vu \leadsto v when GG has a directed path from uu to vv, and let the components be the classes of the relation "u⇝vu \leadsto v and v⇝uv \leadsto u". Let d[v]d[v] and f[v]f[v] be the discovery and finish times of the DFS of line L1. For a set CC of vertices, let d(C)=min⁡v∈Cd[v]d(C) = \min_{v \in C} d[v] and f(C)=max⁡v∈Cf[v]f(C) = \max_{v \in C} f[v]. We use three facts from the depth-first search pages: the times are distinct; ww is a proper descendant of xx exactly when d[x]<d[w]<f[w]<f[x]d[x] < d[w] < f[w] < f[x] (the parenthesis theorem); and the white-path theorem.

Lemma 1. Let C≠DC \ne D be components, and let GG have an arc (c,e)(c, e) with c∈Cc \in C and e∈De \in D. Then f(C)>f(D)f(C) > f(D).

Proof. Let xx be the vertex of C∪DC \cup D that is discovered first, so d[x]=d(C∪D)d[x] = d(C \cup D).

Case x∈Cx \in C. Just before d[x]d[x], every vertex of C∪DC \cup D is white. Each y∈Dy \in D is reachable from xx by a path that goes inside CC from xx to cc, takes the arc (c,e)(c, e), and goes inside DD from ee to yy. The paths inside a component stay in the component (see strongly connected components), so this path is white, and by the white-path theorem yy is a descendant of xx. As y≠xy \ne x, the parenthesis theorem gives f[y]<f[x]f[y] < f[x]. So f(D)<f[x]≤f(C)f(D) < f[x] \le f(C).

Case x∈Dx \in D. As above, each vertex of DD is a descendant of xx, so f(D)=f[x]f(D) = f[x]. No vertex zz of CC is reachable from xx: else e⇝x⇝z⇝c→ee \leadsto x \leadsto z \leadsto c \to e, and CC and DD would be one component. A descendant of xx is reachable from xx by the tree path, so no vertex of CC is a descendant of xx. Let z∈Cz \in C. Then d[z]>d[x]d[z] > d[x], by the choice of xx. If d[z]<f[x]d[z] < f[x], the intervals [d[x],f[x]][d[x], f[x]] and [d[z],f[z]][d[z], f[z]] would meet, so by the parenthesis theorem one would contain the other, and as d[x]<d[z]d[x] < d[z] the vertex zz would be a descendant of xx. So d[z]>f[x]d[z] > f[x], and f[z]>d[z]>f[x]f[z] > d[z] > f[x]. Hence f(C)>f[x]=f(D)f(C) > f[x] = f(D). □\square

In GTG^{\mathsf T} the arc (c,e)(c, e) becomes (e,c)(e, c), and GTG^{\mathsf T} has the same components as GG, because u⇝vu \leadsto v in GG exactly when v⇝uv \leadsto u in GTG^{\mathsf T}. So Lemma 1 reads:

Corollary 2. If GTG^{\mathsf T} has an arc from a component DD to another component CC, then f(C)>f(D)f(C) > f(D).

Lemma 3 (what ASSIGN labels). Let UU be the set of vertices with $comp = $ NIL just before a call ASSIGN(GT,u,k)(G^{\mathsf T}, u, k) from line L7, with u∈Uu \in U. When the call returns, the vertices labelled kk are exactly the vertices vv that GTG^{\mathsf T} has a path from uu to with all its vertices in UU. No other label changes.

Proof. ASSIGN is a depth-first search of GTG^{\mathsf T} that treats labelled vertices as already visited. Line L9 labels each vertex it is called on, line L11 calls it only on unlabelled vertices, so each vertex of UU is labelled at most once and the run stops after at most ∣U∣|U| calls, each with a finite loop. Every labelled vertex is joined to uu by the chain of calls, which is a path inside UU. Conversely, let u=y0,y1,…,yju = y_0, y_1, \ldots, y_j be a path of GTG^{\mathsf T} inside UU, and assume, for a contradiction, that some yiy_i is not labelled kk at the end. Take the least such ii; then i≥1i \ge 1, and yi−1y_{i-1} was labelled kk by a call that scanned AdjT[yi−1]\mathrm{Adj}^{\mathsf T}[y_{i-1}]. At that moment yiy_i was either unlabelled, and line L11 labelled it, or already labelled. A label set before the call is impossible, as yi∈Uy_i \in U, and a label set during the call is kk. Both contradict the choice of ii. □\square

Theorem. KOSARAJU-SHARIR stops, and when it returns, comp[u]=comp[v]comp[u] = comp[v] if and only if uu and vv are in the same component. Moreover the labels 1,2,…1, 2, \ldots are given to the components in decreasing order of f(C)f(C), so comp[u]≤comp[v]comp[u] \le comp[v] for each arc (u,v)(u, v) of GG.

Proof. Lines L1 and L2 stop, and the loop of line L4 has nn steps, each of which stops by Lemma 3. We prove by induction on the steps of line L4 the invariant:

(K) The labelled vertices are the union of whole components C1,…,CkC_1, \ldots, C_k, where CiC_i is exactly the set labelled ii, and every component CC that is not labelled has f(C)<f(Ci)f(C) < f(C_i) for each i≤ki \le k. Also, every vertex ww that line L4 has already passed is labelled.

At the start, k=0k = 0, no vertex is labelled and no vertex is passed, so (K) holds. Consider a step with vertex uu. If uu is labelled, nothing changes and uu becomes passed, so (K) holds. Else let CC be the component of uu. By (K), CC is not labelled at all, because the labelled set is a union of whole components and misses uu. We first show that f[u]=f(C)f[u] = f(C) and that CC has the largest ff among the unlabelled components. Line L4 takes the vertices in decreasing order of ff, and every vertex with a larger finish time than uu is passed and so labelled. So each unlabelled vertex ww has f[w]≤f[u]f[w] \le f[u]. Applied to the vertices of CC this gives f(C)=f[u]f(C) = f[u], and applied to an unlabelled component DD it gives f(D)≤f[u]=f(C)f(D) \le f[u] = f(C), with equality only if D=CD = C, as the times are distinct.

Now we show that ASSIGN labels exactly CC. Every vertex of CC is unlabelled and joined to uu by a path of GTG^{\mathsf T} inside CC, so by Lemma 3 it gets the label k+1k + 1. Assume that some vertex outside CC gets this label. By Lemma 3, a path of GTG^{\mathsf T} from uu inside the unlabelled set reaches it, so this path has a first arc (y,z)(y, z) with y∈Cy \in C and zz in another component DD, and zz is unlabelled. By (K), DD is then a whole unlabelled component, so f(D)<f(C)f(D) < f(C) by the paragraph above. But (y,z)(y, z) is an arc of GTG^{\mathsf T} from the component CC to the component DD, so Corollary 2 gives f(D)>f(C)f(D) > f(C). This is a contradiction. So the set labelled k+1k + 1 is exactly CC, which we call Ck+1C_{k+1}, and every remaining unlabelled component DD has f(D)<f(C)=f(Ck+1)f(D) < f(C) = f(C_{k+1}). Together with (K) for C1,…,CkC_1, \ldots, C_k, which still holds because CC itself was unlabelled, the invariant holds after the step.

When the loop ends, every vertex is passed and so labelled, and by (K) each label class is exactly one component. This proves the first claim. By (K), f(C1)>f(C2)>⋯f(C_1) > f(C_2) > \cdots. For an arc (u,v)(u, v) of GG with uu and vv in different components Ci∋uC_i \ni u and Cj∋vC_j \ni v, Lemma 1 gives f(Ci)>f(Cj)f(C_i) > f(C_j), so i<ji < j. If they are in the same component, the labels are equal. ■\blacksquare

Remark on the second search. Lemma 3 holds for any search that labels exactly the vertices reachable from uu inside UU, so the theorem holds when ASSIGN is a breadth-first search or a search with an explicit stack, as in the Python implementation.

Back to Kosaraju-Sharir algorithm