Algorithm Search⌘K

Proofs: Italiano's dynamic transitive closure algorithm

These are the human proofs of Italiano's dynamic transitive closure algorithm, at full length.

Italiano's reachability trees stay exact under insertions, and under deletions in a DAG full

This proof shows: correctness.

Write R(x)R(x) for the set of vertices reachable from xx in the current graph, with x∈R(x)x \in R(x). The invariant is:

(T) For every xx, desc(x)\mathrm{desc}(x) is a tree rooted at xx with vertex set R(x)R(x), and every tree edge from a parent pp to a child ww is an edge (p,w)(p, w) of the graph.

If (T) holds, line L5 is correct, and line L6 returns a path of graph edges from xx to yy, because following parents from yy in a rooted tree ends at the root. For the empty graph, every tree is the single vertex xx, and (T) holds.

Insertions

Lemma 1. Let G′G' be GG with the new edge (i,j)(i, j), and R′R' the reachable sets in G′G'. If i∈R(x)i \in R(x), then R′(x)=R(x)∪R(j)R'(x) = R(x) \cup R(j). Otherwise R′(x)=R(x)R'(x) = R(x).

Proof. A path in G′G' that does not use (i,j)(i, j) is a path in GG. A path from xx to yy that uses (i,j)(i, j) reaches ii in GG before its first use, so i∈R(x)i \in R(x), and after its last use it is a path in GG from jj to yy, so y∈R(j)y \in R(j). So R′(x)⊆R(x)∪R(j)R'(x) \subseteq R(x) \cup R(j) when i∈R(x)i \in R(x), and R′(x)=R(x)R'(x) = R(x) when no path from xx reaches ii, since then the new edge is never used. The reverse inclusion is clear. □\square

Note that R(j)R(j) does not change in the insertion when it matters: by Lemma 1 with x=jx = j, R′(j)=R(j)∪R(j)R'(j) = R(j) \cup R(j) if i∈R(j)i \in R(j), so R′(j)=R(j)R'(j) = R(j) in all cases. Line L2 never picks x=jx = j, because j∈desc(j)j \in \mathrm{desc}(j), so desc(j)\mathrm{desc}(j) is not changed while it is read.

Lemma 2. If (T) holds before INSERT(i,j)(i, j), then it holds after it.

Proof. Fix xx. If i∉desc(x)i \notin \mathrm{desc}(x), then i∉R(x)i \notin R(x) and R′(x)=R(x)R'(x) = R(x) by Lemma 1, and desc(x)\mathrm{desc}(x) is not changed. If j∈desc(x)j \in \mathrm{desc}(x), then R(j)⊆R(x)R(j) \subseteq R(x), since reachability is transitive, so again R′(x)=R(x)R'(x) = R(x) and nothing changes.

Otherwise line L3 walks desc(j)\mathrm{desc}(j) from jj. We claim that after the walk the vertex set of desc(x)\mathrm{desc}(x) is R(x)∪R(j)R(x) \cup R(j). Every vertex added is in desc(j)\mathrm{desc}(j), so in R(j)R(j). Conversely let w∈R(j)∖R(x)w \in R(j) \setminus R(x). Its path in desc(j)\mathrm{desc}(j) from jj is j=w0,w1,…,wk=wj = w_0, w_1, \ldots, w_k = w. No wtw_t is in R(x)R(x): otherwise ww, which is reachable from wtw_t by tree edges, would be in R(x)R(x) by transitivity. So none of w0,…,wkw_0, \ldots, w_k was in desc(x)\mathrm{desc}(x) before the walk. The walk reaches w0w_0 first. When the walk reaches wtw_t, it is not yet in desc(x)\mathrm{desc}(x), because each vertex of the tree desc(j)\mathrm{desc}(j) is reached only from its parent, at most once; so it is added and its children, including wt+1w_{t+1}, are pushed. By induction, ww is added. Pruned vertices are in desc(x)\mathrm{desc}(x) already, and every vertex is added at most once since the walk skips vertices already present.

Each added vertex ww gets as parent a vertex already in desc(x)\mathrm{desc}(x): ii for w=jw = j, and otherwise its parent in desc(j)\mathrm{desc}(j), which was added just before ww was pushed. So the parents point to earlier vertices, and desc(x)\mathrm{desc}(x) is still a tree rooted at xx. The new tree edges are (i,j)(i, j), a graph edge, and edges of desc(j)\mathrm{desc}(j), graph edges by (T). With Lemma 1, the vertex set is R′(x)R'(x), and (T) holds for xx. □\square

Deletions in a DAG

