Proofs: Generalized suffix tree
These are the human proofs of Generalized suffix tree, at full length.
The stack build gives the generalized suffix tree full
This proof shows: correctness, termination, time.worst.
Notation. The strings are , and has length . The separators are distinct, each occurs once in , and are smaller than all letters. Positions are 0-based. For a position that holds a letter, let be the position of the first separator at or after , and let , the suffix of its string followed by its separator. The generalized suffix tree is the compacted trie of the set : a rooted tree whose edges are labeled with nonempty strings, where the labels of the edges out of a node start with different symbols, each internal node other than the root has at least two children, and the leaves are exactly the strings of .
Lemma 1 (terminated suffixes). Let be letter positions. Then , and if and only if . In particular, no string of is a prefix of another.
Proof. Let and suppose . Then , and the left side is the separator at . A separator occurs once in , so , a contradiction. The same holds for . So the first difference of and is at an offset inside both and , with the same two symbols, and the orders agree. If were a prefix of , then .
Lemma 2 (ranks). The ranks of the suffix array of hold the suffixes that start with a separator, and the ranks hold the letter positions. For , , and .
Proof. A suffix that starts with a separator is smaller than each suffix that starts with a letter, because the separators are smaller than all letters. For both suffixes start at letter positions, and Lemma 1 shows that their common prefix lies inside both terminated suffixes. The suffix of rank starts with a separator and that of rank with a letter, so .
So the letter positions in the order list in increasing order, with the LCP of each adjacent pair. Write and for .
Invariant. After the loop of lines L3 to L10 has handled :
(G) The tree is the compacted trie of , with the leaf of labeled by its string and offset. The stack holds, from bottom to top, the nodes of the path from the root to the leaf of , in order of increasing string depth.
Initialization. Before the loop, the tree is the root alone and the stack is [root]. For , : line L5 pops nothing, since the root has depth 0, line L6 fails, and lines L9 and L10 hang the leaf of below the root with the edge label . This is , and the stack is the path to the leaf.
Maintenance. Assume (G) for and handle with . Because the list is sorted, branches off the path to at string depth : the common prefix of with each earlier has length at most , by the sandwich property of sorted strings, . So in the leaf of hangs from the point at depth on the path to , and no other part of changes. By Lemma 1, , the depth of the leaf on top of the stack. Line L5 pops the nodes of depth more than ; at least the leaf is popped, so is defined, and is the shallowest popped node, a child of the new top. If the new top has depth , that node is the branch point. Otherwise its depth is less than and the point at depth lies inside the edge from the top to ; lines L7 and L8 split this edge with a new node of depth . The key of below is the symbol at depth of its path label, and the key of below the top is the same as the old key of , so the edge to is replaced. Lines L9 and L10 hang the leaf of below the branch point, with the key . This key differs from the key of the child on the path to , because is the exact LCP. Each new internal node has two children, and the stack is the path to the new leaf. So (G) holds for .
Termination and result. The loop runs times and each pop removes a node pushed earlier, so it ends. By (G) the result is the compacted trie of , which is the generalized suffix tree. Each suffix of each that is nonempty is one leaf.
Lemma 3 (search). For a nonempty pattern over the letters, the occurrences of in the strings are the labels of the leaves below the highest node whose path label starts with .
Proof. occurs at offset of if and only if is a prefix of with the position of , because has no separator. The strings of with prefix are the leaves below the locus of in the compacted trie.
Theorem (time). Given the suffix array and the LCP array of , lines L2 to L10 run in time.
Proof. Each iteration pushes at most two nodes, so there are at most pushes and so at most as many pops in total. The other lines take time each, with the children of a node in a hash map keyed by a symbol, and the string of each position is found in time from a table of the string of each position, or in time by a binary search on the start positions. With a linear-time suffix array construction for an integer alphabet and Kasai's algorithm for the LCP array, the whole build is .