Algorithm Search⌘K

Proofs: Amir-Lewenstein-Porat algorithm

These are the human proofs of Amir-Lewenstein-Porat algorithm, at full length.

The Amir-Lewenstein-Porat algorithm reports exactly the k-mismatch occurrences full

This proof shows: correctness.

Indices are 0-based, ∣P∣=m|P| = m, ∣T∣=n|T| = n, k≥0k \ge 0, and hih_i is the number of q∈{0,…,m−1}q \in \{0, \ldots, m-1\} with P[q]≠T[i+q]P[q] \ne T[i + q], for 0≤i≤n−m0 \le i \le n - m. The claim is that ALP-K-MISMATCH returns the set { i:0≤i≤n−m, hi≤k }\{\, i : 0 \le i \le n - m,\ h_i \le k \,\} in increasing order. If m>nm > n there is no start position, and the algorithm returns nothing. Assume m≤nm \le n from now on.

Line L1. If k≥mk \ge m, then hi≤m≤kh_i \le m \le k for every ii, so every start position is an occurrence, which is what line L1 returns. Assume k<mk < m from now on. Then m≥1m \ge 1.

The parameters. Since f≥1f \ge 1 and g=⌈2k/f⌉g = \lceil 2k / f \rceil, we have gf≥2kg f \ge 2k. Each symbol of FF occurs at least ff times in PP, so in case A line L4 can choose ff distinct positions of each of gg distinct symbols of FF. Let MM be this set of marks. Then ∣M∣=gf|M| = g f, and P[q]P[q] is one of the chosen symbols for each q∈Mq \in M.

Lemma 1: the counts of case A

After line L5, count[i]count[i] is the number of marks q∈Mq \in M with P[q]=T[i+q]P[q] = T[i + q], for 0≤i≤n−m0 \le i \le n - m.

Proof. Line L5 adds 1 to count[i]count[i] once for each pair (j,q)(j, q) with q∈Mq \in M, P[q]=T[j]P[q] = T[j] and j−q=ij - q = i. For a fixed ii, the map q↦(i+q,q)q \mapsto (i + q, q) is a bijection from the marks qq with P[q]=T[i+q]P[q] = T[i + q] onto these pairs, since j=i+qj = i + q is determined by qq, and 0≤i+q≤n−10 \le i + q \le n - 1 holds because 0≤i≤n−m0 \le i \le n - m and 0≤q≤m−10 \le q \le m - 1. □\square

Lemma 2: the filter keeps every occurrence

If hi≤kh_i \le k, then count[i]≥gf−kcount[i] \ge g f - k.

Proof. The marks with P[q]≠T[i+q]P[q] \ne T[i + q] are some of the hih_i mismatched positions, so there are at most hi≤kh_i \le k of them. By Lemma 1, count[i]≥∣M∣−k=gf−kcount[i] \ge |M| - k = g f - k. □\square

Lemma 3: the kangaroo check

KANGAROO(ii) succeeds if and only if hi≤kh_i \le k.

Proof. Let h=hih = h_i, let q1<q2<⋯<qhq_1 < q_2 < \cdots < q_h be the mismatched positions of alignment ii, and let q0=−1q_0 = -1 and qh+1=mq_{h+1} = m. We claim that for e=0,1,…e = 0, 1, \ldots, if the loop has not stopped, its iteration number e+1e + 1 starts with q=qe+1q = q_e + 1 and the counter equal to ee. This holds for e=0e = 0. In this iteration, P[q′]=T[i+q′]P[q'] = T[i + q'] for qe<q′<qe+1q_e < q' < q_{e+1}, and P[qe+1]≠T[i+qe+1]P[q_{e+1}] \ne T[i + q_{e+1}] when qe+1<mq_{e+1} < m. So the longest common prefix of P[q…m−1]P[q \ldots m-1] and T[i+q…n−1]T[i + q \ldots n-1] has length qe+1−qq_{e+1} - q, and qq becomes qe+1q_{e+1}. If e=he = h, then q=mq = m, and the check succeeds. Otherwise the counter becomes e+1e + 1; the check fails if e+1>ke + 1 > k, and else qq becomes qe+1+1q_{e+1} + 1, which proves the claim for e+1e + 1. So the check fails in iteration e+1e + 1 for the least e<he < h with e+1>ke + 1 > k, which exists if and only if h>kh > k; and when h≤kh \le k, it reaches iteration h+1h + 1 and succeeds. □\square

Each step makes one extension query, and the check fails at the latest at the (k+1)(k+1)st mismatch, so it makes at most k+1k + 1 queries. A query at q<mq < m reads the suffix of TT from i+q≤n−1i + q \le n - 1, so it is defined.

Case A is correct

Line L6 returns the ii with count[i]≥gf−kcount[i] \ge g f - k for which KANGAROO(ii) succeeds, in increasing order. By Lemma 3, every returned ii has hi≤kh_i \le k. Conversely, if hi≤kh_i \le k, Lemma 2 shows that ii passes the filter, and Lemma 3 shows that the check succeeds, so ii is returned.

Case B is correct

We show that after lines L8 and L9, match[i]=m−himatch[i] = m - h_i, the number of qq with P[q]=T[i+q]P[q] = T[i + q]. Split these qq by the symbol c=P[q]=T[i+q]c = P[q] = T[i + q].

  • If c∈Fc \in F, line L8 adds the correlation for cc, which counts at ii exactly the qq with P[q]=cP[q] = c and T[i+q]=cT[i + q] = c. Each block of TT of length 2m−12m - 1 starting at bb holds the windows of the starts i=b,…,b+m−1i = b, \ldots, b + m - 1, and the blocks start at 0,m,2m,…0, m, 2m, \ldots, so each start i≤n−mi \le n - m is computed in exactly one block. The transform computes the correlation exactly: with a number-theoretic transform modulo a prime p>mp > m each value is at most m<pm < p, and with a floating-point transform each value is rounded to the nearest integer.
  • If cc is rare, line L9 adds 1 at ii for the pair (j,q)=(i+q,q)(j, q) = (i + q, q), since T[j]=cT[j] = c is rare and P[q]=T[j]P[q] = T[j], and for no other pair with this qq, by the bijection of Lemma 1.

A pair (i,q)(i, q) with P[q]≠T[i+q]P[q] \ne T[i + q] is counted by neither line: the correlation for cc needs P[q]=T[i+q]=cP[q] = T[i + q] = c, and line L9 needs P[q]=T[j]P[q] = T[j]. So match[i]=m−himatch[i] = m - h_i, and line L10 returns exactly the ii with hi≤kh_i \le k, in increasing order.

Conclusion

Lines L3 to L10 run exactly one of the two cases, and each returns the set of occurrences. With line L1, ALP-K-MISMATCH is correct for all k≥0k \ge 0 and all strings, including the empty pattern, which line L1 handles because k≥0=mk \ge 0 = m. ■\blacksquare

Back to Amir-Lewenstein-Porat algorithm