Now the graph is acyclic, and π\pi is a topological numbering: π(z)<π(w)\pi(z) < \pi(w) for every edge (z,w)(z, w). Edges are only deleted, so π\pi stays a topological numbering, and reachable sets only shrink. For deletions we add a second invariant.

(P) For every xx and every w∈R(x)∖{x}w \in R(x) \setminus \{x\}, the pointer of ww in desc(x)\mathrm{desc}(x) is at its tree parent pp, the edge (p,w)(p, w) is present, and every in-edge of ww before the pointer either is deleted or comes from a vertex z∉R(x)z \notin R(x).

The construction sets every pointer at the first present in-edge from a vertex of R(x)R(x), so (P) holds at the start. The resulting parent pointers go from larger to smaller π\pi, so they form a tree rooted at xx, and (T) holds.

Lemma 3. If (T) and (P) hold before DELETE(u,v)(u, v), then they hold after it.

Proof. Let R′R' be the new reachable sets. Fix xx. If uu is not the parent of vv in desc(x)\mathrm{desc}(x), the tree uses no deleted edge, so it is still a tree of graph edges and spans a set of vertices reachable in the new graph; since R′(x)⊆R(x)R'(x) \subseteq R(x), it spans R′(x)R'(x). The pointers do not move, and the edges before them still satisfy (P), since sets only shrink. So assume u=parx(v)u = \mathrm{par}_x(v).

Call a vertex settled when it is taken from QQ and processed. We prove, by induction in the order of processing, that when ww is taken from QQ:

  • (a) every vertex zz with π(z)<π(w)\pi(z) < \pi(w) that is marked reachable in desc(x)\mathrm{desc}(x) is in R′(x)R'(x), and every vertex not marked reachable is not in R′(x)R'(x);
  • (b) ww is hooked again if and only if w∈R′(x)w \in R'(x).

The vertices put into QQ are vv and the children of removed vertices. Each child has a larger number than its parent, and QQ returns the least number, so the numbers taken from QQ increase. A vertex is marked not reachable when it enters QQ, and its descendants keep their marks until their own turn.

For (a): a vertex zz with π(z)<π(w)\pi(z) < \pi(w) that is marked reachable is either settled and hooked, so in R′(x)R'(x) by (b) for zz, or it was never an orphan. In the second case its whole tree path from xx consists of vertices that were never orphans, since an orphan's descendants all become orphans until the orphan is hooked again, and a hooked orphan is in R′(x)R'(x). So its tree path uses only present edges and z∈R′(x)z \in R'(x). A vertex marked not reachable is either outside R(x)R(x), and so outside R′(x)R'(x), or it was settled and removed, so outside R′(x)R'(x) by (b).

For (b): the in-neighbors zz of ww have π(z)<π(w)\pi(z) < \pi(w), so by (a) the test z∈desc(x)z \in \mathrm{desc}(x) of line L9 is exactly z∈R′(x)z \in R'(x). If w∈R′(x)w \in R'(x), a path from xx to ww in the new graph ends with a present edge (z,w)(z, w) with z∈R′(x)z \in R'(x). That edge is at or after the pointer: every edge before it, by (P), was deleted or came from a vertex outside R(x)⊇R′(x)R(x) \supseteq R'(x). So line L9 finds an edge and hooks ww. If w∉R′(x)w \notin R'(x), every present in-edge comes from a vertex outside R′(x)R'(x), so no edge is found and ww is removed. Every edge passed by the pointer is deleted or comes from outside R′(x)R'(x), so (P) holds for ww afterwards.

When QQ is empty, every orphan has been settled. A vertex of R(x)R(x) that never became an orphan keeps its tree path, which uses present edges, so it is in R′(x)R'(x). Every vertex of R(x)∖R′(x)R(x) \setminus R'(x) lies below the deleted tree edge, so it became an orphan and was removed by (b). So the marked vertices are exactly R′(x)R'(x). The parents of hooked vertices have smaller numbers and are in R′(x)R'(x), so the parent pointers again form a tree rooted at xx of present edges. Hence (T) and (P) hold. □\square

Theorem. Under insertions in any digraph, and under deletions in a DAG, every query REACHABLE(x,y)(x, y) returns whether y∈R(x)y \in R(x), and PATH(x,y)(x, y) returns a path of graph edges from xx to yy when there is one.

Proof. By induction on the updates, (T) holds after each insertion by Lemma 2, and (T) and (P) hold after each deletion by Lemma 3. Queries read desc(x)\mathrm{desc}(x), which by (T) has vertex set R(x)R(x) and consists of graph edges. ■\blacksquare

Back to Italiano's dynamic transitive closure algorithm