Wu-Manber outputs exactly the occurrences of the patterns full
This proof shows: correctness, termination.
Claim. For every text T[0…n−1], patterns P0,…,Pk−1 and block size B≥1, WU-MANBER stops and outputs each pair (s,j) with 0≤s≤n−∣Pj∣ and T[s…s+∣Pj∣−1]=Pj exactly once, and no other pair.
Notation. After line L3, ℓ≥1 is the shortest nonempty length and 1≤B≤ℓ. For a nonempty Pj, the cut pattern is P^j=Pj[0…ℓ−1]. A window is identified by pos; its start is s(pos)=pos−ℓ+1 and its block is X(pos)=T[pos−B+1…pos], which is inside the text when ℓ−1≤pos≤n−1 since B≤ℓ.
Lemma 1 (the tables). After line L6, for every block X:
- SHIFT[X]=min({ℓ−B+1}∪{ℓ−q:B≤q≤ℓ, ∃j:P^j[q−B…q−1]=X}), so 0≤SHIFT[X]≤ℓ−B+1;
- HASH[X]={j:Pj=ε, P^j[ℓ−B…ℓ−1]=X};
- PREFIX[j]=Pj[0…B−1] for every nonempty Pj.
Proof. Line L4 sets every entry of SHIFT to ℓ−B+1, and line L5 lowers the entry of each block of each cut pattern, ending at q, to ℓ−q when smaller; the blocks visited are exactly those of the set in item 1. Line L6 appends each nonempty index once to the list of its last cut block, and stores the prefix. □
Lemma 2 (a zero-shift window). Let SHIFT[X(pos)]=0 and s=s(pos). Lines L13 and L14 output exactly the pairs (s,j) with Pj nonempty and occurring at s, each once.
Proof. If a nonempty Pj occurs at s, then s+∣Pj∣≤n, T[s…s+ℓ−1]=P^j, and so X(pos)=T[pos−B+1…pos]=P^j[ℓ−B…ℓ−1]. By Lemma 1, j∈HASH[X(pos)]. The three tests of line L14 succeed: the first B characters agree because B≤ℓ≤∣Pj∣, the length fits, and the whole pattern agrees. So (s,j) is output. Conversely, line L14 outputs (s,j) only after it has checked s+∣Pj∣≤n and T[s…s+∣Pj∣−1]=Pj, so the pair is an occurrence. Each j appears once in HASH[X(pos)], so the pair is output once by this window. □
Lemma 3 (safe shift). Let d=SHIFT[X(pos)]>0 and s=s(pos). No nonempty pattern occurs at any start s+δ with 0≤δ<d.
Proof. Suppose Pj occurs at s+δ with 0≤δ<d. Then T[s+δ…s+δ+ℓ−1]=P^j, and this range ends at pos+δ.
- If δ≤ℓ−B, let q=ℓ−δ, so B≤q≤ℓ. The block X(pos) occupies pos−B+1…pos, which is the range of indices q−B…q−1 of P^j in this occurrence, since s+δ+q−1=pos and q−B≥0. So P^j[q−B…q−1]=X(pos), and Lemma 1 gives d≤ℓ−q=δ, a contradiction.
- If δ≥ℓ−B+1, then d>δ≥ℓ−B+1, which contradicts d≤ℓ−B+1 from Lemma 1. □
Theorem. The claim holds.
Proof. Empty patterns. Line L1 outputs (s,j) for all s∈{0,…,n} and every empty Pj, exactly their occurrences, once each. Later lines output only nonempty patterns, since only they are in HASH. If all patterns are empty, line L2 stops.
Termination. Each pass of the loop of line L8 increases pos by SHIFT[X]≥1 at line L10 or by 1 at line L15, and the inner loop of line L13 is over a finite list. So the loop ends.
Nonempty patterns. Let pos1<pos2<⋯<posr be the windows visited, with pos1=ℓ−1, so the starts st=s(post) begin at s1=0. Each window outputs only pairs with the start st, so different windows output different pairs, and by Lemma 2 no pair is output twice. Let Pj be nonempty and occur at s; then 0≤s≤n−∣Pj∣≤n−ℓ. Let t be the largest index with st≤s; it exists since s1=0. The step taken after window t carries the start from st to a value above s: if window t+1 exists, its start is above s by the choice of t; if t=r, the loop ended because the next value of pos exceeds n−1, so the next start exceeds n−ℓ≥s.
- If window t had a zero shift, the next start is st+1>s, so s=st and Lemma 2 outputs (s,j).
- If window t had a shift d>0, the next start, or the end of the loop, lies beyond s, so st≤s<st+d, and Lemma 3 says that no nonempty pattern occurs at s, a contradiction.
So every occurrence of a nonempty pattern is output exactly once, and only occurrences are output. ■