Algorithm Search⌘K

Proofs: Manber-Myers algorithm

These are the human proofs of Manber-Myers algorithm, at full length.

Each round of Manber-Myers sorts the suffixes by twice as many symbols full

This proof shows: correctness, termination.

Let S=S[0…n−1]S = S[0 \ldots n-1] with n≥1n \ge 1, Si=S[i…n−1]S_i = S[i \ldots n-1], and SihS_i^h the prefix of length min⁡(h,n−i)\min(h, n-i) of SiS_i; for i≥ni \ge n, SihS_i^h is the empty string ε\varepsilon, which is smaller than each nonempty string. We use the split lemma proved on the suffix array page: Si2h=Sih⋅Si+hhS_i^{2h} = S_i^h \cdot S_{i+h}^h, and

Si2h<Sj2h  ⟺  Sih<Sjh, or Sih=Sjh and Si+hh<Sj+hh.(1)S_i^{2h} < S_j^{2h} \iff S_i^h < S_j^h, \text{ or } S_i^h = S_j^h \text{ and } S_{i+h}^h < S_{j+h}^h. \qquad (1)

Invariant (Ih_h). SASA is a permutation of {0,…,n−1}\{0, \ldots, n-1\} with SSA[0]h≤⋯≤SSA[n−1]hS_{SA[0]}^h \le \cdots \le S_{SA[n-1]}^h, and for each ii, B[i]B[i] is the least rank rr with SSA[r]h=SihS_{SA[r]}^h = S_i^h. So B[i]=B[j]B[i] = B[j] if and only if Sih=SjhS_i^h = S_j^h, and B[i]<B[j]B[i] < B[j] if and only if Sih<SjhS_i^h < S_j^h. Extend BB by B[i]=−1B[i] = -1 for i≥ni \ge n; then the last two statements also hold for i,j≥ni, j \ge n, with ε\varepsilon.

Initialization. Line L1 sorts by the first symbol, so SASA is ordered by Si1S_i^1. Line L2 gives each run of equal first symbols the rank of its first member. So (I1_1) holds before the first test of line L4.

Maintenance. Assume (Ih_h) before a round. For each bucket xx (a value of BB), let Px={ i:B[i]=x }P_x = \{\, i : B[i] = x \,\} and cx=∣Px∣c_x = |P_x|. By (Ih_h) the bucket occupies the ranks x,…,x+cx−1x, \ldots, x + c_x - 1.

Each position is placed exactly once, in its bucket. Line L6 places the positions ii with n−h≤i≤n−1n - h \le i \le n-1. Line L7 places j=SA[r]−hj = SA[r] - h for each rr with SA[r]≥hSA[r] \ge h, that is, each jj with 0≤j≤n−1−h0 \le j \le n - 1 - h, once, since SASA is a permutation. Together these are all positions, each once. A position ii goes to slot next[B[i]]next[B[i]], which starts at B[i]B[i] and grows by one at each placement into that bucket. Since bucket B[i]B[i] receives exactly cB[i]c_{B[i]} placements, the slots used are B[i],…,B[i]+cB[i]−1B[i], \ldots, B[i] + c_{B[i]} - 1, which are the ranks of the bucket. So line L8 makes SASA a permutation in which each bucket keeps its range of ranks, and the buckets stay in increasing order of SihS_i^h.

Inside a bucket, the order is by the second half. Take i,ji, j in the same bucket with Si+hh<Sj+hhS_{i+h}^h < S_{j+h}^h. We show that ii is placed before jj. If i+h≥ni + h \ge n, then ii is placed in line L6, before all placements of line L7, and before jj unless jj is also placed in line L6. But two different positions i,j≥n−hi, j \ge n - h in the same bucket would have Sih=SiS_i^h = S_i and Sjh=SjS_j^h = S_j of different lengths (if both are at least n−hn - h, their suffixes have length at most hh), so they are not in the same bucket. If i+h<ni + h < n, then j+h<nj + h < n too (since Sj+hh>Si+hh≥εS_{j+h}^h > S_{i+h}^h \ge \varepsilon is nonempty), both are placed in line L7, at the ranks rir_i and rjr_j of i+hi + h and j+hj + h in the old SASA. By (Ih_h), Si+hh<Sj+hhS_{i+h}^h < S_{j+h}^h implies ri<rjr_i < r_j. So ii is placed first, in a smaller slot.

So the new SASA is ordered by 2h2h-prefixes. Take ranks r<r′r < r' of the new SASA with p=SA[r]p = SA[r] and q=SA[r′]q = SA[r']. If pp and qq are in different buckets, the bucket of pp comes first, so Sph<SqhS_p^h < S_q^h and by (1) Sp2h<Sq2hS_p^{2h} < S_q^{2h}. If they are in the same bucket, the previous paragraph shows that Sp+hh≤Sq+hhS_{p+h}^h \le S_{q+h}^h (otherwise qq would have been placed first), and by (1) Sp2h≤Sq2hS_p^{2h} \le S_q^{2h}.

Line L9 gives the new buckets. By (Ih_h), B[p]=B[q]B[p] = B[q] and B[p+h]=B[q+h]B[p+h] = B[q+h] hold if and only if Sph=SqhS_p^h = S_q^h and Sp+hh=Sq+hhS_{p+h}^h = S_{q+h}^h, that is, by the split, if and only if Sp2h=Sq2hS_p^{2h} = S_q^{2h}. Since the new SASA is sorted by 2h2h-prefixes, equal 2h2h-prefixes are contiguous, and line L9 gives each run the rank of its first member. After line L10, (I2h_{2h}) holds with the new value of hh.

Termination. Each round doubles hh, so the test h<nh < n of line L4 fails after at most ⌈lg⁡n⌉\lceil \lg n \rceil rounds.

Result. The loop ends when BB has nn distinct values or when h≥nh \ge n. In the second case Sih=SiS_i^h = S_i for all ii, and different suffixes are different strings, so BB has nn distinct values in both cases. Then all hh-prefixes are different, and by (Ih_h) SSA[0]h<⋯<SSA[n−1]hS_{SA[0]}^h < \cdots < S_{SA[n-1]}^h. Two suffixes with different hh-prefixes compare like these prefixes: they differ at a position less than hh inside both, or one prefix is shorter than hh, so it is the whole suffix, and it is a proper prefix of the other suffix. Hence SSA[0]<⋯<SSA[n−1]S_{SA[0]} < \cdots < S_{SA[n-1]}, and line L11 returns the suffix array. ■\blacksquare

Back to Manber-Myers algorithm