Galil-Seiferas outputs exactly the valid shifts full
This proof shows: correctness, termination.
Claim. For a text T[0…n−1], a pattern P[0…m−1] over any alphabet with equality tests, and an integer k≥3, GALIL-SEIFERAS(T,P) stops and outputs exactly the shifts p, 0≤p≤n−m, with T[p…p+m−1]=P, in increasing order.
For m=0, line L2 outputs every shift, so let m≥1. Throughout, v=P[s…m−1] for the current value of s.
Definitions and facts. For a string w, per(w) is its smallest period. For 1≤p≤∣v∣, reach(p) is the length of the longest prefix of v with period p; so reach(p)≥p, and if reach(p)<∣v∣ then v[reach(p)]=v[reach(p)−p]. A length p is a prefix period if v[0…p−1] is primitive and reach(p)≥kp, and good if reach(p)≥kp or reach(p)=∣v∣. We use three standard facts.
(F1) If π=per(w) then w[0…π−1] is primitive: if it were yr with r≥2, then w, a prefix of y∞, would have the smaller period ∣y∣.
(F2) Fine and Wilf: if w has periods a and b and ∣w∣≥a+b−gcd(a,b), it has period gcd(a,b).
(F3) If z=v[0…p−1] is primitive, a prefix w of v with period p and ∣w∣≥p has no period g<p dividing p; with (F2), if w also has a period d and ∣w∣≥p+d, then p divides d. Indeed z would have period g∣p, g<p, making it a power.
(F4) If v[0…L−1] has period d and L≥kd, then π=per(v[0…L−1])≤d is a prefix period, by (F1) and reach(π)≥L≥kπ.
The properties of the factorization. We show that whenever FACTORIZE returns (s,p1,q1):
(S1) every prefix period of v equals p1;
(S2) p1+q1=reach(p1);
(S3) p1=per(v[0…p1+q1−1]).
Write R=p1+q1. The invariant of lines L11 to L15 and of the loop of lines L24 to L29, at the start of lines L12 and L25, is
(G) no p<p1 is good for v;
and after line L12 or L25 has run, R=reach(p1), because q1 was 0 or already reach(p1)−p1 when the loop started, and the loop stops at the end of v or at the first mismatch.
Lemma 1 (skip). Assume (G), R=reach(p1)<kp1 and R<∣v∣. Then no p with p1<p≤p1+⌊q1/k⌋ is good, so (G) holds after line L15 or L28.
Proof. Suppose p=p1+δ is good, 1≤δ≤q1/k. Then reach(p)≥R: either reach(p)≥kp>kp1>R, or reach(p)=∣v∣>R. For 0≤i<q1−δ, we have i+p<R, so v[i]=v[i+p], and i+δ+p1<R, so v[i+p]=v[(i+δ)+p1]=v[i+δ]. So v[0…q1−1] has period δ and length q1≥kδ. By (F4) it has a prefix period π≤δ≤q1/k, and q1=R−p1<(k−1)p1 gives π<p1; a prefix period is good, against (G). □
Lemma 2 (the shortest prefix period). Assume (G) and R=reach(p1)≥kp1. Then p1 is a prefix period and p1=per(v[0…R−1]).
Proof. Let π=per(v[0…R−1])≤p1. By (F1) v[0…π−1] is primitive and reach(π)≥R≥kp1≥kπ, so π is good, and (G) gives π=p1. □
Lemma 3 (drop). Assume (G), R=reach(p1)≥kp1, and let line L26 move s by tp1, t≥1, to obtain v′=v[tp1…] and R′=R−tp1, with (k−1)p1≤R′<kp1. Then reachv′(p1)=R′ and (G) holds for v′.
Proof. By Lemma 2, z=v[0…p1−1] is primitive. v′[0…R′−1]=v[tp1…R−1] is a factor of the p1-periodic prefix that starts at a multiple of p1, so it equals v[0…R′−1], and the mismatch (or end) at R in v is at R′ in v′; so reachv′(p1)=R′. Suppose δ<p1 is good for v′, and let L=min(reachv′(δ),R′); then v′[0…L−1] has periods δ and p1. If L≥δ+p1, (F3) applied to v′ (which starts with z) says p1∣δ, impossible for 0<δ<p1. Otherwise L<δ+p1<2p1≤(k−1)p1≤R′, using k≥3, so L=reachv′(δ)<R′≤∣v′∣, and goodness gives reachv′(δ)≥kδ. Since v and v′ agree on their first R′ characters and reachv′(δ)<R′, the mismatch that ends the δ-periodic prefix of v′ is also one in v, so reachv(δ)=reachv′(δ)≥kδ, and δ is good for v, against (G). □
Lines L11 to L15. (G) holds at the first entry, with p1=1, vacuously. If line L14 returns, R=∣v∣<kp1: by (G) no p<p1 is a prefix period or a period of v; p1 is not a prefix period; and p>p1 has reach(p)≤∣v∣<kp. So v has no prefix period and p1=per(v): (S1) to (S3) hold. If line L15 runs, Lemma 1 keeps (G). If line L16 is reached, Lemma 2 applies.
Lines L17 to L23. Here p1 is a prefix period with R≥kp1, z=v[0…p1−1] is primitive and p1=per(v[0…R−1]) (Lemma 2). The invariant at the start of line L19 is:
(H1) no prefix period p with p1<p<p2;
(H2) p2+q2≤∣v∣ and v[0…q2−1]=v[p2…p2+q2−1].
Start. p2=q1=R−p1≥(k−1)p1>p1 and q2=0. If p1<p<q1 were a prefix period, then reach(p)≥kp≥p+p1 and R=p1+q1>p+p1, so v[0…p+p1−1] has periods p and p1, and (F3) for the primitive prefix of length p gives p∣p1, impossible as p>p1.
Exits. Line L19 keeps (H2). If line L20 exits, p2 is used only as a bound in lines L24 to L29, where (G) is what matters, and (G) holds there because it held at line L12 and v, p1 have not changed since. If line L21 returns, ∣v∣=p2+q2<kp2, so no p≥p2 is a prefix period; with (H1) and (G), every prefix period equals p1, and with Lemma 2 this gives (S1) to (S3).
Line L22, q2=R. The loop stopped at a mismatch v[q2]=v[p2+q2] with p2+q2<kp2, so reach(p2)=p2+q2<kp2 and p2 is not a prefix period. Let p=p2+δ, 1≤δ<p1, be a prefix period. Then reach(p)≥kp>p2+q2, so for 0≤i<R−δ, v[i]=v[i+p] and, by (H2), v[i+p]=v[p2+(i+δ)]=v[i+δ]; so v[0…R−1] has period δ<p1, against Lemma 2. So (H1) holds for p2+p1. For (H2), for i<q1: v[p2+p1+i]=v[p1+i]=v[i], by (H2) and the period p1 of v[0…R−1].
Line L23, q2=R. As above p2 is not a prefix period. Let p=p2+δ, 1≤δ≤q2/k, be one. Then reach(p)≥kp>p2+q2, and for 0≤i<q2−δ, v[i]=v[i+p]=v[p2+i+δ]=v[i+δ] by (H2): v[0…q2−1] has period δ and length q2≥kδ. By (F4) it has a prefix period π≤δ≤q2/k<p2, which is p1 by (H1) and (G). So v[0…q2−1] has period p1, hence q2≤R, and so q2<R and v[0…q2] has period p1. Also q2≥kδ≥δ+p1 (as δ≥π=p1), so (F3) gives p1∣δ. Now p≤p2+q2<reach(p), so v[p2+q2]=v[p2+q2−p]=v[q2−δ]=v[q2], against the mismatch. (H2) holds with q2=0, and p2+⌊q2/k⌋+1≤p2+q2+1≤∣v∣ since p2+q2<∣v∣.
Lines L24 to L29. (G) holds at the first entry. After line L25, if R≥kp1, line L26 drops copies and Lemma 3 gives (G) for the new v with reach(p1)=R′<kp1; this does not change s+p1+q1. If line L27 returns, reach(p1)=∣v∣<kp1, and (S1) to (S3) follow exactly as for line L14. Otherwise Lemma 1 applies to line L28.
Lemma 4 (the search). Assume (S1) to (S3), R=p1+q1. At the start of each window p of line L5, T[p+s…p+s+q−1]=v[0…q−1]; line L7 outputs p exactly when p is valid; and no shift p′ with p<p′<pnext is valid.
Proof. The invariant holds with q=0; line L6 keeps it and stops at q=∣v∣ or at a real mismatch T[p+s+q]=v[q] (the position is inside T because p≤n−m). Line L7 outputs p exactly when v and u both match, that is, when p is valid. After line L8, for i<q−p1=q1, T[p+p1+s+i]=v[p1+i]=v[i] by the period p1 of v[0…R−1]; after line L9 the invariant is empty. For the shifts: p′ valid implies v occurs at p′+s; let d=p′−p≥1. For d≤i<q, T[p+s+i]=v[i] and T[p+s+i]=v[i−d], so v[0…q−1] has period d.
- Line L8, q=R, d<p1: v[0…R−1] has period d<p1, against (S3).
- Line L9, q=R, d≤q/k: v[0…q−1] has period d and length q≥kd, so by (F4) it has a prefix period π≤d, and π=p1 by (S1). Then v[0…q−1] has period p1, so q≤R by (S2), and q<R≤∣v∣: the scan stopped at a real mismatch, and v[0…q] has period p1. As q≥kd≥d+p1, (F3) gives p1∣d. The occurrence gives T[p+s+q]=v[q−d]=v[q], against the mismatch. □
Termination. In lines L11 to L15 and L24 to L29, p1 strictly increases at lines L15 and L28, and line L26 only runs while p1+q1≥kp1, which bounds the number of drops. These lines keep p1+q1≤∣v∣≤m: lines L15 and L28 run only when s+p1+q1<m, and then p1+⌊q1/k⌋+1≤p1+q1+1≤∣v∣. Lines L17 to L23 strictly increase p2 at each step and keep p2≤p2+q2≤∣v∣ by (H2), so they stop. The loop of lines L24 to L29 ends with p1≥p2>p1old, so each return to line L12 has a larger p1, and since p1≤m FACTORIZE returns. In the search, each shift is at least 1 and each window does at most m steps of line L6, so the search stops after at most n−m+1 windows.
Proof of the claim. FACTORIZE returns with (S1) to (S3). By Lemma 4, every window is output exactly when it is valid, the shifts skip no valid shift, and p increases, so every valid shift is output once, in increasing order. ■