Algorithm Search⌘K

Proofs: Generalized suffix automaton

These are the human proofs of Generalized suffix automaton, at full length.

The insertion with the extra check builds the generalized suffix automaton full

This proof shows: correctness, termination, time.worst.

Notation. Let W=(W0,…,Wr)W = (W_0, \ldots, W_{r}) be a list of strings, positions 0-based. For a nonempty string uu, endW(u)\mathrm{end}_W(u) is the set of pairs (k,e)(k, e) such that uu is a suffix of Wk[0…e]W_k[0 \ldots e]; uu is a substring of WW if this set is nonempty. Two substrings are equivalent if they have the same end set. The generalized suffix automaton A(W)A(W) has a root for the empty string and one state for each class; len(v)len(v) is the length of the longest string of vv; link(v)link(v) is the class of the longest suffix of the longest string of vv that is not in vv (the root if there is none); and δ(v,c)\delta(v, c) is the class of ucuc for any u∈vu \in v, defined when ucuc is a substring.

Lemma 1 (classes). (a) If uu is a suffix of zz and both are substrings, then end(z)⊆end(u)\mathrm{end}(z) \subseteq \mathrm{end}(u). (b) Each class consists of the suffixes of its longest string zz with lengths in an interval (len(link(v)),len(z)](len(link(v)), len(z)]. (c) δ\delta is well defined. (d) A prefix Wk[0…e]W_k[0 \ldots e] is the longest string of its class.

Proof. (a) is clear. (b) If uu and zz are in one class with ∣u∣≤∣z∣|u| \le |z|, take an end (k,e)(k, e) of both: both are suffixes of Wk[0…e]W_k[0 \ldots e], so uu is a suffix of zz; and any yy between them in length that is a suffix of zz is in the class, by (a) on both sides. (c) If end(u)=end(u′)\mathrm{end}(u) = \mathrm{end}(u'), then end(uc)={(k,e+1):(k,e)∈end(u), Wk[e+1]=c}=end(u′c)\mathrm{end}(uc) = \{(k, e+1) : (k, e) \in \mathrm{end}(u),\ W_k[e+1] = c\} = \mathrm{end}(u'c). (d) A string longer than e+1e + 1 cannot end at (k,e)(k, e). □\square

The step. Suppose the structure is A(W)A(W), where the last string of WW is the prefix x=Wr[0…e]x = W_r[0 \ldots e] (possibly empty, with e=−1e = -1), and lastlast is the class of xx (the root if xx is empty). Let W′W' be WW with WrW_r extended by cc. Then endW′(u)=endW(u)∪{(r,e+1)}\mathrm{end}_{W'}(u) = \mathrm{end}_W(u) \cup \{(r, e+1)\} if uu is a suffix of xcxc, and endW′(u)=endW(u)\mathrm{end}_{W'}(u) = \mathrm{end}_W(u) otherwise. Let tt be the length of the longest suffix ww of xcxc that is a substring of WW (t=0t = 0 and ww empty if there is none).

Lemma 2 (what changes). (i) The suffixes of xcxc longer than tt form one new class with end set {(r,e+1)}\{(r, e+1)\}, if t<∣x∣+1t < |x| + 1. (ii) Among the old classes, only the class qq of ww can split, and it splits if and only if len(q)>tlen(q) > t: into the strings of length greater than tt, with the old end set, and those of length at most tt, with the new end. (iii) Every other old class keeps its strings.

Proof. (i) These suffixes are new substrings, and each ends only at (r,e+1)(r, e+1). (ii, iii) A class with no suffix of xcxc keeps its end set. Let yy be a suffix of xcxc of length j≤tj \le t, with zz the longest string of its class. Take an end of ww; it is also an end of yy, so of zz, so zz and ww are suffixes of one prefix. If ∣z∣≤t|z| \le t, zz is a suffix of ww, and by Lemma 1(b) the whole class of yy consists of suffixes of xcxc, which all gain the same end. If ∣z∣>t|z| > t, then ww is a suffix of zz of length between jj and ∣z∣|z|, so ww is in the class of yy; that is the class qq. In qq, the strings of length at most tt are suffixes of xcxc, and the longer ones are not, since they are not suffixes of ww and ww is the longest old suffix of xcxc. □\square

Lemma 3 (the clone keeps the transitions). If qq splits into qq (long part) and q′q' (short part), then δW′(q′,a)=δW(q,a)\delta_{W'}(q', a) = \delta_W(q, a) and δW′(q,a)=δW(q,a)\delta_{W'}(q, a) = \delta_W(q, a) for every symbol aa, and the targets are old classes that do not split.

