Algorithm Search⌘K

Proofs: Greedy superstring merging

These are the human proofs of Greedy superstring merging, at full length.

GREEDY-SUPERSTRING returns a superstring and equals greedy merging full

This proof shows: correctness, termination.

Notation. Strings are over an alphabet with equality of letters only; indices are 0-based. For strings x,yx, y, ov(x,y)\mathrm{ov}(x, y) is the length of the longest suffix of xx that is a prefix of yy. After line L1 the list s0,…,sm−1s_0, \ldots, s_{m-1} has no repeats and no string inside another (substring-free), and w(i,j)=ov(si,sj)w(i, j) = \mathrm{ov}(s_i, s_j) for i≠ji \ne j.

Lemma 1. If x≠yx \ne y are in a substring-free list, then ov(x,y)<min⁡(∣x∣,∣y∣)\mathrm{ov}(x, y) < \min(|x|, |y|).

Proof. An overlap of length ∣y∣|y| makes yy a suffix of xx, and one of length ∣x∣|x| makes xx a prefix of yy; both are excluded. □\square

Lemma 2 (removed strings are covered). Each input string occurs in some sis_i.

Proof. A repeat of a string is covered by the copy that L1 keeps or by what covers that copy, so consider a removed string xx. It occurs inside a different string yy of the list, and then ∣y∣>∣x∣|y| > |x|, since a different string of the same length cannot contain xx. If yy is removed too, repeat the argument with yy. The lengths grow strictly, so this stops at a kept string, and occurrence is transitive. □\square

Invariant of the scan. Before and after each step of line L4: the accepted edges form vertex-disjoint paths (chains) covering all mm vertices; next[i]=nil\mathit{next}[i] = \mathrm{nil} exactly for the tails, prev[j]=nil\mathit{prev}[j] = \mathrm{nil} exactly for the heads; head[t]\mathit{head}[t] is the head of the chain with tail tt, and tail[h]\mathit{tail}[h] the tail of the chain with head hh.

Initially each vertex is a chain alone, and head[t]=t\mathit{head}[t] = t, tail[h]=h\mathit{tail}[h] = h. An accepted edge (i,j)(i, j) has ii a tail, jj a head, and head[i]≠j\mathit{head}[i] \ne j, so the chain C1C_1 ending at ii and the chain C2C_2 starting at jj differ; the edge joins them into one path with head head[i]\mathit{head}[i] and tail tail[j]\mathit{tail}[j], and line L6 records these two values. The other chains do not change. A rejected edge changes nothing.

Lemma 3 (one chain at the end). After the scan there is exactly one chain.

Proof. Suppose there are two chains A≠BA \ne B at the end; let tt be the tail of AA and hh the head of BB. The pair (t,h)(t, h) was scanned, and t≠ht \ne h. Chains only merge, and next\mathit{next}, prev\mathit{prev} are never reset, so at that time tt was a tail, hh a head, and they were in different chains (otherwise they would be in the same chain at the end). So head[t]≠h\mathit{head}[t] \ne h, and line L5 accepted (t,h)(t, h), which makes next[t]≠nil\mathit{next}[t] \ne \mathrm{nil} at the end, a contradiction. □\square

Termination. Line L4 scans the finite list of m(m−1)m(m - 1) pairs. By Lemma 3 the accepted edges form one path h0→h1→⋯→hm−1h_0 \to h_1 \to \cdots \to h_{m-1}; line L7 finds its unique head h0h_0, and line L8 runs m−1m - 1 times.

Lemma 4 (the spelling). After the step of line L8 that reaches hrh_r, RR ends with shrs_{h_r} and contains sh0,…,shrs_{h_0}, \ldots, s_{h_r}, and ∣R∣=∑q≤r∣shq∣−∑q<rw(hq,hq+1)|R| = \sum_{q \le r} |s_{h_q}| - \sum_{q < r} w(h_q, h_{q+1}).

Proof. True for r=0r = 0. The step appends shr+1s_{h_{r+1}} without its prefix of length k=w(hr,hr+1)k = w(h_r, h_{r+1}). That prefix is a suffix of shrs_{h_r}, hence of RR, so the new RR ends with shr+1s_{h_{r+1}}, and its length grows by ∣shr+1∣−k|s_{h_{r+1}}| - k. □\square

With Lemma 2, the output contains every input string. For m=0m = 0 the list is empty; we return the empty string, which is correct.

Lemma 5 (inherited overlaps). Let LL be a substring-free list, let x,y∈Lx, y \in L with ov(x,y)=k\mathrm{ov}(x, y) = k maximal over all pairs of distinct strings of LL, and let z=x⋅y[k..]z = x \cdot y[k..]. Then for each u∈L∖{x,y}u \in L \setminus \{x, y\}: uu does not occur in zz, zz does not occur in uu, ov(z,u)=ov(y,u)\mathrm{ov}(z, u) = \mathrm{ov}(y, u) and ov(u,z)=ov(u,x)\mathrm{ov}(u, z) = \mathrm{ov}(u, x).

Proof. zz is longer than xx, which is not inside uu, so zz is not inside uu. If uu occurs in zz at index pp, it is not inside xx, so it ends after ∣x∣−1|x| - 1; it is not inside yy, which occupies the indices from ∣x∣−k|x| - k on, so p<∣x∣−kp < |x| - k. Then the suffix of xx from pp, of length ∣x∣−p>k|x| - p > k, is a prefix of uu, and ov(x,u)>k\mathrm{ov}(x, u) > k, against the choice of kk. For the overlaps: a suffix of zz that is a prefix of uu has length less than ∣y∣|y|, otherwise yy, a suffix of zz, would be inside uu (as a suffix of that prefix). So it is a suffix of yy, and ov(z,u)=ov(y,u)\mathrm{ov}(z, u) = \mathrm{ov}(y, u). Symmetrically, a prefix of zz that is a suffix of uu has length less than ∣x∣|x|, so it is a prefix of xx, and ov(u,z)=ov(u,x)\mathrm{ov}(u, z) = \mathrm{ov}(u, x). □\square

Equivalence with greedy merging. Consider the string form: keep the list of chains, each spelled as a string, and at each step merge the pair of chains (A,B)(A, B) with the largest overlap of their strings, ties broken by the smaller tail of AA, then the smaller head of BB. By Lemma 5 and induction on the number of merges, the list of chain strings stays substring-free, and the overlap of the string of AA with the string of BB equals w(tail(A),head(B))w(\mathrm{tail}(A), \mathrm{head}(B)). So the string form chooses, at each step, the valid edge (from a tail to the head of another chain) that is first in the order of line L3. The scan does the same: an edge rejected at line L5 stays invalid forever, since tails stop being tails, heads stop being heads, and chains only merge; so the next accepted edge is the first valid edge in the order. Both forms accept the same edges in the same order and spell the same string. ■\blacksquare

Back to Greedy superstring merging