Algorithm Search⌘K

Proofs: Karp-Rabin multiple-pattern matching

These are the human proofs of Karp-Rabin multiple-pattern matching, at full length.

KR-SET outputs exactly the occurrences of the patterns full

This proof shows: correctness, termination.

Claim. For every text T[0…n−1]T[0 \ldots n-1], every list of patterns P0,…,Pk−1P_0, \ldots, P_{k-1} and every value of rr drawn at line L1, KR-SET stops and outputs each pair (s,j)(s, j) with 0≤s≤n−∣Pj∣0 \le s \le n - |P_j| and T[s…s+∣Pj∣−1]=PjT[s \ldots s + |P_j| - 1] = P_j exactly once, and outputs no other pair.

Notation. For a string xx of length ℓ\ell, h(x)=∑i=0ℓ−1c(xi) rℓ−1−i mod ph(x) = \sum_{i=0}^{\ell-1} c(x_i)\, r^{\ell-1-i} \bmod p, with values in {0,…,p−1}\{0, \ldots, p-1\}. In the pass for a length ℓ≥1\ell \ge 1 with ℓ≤n\ell \le n, write Ws=T[s…s+ℓ−1]W_s = T[s \ldots s + \ell - 1] and ts=h(Ws)t_s = h(W_s) for 0≤s≤n−ℓ0 \le s \le n - \ell. For a distinct pattern QQ, J(Q)={j:Pj=Q}J(Q) = \{j : P_j = Q\}; the sets J(Q)J(Q) partition {0,…,k−1}\{0, \ldots, k-1\}.

Lemma 1 (the table). After line L4 in the pass for ℓ\ell, the lists of HH together contain each distinct pattern of length ℓ\ell exactly once, and QQ is in the list H[v]H[v] if and only if ∣Q∣=ℓ|Q| = \ell and v=h(Q)v = h(Q).

Proof. Line L4 visits each distinct pattern of length ℓ\ell once and appends it to the list at its own hash value, and HH is empty before, by line L3. □\square

Lemma 2 (rolling). For 0≤s<n−ℓ0 \le s < n - \ell, ((ts−c(T[s]) rℓ−1) r+c(T[s+ℓ])) mod p=ts+1\big((t_s - c(T[s])\, r^{\ell-1})\, r + c(T[s+\ell])\big) \bmod p = t_{s+1}.

Proof. Modulo pp,

(ts−c(T[s]) rℓ−1)r+c(T[s+ℓ])≡∑i=1ℓ−1c(T[s+i]) rℓ−i+c(T[s+ℓ])=∑i=0ℓ−1c(T[s+1+i]) rℓ−1−i,\Big(t_s - c(T[s])\, r^{\ell-1}\Big) r + c(T[s+\ell]) \equiv \sum_{i=1}^{\ell-1} c(T[s+i])\, r^{\ell-i} + c(T[s+\ell]) = \sum_{i=0}^{\ell-1} c(T[s+1+i])\, r^{\ell-1-i},

which is h(Ws+1)h(W_{s+1}) before reduction. The final reduction gives the representative in {0,…,p−1}\{0, \ldots, p-1\}, which is ts+1t_{s+1}. □\square

Lemma 3 (invariant). In the pass for ℓ\ell with 1≤ℓ≤n1 \le \ell \le n, each time line L9 runs for the shift ss, ht=tsht = t_s.

Proof. By induction on ss. For s=0s = 0, line L7 sets ht=h(T[0…ℓ−1])=t0ht = h(T[0 \ldots \ell-1]) = t_0. If ht=tsht = t_s at line L9 and s<n−ℓs < n - \ell, then lines L9 and L10 do not change htht, and line L11 sets htht to the left side of Lemma 2 with R=rℓ−1 mod pR = r^{\ell-1} \bmod p, so ht=ts+1ht = t_{s+1} when line L9 runs for s+1s + 1. □\square

Lemma 4 (the pass for one length). The pass for a length ℓ\ell outputs each pair (s,j)(s, j) with ∣Pj∣=ℓ|P_j| = \ell and PjP_j occurring at ss exactly once, and no other pair.

Proof. Case ℓ=0\ell = 0. Line L5 outputs (s,j)(s, j) for every ss in 0…n0 \ldots n and every jj with Pj=εP_j = \varepsilon, once each, and the pass ends. The empty pattern occurs at exactly these ss.

Case ℓ>n\ell > n. No pattern of length ℓ\ell fits in the text, so it has no occurrence, and line L6 ends the pass with no output.

Case 1≤ℓ≤n1 \le \ell \le n. Each ss in 0…n−ℓ0 \ldots n - \ell is visited once by line L8. Fix ss. By Lemma 3, line L9 goes through the list H[ts]H[t_s], which by Lemma 1 holds each distinct pattern QQ of length ℓ\ell with h(Q)=tsh(Q) = t_s once. Line L10 outputs (s,j)(s, j) for j∈J(Q)j \in J(Q) exactly when Ws=QW_s = Q.

  • Every occurrence is output. If PjP_j occurs at ss, let Q=PjQ = P_j. Then Ws=QW_s = Q, so h(Q)=tsh(Q) = t_s, so QQ is in H[ts]H[t_s], the test of line L10 succeeds, and (s,j)(s, j) is output since j∈J(Q)j \in J(Q).
  • Only occurrences are output. A pair (s,j)(s, j) is output only with some QQ in H[ts]H[t_s] such that Ws=QW_s = Q and j∈J(Q)j \in J(Q), so Pj=Q=WsP_j = Q = W_s.
  • No pair twice. For fixed ss, the pair (s,j)(s, j) can come only from Q=PjQ = P_j, which is in the list once, and jj appears once in J(Q)J(Q). □\square

Theorem. The claim holds.

Proof. Termination. Line L2 runs over finitely many lengths. In each pass, line L4 visits finitely many patterns, line L5 outputs a finite set, and lines L8 to L11 run n−ℓ+1n - \ell + 1 times with finite lists at line L9. So the algorithm stops.

Output. Each pattern index jj belongs to the pass for ℓ=∣Pj∣\ell = |P_j|, and only that pass outputs pairs with index jj, because line L5 and line L10 output only indices of patterns of the current length. By Lemma 4, that pass outputs each occurrence (s,j)(s, j) once and no non-occurrence. The value of rr is not used in this argument, so the output is the same for every base. ■\blacksquare

Remark (the error of the Monte Carlo variant). Without the comparison at line L10, the pass outputs (s,j)(s, j) for every Q∈H[ts]Q \in H[t_s]. A false pair needs a distinct pattern Q≠WsQ \ne W_s of length ℓ\ell with h(Q)=h(Ws)h(Q) = h(W_s). If TT and the patterns do not depend on rr and pp is prime, the difference h(Q)−h(Ws)h(Q) - h(W_s) is a nonzero polynomial in rr of degree at most ℓ−1\ell - 1 over Fp\mathbb{F}_p, because the codes are below pp. It has at most ℓ−1\ell - 1 roots, so this event has probability at most (ℓ−1)/p(\ell - 1)/p. The union bound over the at most nn windows and the distinct patterns of each length gives a total probability of at most n∑j(∣Pj∣−1)+/p≤nm/pn \sum_j (|P_j| - 1)^+ / p \le n m / p.

Back to Karp-Rabin multiple-pattern matching