Proof. For u∈q′u \in q', a pair (r,e+2)(r, e+2) cannot be an end of uaua, since Wr′W'_r has length e+2e + 2. So endW′(ua)=endW(ua)\mathrm{end}_{W'}(ua) = \mathrm{end}_W(ua), the shifted old ends of uu, which are the shifted ends of all of qq. The target class contains strings of length len(q)+1len(q) + 1 or less that are not suffixes of xcxc ending at the new place, so it is not qq, and by Lemma 2 it keeps its strings. □\square

Theorem 1 (correctness). GSA-EXTEND(last,c)(last, c) turns A(W)A(W) into A(W′)A(W') and returns the class of xcxc.

Proof. By Lemma 1(d), len(last)=∣x∣len(last) = |x|. The transitions that change are δ(v,c)\delta(v, c) for the classes vv whose strings uu have ucuc in a new or split class: the suffixes uu of xx with ∣u∣≥t|u| \ge t (whose ucuc is new), and those with len(link(q))≤∣u∣≤t−1len(link(q)) \le |u| \le t - 1 when qq splits (whose ucuc moves to q′q'). The suffix links change only for the new class, for qq and for q′q': a class vv with link(v)=qlink(v) = q points to the longest string of qq, which stays in the long part. The classes of the suffixes of xx are the states on the suffix-link path from lastlast, by Lemma 1(b) applied to the prefix xx.

Case 1: δ(last,c)\delta(last, c) exists (lines L1 to L3). Then xcxc is a substring of WW, so t=∣x∣+1t = |x| + 1, no class is new, and q=δ(last,c)q = \delta(last, c) is the class of xcxc. If len(q)=tlen(q) = t, nothing splits and no transition or link changes, so qq is returned correctly. Otherwise SPLIT makes the clone with len=len(last)+1=tlen = len(last) + 1 = t, the old link of qq and the transitions of qq (Lemma 3), moves δ(p,c)\delta(p, c) from qq to the clone on the path from lastlast while it pointed to qq, which are the classes with len(link(q))≤∣u∣≤t−1len(link(q)) \le |u| \le t - 1, and sets link(q)link(q) to the clone. The clone is the class of xcxc, and it is returned.

Case 2: no transition (lines L4 to L9). Then t≤∣x∣t \le |x| and the new class curcur has len=∣x∣+1len = |x| + 1. Line L5 walks the path from lastlast and sets δ(p,c)=cur\delta(p, c) = cur while pp has no transition on cc; these are the classes whose strings uu have ∣u∣≥t|u| \ge t, since δ(p,c)\delta(p, c) exists for all members of a class or for none. If the walk passes the root, no suffix of xcxc was a substring, t=0t = 0, and link(cur)link(cur) is the root (L6). Otherwise the walk stops at the class pp of the suffix of xx of length t−1t - 1, and len(p)=t−1len(p) = t - 1, since a longer member zz of pp would give an old suffix zczc of xcxc longer than tt. So q=δ(p,c)q = \delta(p, c) is the class of ww. If len(q)=len(p)+1=tlen(q) = len(p) + 1 = t, nothing splits and link(cur)=qlink(cur) = q (L7). Otherwise SPLIT with len(p)+1=tlen(p) + 1 = t splits qq as in Case 1, starting the walk at pp, and link(cur)link(cur) is the clone (L8). The new class is the class of xcxc and is returned (L9). □\square

Theorem 2 (build). Inserting the strings one by one, each from the root, gives A(S0,…,Sm−1)A(S_0, \ldots, S_{m-1}).

Proof. AA of the empty list, and of a list that ends with an empty string, is the root alone. Starting a new string adds an empty last string, which changes no end set, and lastlast = root is its class. Theorem 1 then applies at each symbol. □\square

Theorem 3 (time). For a constant alphabet, the build takes O(N)O(N) time.

Proof. Each call creates at most two states, so there are O(N)O(N) states, and the work outside the loops of L5 and L11 is O(1)O(1) per call. For one string, Blumer et al. bound the total work of these loops by O(n)O(n) with a potential: the number of steps of the loop of L5 is paid by the drop in the depth, in the suffix-link tree, of the link of the state returned, compared with the depth of lastlast, and the redirect loop of L11 by the same drop for the clone. The same accounting holds here within one string, and starting a new string at the root sets the depth to 0, which only lowers the potential. So the total is O(N)O(N). With a transition map of σ\sigma symbols, each transition access adds a factor of O(log⁡σ)O(\log \sigma) for sorted maps, or O(1)O(1) expected time for hashing. ■\blacksquare

Back to Generalized suffix automaton