Abstract 1 Introduction 2 Notation and Preliminary 3 Relative Encoding of 𝐏𝐀 in 𝑶⁢(𝒏) Extra bits 4 Relative Encoding of 𝐏𝐀 in Sublinear Space 5 A Note On Inverse Prefix Array (IPA) Queries 6 Conclusions References

Relative Compressed Reverse Suffix Array

Muhammed Oguzhan Kulekci ORCID Miami University, Oxford, OH, USA Mano Prakash Parthasarathi111Corresponding author ORCID North Carolina State University, Raleigh, NC, USA Rahul Shah ORCID Louisiana State University, Baton Rouge, LA, USA Sharma V. Thankachan ORCID North Carolina State University, Raleigh, NC, USA
Abstract

Suffix trees and suffix arrays are two fundamental data structures in the field of string algorithms. For a string (a.k.a. text or sequence) of length n over an alphabet of size σ, these structures typically require O⁢(n⁢log⁡n) bits of space. The FM-index provides a compressed representation of the suffix array in ≈n⁢log⁡σ bits, allowing for efficient queries on both the suffix array and its inverse array in near logarithmic time. In certain applications, such as approximate pattern matching (i.e., with wildcards, mismatches, edits), there is a need to access the suffix array of a text, as well as the suffix array of text’s reverse. Motivated by this, we explore the possibility of encoding the suffix array of the reversed text in a compact form, assuming the availability of the FM-index for the original text. Our first solution is an O⁢(n)-bit (relative) encoding of the suffix array of the reversed text, with the time for decoding an entry being only O⁢(log∗⁡n) times that of decoding an entry in the text’s suffix array using FM-index. We then demonstrate how to reduce the space to O⁢(n/κ) bits for a parameter κ, while multiplicative factor in time becomes approximately O⁢(κ⁢log∗⁡n+κ3). We can also support inverse suffix array and longest common extension queries on the reversed text. These results are achieved through some careful and non-trivial application of various succinct data structure techniques.

Keywords and phrases:
String Matching, Text Indexing, Data Structures, Suffix Trees
Funding:
Mano Prakash Parthasarathi: U.S. National Science Foundation (NSF) award CCF-2315822.
Rahul Shah: U.S. NSF awards CCF-2434261 and CCF-2137057
Sharma V. Thankachan: U.S. NSF awards CCF-2316691 and CCF-2315822.
Copyright and License:
[Uncaptioned image] © Muhammed Oguzhan Kulekci, Mano Prakash Parthasarathi, Rahul Shah, and
Sharma V. Thankachan; licensed under Creative Commons License CC-BY 4.0
2012 ACM Subject Classification:
Theory of computation → Pattern matching
Editors:
Meena Mahajan, Florin Manea, Annabelle McIver, and Nguyễn Kim Thắng

1 Introduction

The suffix tree data structure [22, 33, 34] has long been a fundamental tool in string processing, enabling tasks such as pattern matching in time linear in the pattern length. However, their use has been limited in practice due to their high memory usage. Suffix arrays [21] were introduced as a more memory-efficient alternative that can perform most of the tasks as suffix trees. Both suffix trees and suffix arrays of a text of length n still require O⁢(n⁢log⁡n) bits to store, while the text itself only needs n⁢log⁡σ bits, where σ is the alphabet size. The major breakthrough came in 2000 with the FM-index [7], along with another important development called the compressed suffix array [14]; both of these encode the suffix array in succinct (even compressed) space. Since then, compressed text indexing has continued to be an active area of research, with the FM-index emerging as a foundational component in many bioinformatics tools [18, 20].

In its standard form, the FM-index is essentially the Burrows-Wheeler Transform (BWT) of the text, stored in a data structure that supports rank queries (typically using a wavelet tree [13, 24]), along with a sampled subset of suffix array values. The wavelet tree part uses n⁢log⁡σ+o⁢(n)+O⁢(σ⁢log⁡n) bits, and supports rank queries in time tw⁢t=O⁢(1+log⁡σ/log⁡log⁡n). For a parameter τ, the number of sampled suffix array values is n/τ and its storage takes O⁢((n/τ)⁢log⁡n) bits. To keep this extra space within o⁢(n) bits, τ is typically chosen as ω⁢(log⁡n). With this, the suffix array (SA) and inverse suffix array (ISA) queries can be supported in time ts⁢a=O⁢(τ⋅tw⁢t). With additional o⁢(n) bits, we can obtain an encoding of the suffix tree itself that supports various queries in time close to O⁢(ts⁢a) [31, 30]. Recent results have revealed the possibility of achieving even more space-efficient encodings of suffix arrays/trees when the data is highly repetitive [10, 16, 26, 27].

We investigate the problem of compactly encoding the suffix array of the reverse of a text, assuming access to the text’s FM-index in its standard form (i.e., the Burrows–Wheeler Transform represented as a wavelet tree together with a sampled suffix array). While this is a natural question in its own right, solutions to it have important applications in text indexing for approximate string matching. A common technique for supporting pattern matching with mismatches or “don’t care” characters involves maintaining both the suffix array or tree of the text and that of its reverse, along with a range query data structure built from specific points derived from these structures [2]. For a comprehensive survey of various results based on this technique, we refer the reader to Lewenstein [19]. See also the solutions for contextual pattern matching [1, 25], bidirectional indexes [17], and affix arrays [32] for further applications. Reducing the memory footprint of the data structures associated with the reversed text can significantly reduce the overall space usage in such applications. We highlight that our problem aligns with the broader theme of relative text indexing, such as relative suffix trees [6] and relative FM-indexes [3], where the goal is to encode a data structure over a dataset by leveraging the availability of the same structure over a closely related dataset. The fact that, in our case, one text is essentially the reverse of the other introduces significant structure to the problem.

This problem was introduced by Ganguly et al. [12], who presented an algorithm to decode the suffix array values of the reversed text directly from the text’s FM-index, without requiring any additional data structures. However, it was heuristic in nature. Specifically, its query time is proportional to the length of the shortest unique substring of the text ending at the value returned, which can be Θ⁢(n) in the worst case. Therefore, our goal is to support suffix array (and inverse suffix array) queries on the reversed text in time close to that of suffix array queries on the original text. We present our results next.

Our Results

Let 𝖳⁢[1⁢..⁢n] denote the text to be indexed, where the characters belong to an integer alphabet of size σ. We can represent the text’s Burrows–Wheeler Transform (BWT) as a (multiary) wavelet tree in n⁢log⁡σ+o⁢(n)+O⁢(σ⁢log⁡n) bits of space, supporting basic wavelet tree operations (rank, select, access) in time tw⁢t=O⁢(1+log⁡σ/log⁡log⁡n) and range quantile queries in time tq⁢u⁢a⁢n⁢t⁢i⁢l⁢e=O⁢(log⁡σ). By maintaining some auxiliary structures of space O⁢(n/κ) bits for an integer parameter κ≥1, we can support suffix array (SA) and inverse suffix array (ISA) queries in time ts⁢a=O⁢(tw⁢t⋅κ⁢log⁡n). We obtain the following results.

  1. 1.

    Our first result is that suffix array queries on the reversed text can be supported in time tp⁢a=ts⁢a⋅O⁢(log∗⁡n) with an auxiliary structure of O⁢(n) bits of space.

  2. 2.

    We then generalize the above result by introducing a parameter κ, achieving a space usage of O⁢(n/κ) bits and a query time tp⁢a=ts⁢a⋅O⁢((κ⁢log∗⁡n+κ3⁢log⁡κ)⋅log2⁡κ).

We also show how to support inverse suffix array queries on the reversed text within the same space and in time O⁢(tp⁢a⋅log⁡n⋅log⁡log⁡n), which is based on a simple method for answering longest common extension queries on the reversed text. As shown in [31, 30], we can use o⁢(n) extra bits to obtain a succinct encoding of the suffix tree of the reversed text that supports various standard operations efficiently.

2 Notation and Preliminary

Throughout this paper, let 𝖳=𝖳⁢[1⁢..⁢n] denotes the text to be indexed and Σ denotes the alphabet set. The i-th character of 𝖳 is denoted by 𝖳⁢[i] and the substring 𝖳⁢[i]∘𝖳⁢[i+1]∘⋯∘𝖳⁢[j−1]∘𝖳⁢[j] is denoted by 𝖳⁢[i⁢..⁢j], where 1≤i≤j≤n and ∘ denotes concatenation. The string 𝖳⁢[i⁢..⁢j] is empty if i>j. We also use 𝖳[i..j) for 𝖳⁢[i⁢..⁢j−1] and 𝖳(i..j] for 𝖳⁢[i+1⁢..⁢j]. A substring 𝖳⁢[i⁢..⁢j] is called a suffix if j=n and a prefix if i=1; also 𝖳⁢[1⁢..⁢j] is a proper prefix if j≠n and 𝖳⁢[i⁢..⁢n] is a proper suffix if i≠1. For any string S=S⁢[1⁢..⁢s], we denote its reverse S⁢[s]∘S⁢[s−1]∘⋯∘S⁢[2]∘S⁢[1] by S←. Without loss of generality, assume that the characters in our alphabet set Σ corresponds to integers in the range [0,σ), where σ=|Σ|. Also, let $ denote the first character in lexicographic order (equivalently, 0) and 𝖳⁢[i]=$ iff i=n, ensuring that no suffix is a prefix of another suffix.

We call a data structure auxiliary if it is used to support operations assuming some related structures are available; otherwise, it is considered standalone. We assume the standard word RAM model of computation with word size Ω⁢(log⁡n) bits.

2.1 Succinct Data Structure Toolkit

2.1.1 Rank/select Queries, Indexible Dictionaries and Wavelet Trees

Let S⁢[1⁢..⁢n]∈Σn, where Σ={0,1,2,…,σ−1}. We define three basic operations.

  • ■

    𝖺𝖼𝖼𝖾𝗌𝗌S⁢(i) is S⁢[i].

  • ■

    𝗋𝖺𝗇𝗄S⁢(i,α), where α∈Σ, is the number of α’s in S⁢[1⁢..⁢i].

  • ■

    𝗌𝖾𝗅𝖾𝖼𝗍S⁢(j,α) is the position of j-th occurrence of α in S.

When Σ={0,1}, we can maintain S in n+o⁢(n) bits and support all three operations in O⁢(1) time [28]. Another representation, called indexible dictionary takes m⁢log⁡(n/m)+O⁢(m) bits, where m is the number of 1’s in S [29]. It supports the above operations in O⁢(log⁡log⁡n) time. Interestingly, it can support 𝗌𝖾𝗅𝖾𝖼𝗍S⁢(j,1) in O⁢(1) time, and also 𝗋𝖺𝗇𝗄S⁢(i,1) when S⁢[i]=1 (referred to as partial rank) in O⁢(1) time. We will use this result extensively.

For a general alphabet Σ, we have the wavelet tree data structure that uses n⁢log⁡σ+o⁢(n)+O⁢(σ⁢log⁡n) bits of space and supports all three basic operations in O⁢(log⁡σ) time [13]. It can also support range quantile queries in O⁢(log⁡σ) time [11], where the goal is to find the k-th smallest element in S⁢[x⁢..⁢y], given the tuple (x,y,k). Multiary wavelet trees offer further improvements, reducing the time complexity of the three basic operations to O⁢(1+log⁡σ/log⁡log⁡n) [8]; however, the time for range quantile queries remains O⁢(log⁡σ). Also note that the o⁢(n) term in space can be made O⁢(n/logc⁡n) for any constant c using efficient bit string representations [28]. We refer to Navarro’s survey for further reading on this topic [24]. Moving forward, we use tw⁢t to denote the time complexity of the basic operations, and tq⁢u⁢a⁢n⁢t⁢i⁢l⁢e to represent the time complexity of a range quantile query.

2.1.2 Range Minimum Query (RMQ)

Let A⁢[1⁢..⁢n] be an array of numbers. A range minimum query RMQA⁡(x,y) returns the position k∈[x,y], where A⁢[k] is the smallest element in A⁢[x⁢..⁢y]. By maintaining a standalone data structure of space 2⁢n+o⁢(n) bits, we can support RMQ in O⁢(1) time [9].

2.1.3 Succinct Representation of Ordinal Trees

The topology of an ordinal tree of n nodes can be represented in 2⁢n+o⁢(n) bits and support the following operations in O⁢(1) time [15, 23]. We specify a node by its preorder rank.

  • ■

    𝗉𝖺𝗋𝖾𝗇𝗍⁢(u) returns the parent of node u.

  • ■

    LCA⁡(u,v) returns the lowest (farthest from the root) common ancestor of nodes u and v.

  • ■

    𝗌𝗂𝗓𝖾⁢(u) returns the number of leaves in the subtree of node u.

  • ■

    0⁢p⁢t⁢(u) returns the number of ancestors of node u.

  • ■

    𝗅𝖾𝗏𝖾𝗅⁢_⁢𝖺𝗇𝖼𝖾𝗌𝗍𝗈𝗋⁢(u,d) returns the ancestor of node u at 0⁢p⁢t d.

  • ■

    range of leaves [a,b] of any given node u, where a-th (resp., b-th) leaf in the tree represents the leftmost (resp., rightmost) leaf in the subtree of u.

2.2 Suffix Tree, Suffix Array and Longest Common Prefix (LCP) Array

The suffix of 𝖳 starting at position i is 𝖳⁢[i⁢..⁢n]. The circular suffix of 𝖳, starting at position i is 𝖳[i..n]∘𝖳[1..i)=𝖳[i]∘𝖳[i+1]∘⋯∘𝖳[n]∘𝖳[1]∘𝖳[2]∘⋯∘𝖳[i−1].

We define the suffix tree of text 𝖳 as a compacted trie of all circular suffixes of 𝖳. This is equivalent to the standard definition (i.e., without the term “circular”), since 𝖳⁢[i]=$ iff i=n. It consists of n leaves and less than n internal nodes. The edges are (implicitly) labeled with substrings of 𝖳. We use str⁢(u) to denote the concatenation of edge labeled on the path from root to node u. Also, let strlen⁢(u) be the length of str⁢(u) (called string depth). The i-th leftmost leaf in the suffix tree is denoted by ℓi. The suffix array and the inverse suffix array of 𝖳 are the arrays SA⁡[1⁢..⁢n] and ISA⁡[1⁢..⁢n], respectively, where SA⁡[j]=i and ISA⁡[i]=j iff the j-th smallest circular suffix in lexicographic order is 𝖳[i..n]∘𝖳[1..i). Equivalently, str(ℓj)=𝖳[i..n]∘𝖳[1..i).

For a string P, the locus node u (if it exists) is the node closest to root such that P is a prefix of str⁢(u) and the range of leaves of u is called the suffix range of P, denoted by [𝗌𝗉⁢(P),𝖾𝗉⁢(P)]. The set {SA⁡[k]∣k∈[𝗌𝗉⁢(P),𝖾𝗉⁢(P)]} denotes the occurrences of P in 𝖳. The longest common extension, denoted by LCE⁡(i,j) is the length of the longest common prefix of the suffixes of 𝖳 starting positions i and j, which is the same as strlen⁢(u), where u is the lowest common ancestor (LCA) of leaves ℓISA⁡[i] and ℓISA⁡[j].

The longest common prefix array LCP[1..n) is an array where LCP⁡[i]=LCE⁡(SA⁡[i],SA⁡[i+1]). Therefore, LCE⁡(i,j) is the smallest element in LCP[x..y), where x=min⁡{ISA⁡[i],ISA⁡[j]} and y=max⁡{ISA⁡[i],ISA⁡[j]}. The permuted longest common prefix array pLCP[1..n) is defined as pLCP⁡[j]=LCP⁡[ISA⁡[j]]=LCE⁡(j,SA⁡[ISA⁡[j]+1]). Note that the argument of LCP⁡[⋅] is a leaf position in the suffix tree, whereas that of pLCP⁡[⋅] is a position in the text. We will later see that pLCP array can be encoded in 2⁢n+o⁢(n) bits. See Table 1 for an example.

Table 1: SA,ISA,LCP,pLCP,BWT,PA,IPA,LCS, and pLCS values for 𝖳⁢[1⁢..⁢12]=m⁢i⁢s⁢s⁢i⁢s⁢s⁢i⁢p⁢p⁢i⁢$.
i 1 2 3 4 5 6 7 8 9 10 11 12
𝖳[1..12] m i s s i s s i p p i $
SA[1..12] 12 11 8 5 2 1 10 9 7 4 6 3
ISA[1..12] 6 5 12 10 4 11 9 3 8 7 2 1
LCP[1..12] 0 1 1 4 0 0 1 0 2 1 3 -
pLCP[1..12] 0 0 - 1 4 3 2 1 0 1 1 0
BWT[1..12] i p s s m $ p i s s i i
PA[1..12] 12 2 11 5 8 1 9 10 3 6 4 7
IPA[1..12] 6 2 9 11 4 10 12 5 7 8 3 1
LCS[1..12] 0 1 1 4 0 0 1 0 2 1 2 -
pLCS[1..12] 0 1 2 2 4 1 - 0 1 0 1 0

2.3 Prefix Tree, Prefix Array and Longest Common Suffix (LCS) Array

We now introduce the prefix tree and prefix array of the text, which are equivalent to the suffix tree and suffix array of the reversed text. These alternative definitions are introduced purely for notational convenience.

The prefix of 𝖳 ending at position i is 𝖳⁢[1⁢..⁢i]. The circular prefix of 𝖳 ending at i is 𝖳(i..n]∘𝖳[1..i] and its reverse is 𝖳⁢[i]∘𝖳⁢[i−1]∘⋯∘𝖳⁢[1]∘𝖳⁢[n]∘𝖳⁢[n−1]∘⋯∘𝖳⁢[i+1]. The prefix tree of 𝖳 is a compacted trie of the reverse of all circular prefixes of 𝖳. It will have n leaves and less than n internal nodes, and the edges will be labeled as in the suffix tree, but with substrings of 𝖳←. We shall reuse the notations ℓi, str⁢(⋅) and strlen⁢(⋅) as before when the context is clear. We define prefix array PA⁡[1⁢..⁢n] and inverse prefix array IPA⁡[1⁢..⁢n] of 𝖳 as PA⁡[j]=i and IPA⁡[i]=j iff str⁢(ℓj) is the “reverse” of the circular prefix of 𝖳 ending at i. Define LCE←⁢(i,j) as the length of the longest common suffix of the prefixes of 𝖳 ending at positions i and j. Therefore, LCE←⁢(i,j)=strlen⁢(u), where u is the LCA of leaves ℓIPA⁡[i] and ℓIPA⁡[j] in the prefix tree. The longest common suffix (LCS) array LCS[1..n) is an array where LCS⁡[i]=LCE←⁢(PA⁡[i],PA⁡[i+1]) and the permuted longest common suffix (pLCS) array is such that pLCS⁡[j]=LCS⁡[IPA⁡[j]]=LCE←⁢(j,PA⁡[IPA⁡[j]+1]). See Table 1 for an example.

2.4 The FM-index

The FM-index [7] is a compressed representation of the suffix array SA, based on the text’s BWT [5]. It is a self-index, meaning it does not require access to the original text in order to function. The BWT of 𝖳, denoted by BWT⁡[1⁢..⁢n] is a permutation of characters in 𝖳, where BWT⁡[i] denotes the last character of i-th lexicographically smallest circular suffix of 𝖳. In other words, BWT⁡[i]=𝖳⁢[SA⁡[i]−1] if SA⁡[i]≠1 and is $ otherwise. See Table 1 for an example.

The Last-to-Front operation is defined as LF⁡[i]=ISA⁡[SA⁡[i]−1] if SA⁡[i]≠1 and is 1 otherwise. Moreover, LF⁡[i]=C⁢o⁢u⁢n⁢t⁢(c)+𝗋𝖺𝗇𝗄BWT⁢(i,c), where c=BWT⁡[i] and C⁢o⁢u⁢n⁢t⁢(c)=|{j∣BWT⁡[j]<c}|. By maintaining BWT as a wavelet tree, along with C⁢o⁢u⁢n⁢t⁢(c) for all c∈Σ, in O⁢(σ⁢log⁡n) bits, we can support LF⁡[⋅] operation in O⁢(tw⁢t) time.

We next focus on SA⁡[⋅] and ISA⁡[⋅] operations. Let LFk⁡[i]=LF⁡[LFk−1⁡[i]] if k>1 and is LF⁡[i] if k=1, then SA⁡[LFk⁡[i]]=SA⁡[i]−k. For a parameter τ, explicitly store the pairs (i,SA⁡[i]) with SA⁡[i] being a multiple of τ; space is O⁢((n/τ)⁢log⁡n) bits. To decode SA⁡[i], where (i,SA⁡[i]) is not stored, we compute LF⁡[i],LF2⁡[i],LF3⁡[i],… until we find an LFk⁡[i], where (LFk⁡[i],SA⁡[LFk⁡[i]]) is stored, and return SA⁡[i]=k+SA⁡[LFk⁡[i]]. To decode ISA⁡[j], where (ISA⁡[j],j) is not stored, we find j′=τ⁢⌈j/τ⌉ and i′=ISA⁡[j′] (note that (i′,j′) is stored) and return LFk⁡[i′], where k=j′−j. In both cases, the sampling scheme guarantees k≤τ and the resulting time complexity, denoted by ts⁢a, is k⋅tw⁢t=O⁢(τ⋅tw⁢t).

We can also extract any substring 𝖳[j..j+r) in time O⁢(ts⁢a+r⋅tw⁢t) as follows: find x=ISA⁡[j+r], LF⁡[x],LF2⁡[x],LF3⁡[x],…,LFr−1⁡[x] successively and output the string BWT⁡[LFr−1⁡[x]]∘…⁢BWT⁡[LF⁡[x]]∘BWT⁡[x].

Lemma 1.

Suppose the text’s BWT is available as a wavelet tree supporting basic operations (i.e., 𝗋𝖺𝗇𝗄,𝗌𝖾𝗅𝖾𝖼𝗍 and 𝖺𝖼𝖼𝖾𝗌𝗌) in tw⁢t time, then with O⁢((n/τ)⁢log⁡n) extra bits, we can support SA/ISA queries in time ts⁢a=O⁢(τ⋅tw⁢t) and extract any substring 𝖳[j..j+r) in time O⁢(ts⁢a+r⋅tw⁢t). Here, τ is a parameter.

2.5 Longest Common Extension (LCE) and Related Queries

The following two results, along with the succinct representation of the suffix tree topology as in Section 2.1.3, gives the compressed representation of the suffix tree. We present sketches of the proofs for these known results, since we will be adapting them in subsequent sections.

Lemma 2 (Sadakane [31]).

The pLCP array can be encoded in 2⁢n+o⁢(n) bits, such that pLCP⁡[j] for any position j in the text can be retrieved in O⁢(1) time.

Proof.

Key observation is that pLCP⁡[j+1]≥pLCP⁡[j]−1 for all j. To prove this, note that it is trivially true when pLCP⁡[j]=0. Otherwise, let SA⁡[ISA⁡[j]+1]=j′. Then ISA⁡[j+1]<ISA⁡[j′+1], therefore pLCP⁡[j+1] is atleast LCE⁡(j+1,j′+1)=pLCP⁡[j]−1. By rearranging the inequality and by adding j on both sides, we get j+pLCP⁡[j]≤(j+1)+pLCP⁡[j+1]. This means, the function f⁢(j)=j+pLCP⁡[j] is non-decreasing. Moreover f⁢(j)∈[1,n], because pLCP⁡[n]=0 and hence f⁢(n)=n. Therefore, we can store the function f⁢(⋅) as a bit string B=0f⁢(1)⁢10f⁢(2)−f⁢(1)⁢10f⁢(3)−f⁢(2)⁢1⁢… with O⁢(1) time rank/select support in 2⁢n+o⁢(n) bits. To decode pLCP⁡[j], we first find p=𝗌𝖾𝗅𝖾𝖼𝗍B⁢(j,1), the position of j-th 1 in B in O⁢(1) time. Then we have f⁢(j)=p−j, the number of 0’s until p, and pLCP⁡[j]=f⁢(j)−j. ◀

Lemma 3 (LCE Queries).

By maintaining an auxiliary structure of space O⁢(n) bits along with the FM-index, we can answer LCE⁡(⋅,⋅) queries in O⁢(ts⁢a) time.

Proof.

Maintain the encoding of the pLCP array described in Lemma 2 and an RMQ data structure over the LCP array, but without explicitly storing the LCP array itself. To compute LCE⁡(i,j), find i′=ISA⁡[i] and j′=ISA⁡[j]. Without loss of generality, assume that i′<j′. Then find k′∈[i′,j′), where LCP⁡[k′] is the smallest in LCP[i′..j′) using an RMQ in O⁢(1) time. Then compute k=SA⁡[k′] and return pLCP⁡[k]. Total time is O⁢(ts⁢a). ◀

We next present an additional result that will be used later.

Lemma 4 (LCE← Queries).

Let D be an integer parameter. By maintaining an auxiliary structure of space O⁢((n/D)⁢log⁡n) bits, we can compute LCE←⁢(i,j) for any given i,j via O⁢(log⁡D) number of LCE queries.

Proof.

For any given text of length n, there exists a standalone data structure of space O⁢(n/D) words, equivalently O⁢((n/D)⁢log⁡n) bits, that in constant time either correctly computes LCE⁡(i,j) or determines that LCE⁡(i,j)≤D2 for any given i,j [4]. We maintain this data structure over the reversed text, which allows us to correctly compute LCE←⁢(i,j) or to determine that LCE←⁢(i,j)≤D2. When LCE←⁢(i,j)≤D2, we exploit the following observation: LCE←⁢(i,j)≥t if and only if LCE⁡(i−t+1,j−t+1)≥t, and binary search on t∈[0,D2]. This will give us LCE←⁢(i,j) in O⁢(log⁡D) number of LCE queries. ◀

3 Relative Encoding of 𝐏𝐀 in 𝑶⁢(𝒏) Extra bits

The prefix tree/array of 𝖳 corresponds to the suffix tree/array of T←. Specifically, the i-th entry in the suffix array of 𝖳← is (n−PA⁡[i]+1). Therefore, it suffices to design an encoding of the prefix array.

3.1 Basic Components

Let π≠0 be an integer parameter (positive or negative). We now introduce arrays LCPπ and pLCPπ, which are generalizations of LCP array and pLCP array as follows:

LCPπ⁡[i]=LCE⁡(SA⁡[i],SA⁡[i+π]), where ⁢i+π≤n
pLCPπ⁡[j]=LCPπ⁡[ISA⁡[j]]=LCE⁡(j,SA⁡[ISA⁡[j]+π]), where ⁢ISA⁡[j]+π≤n

The encoding technique by Sadakane (see Lemma 2) extends to the pLCPπ array as follows.

Lemma 5.

Let π≠0 be an integer parameter (positive or negative). We can encode pLCPπ in O⁢(n) bits, and return pLCPπ⁡[j] for any text position j in O⁢(1) time.

Proof.

We first prove that pLCPπ⁡[j+1]≥pLCPπ⁡[j]−1 for all j. Clearly, the inequality holds when pLCPπ⁡[j]=0. Otherwise, let SA⁡[ISA⁡[j]+π]=j′ and SA⁡[ISA⁡[j+1]+π]=j′′. Then we can see that ISA⁡[j+1]<ISA⁡[j′′]≤ISA⁡[j′+1] if π is positive and ISA⁡[j+1]>ISA⁡[j′′]≥ISA⁡[j′+1] if π is negative. In both cases, pLCPπ⁡[j+1]=LCE⁡(j+1,j′′)≥LCE⁡(j+1,j′+1)≥LCE⁡(j,j′)−1=pLCPπ⁡[j]−1. By rearranging the inequality as in the proof of Lemma 2, we obtain a non-decreasing function fπ⁢(j)=j+pLCPπ⁡[j]∈𝒪⁢(n). We store fπ as bit string B=0fπ⁢(1)⁢10fπ⁢(2)−fπ⁢(1)⁢10fπ⁢(3)−fπ⁢(2)⁢1⁢… with O⁢(1) time rank/select support in O⁢(n) bits. Then pLCPπ⁡[j] is given by fπ⁢(j)−j=(𝗌𝖾𝗅𝖾𝖼𝗍B⁢(j,1)−j)−j. ◀

Lemma 6 (Sampled pLCPπ).

Let π≠0 be an integer parameter (positive or negative) and S⊆[n] be a set of size s. There exists a standalone structure of space O⁢(s⁢log⁡(n/s)) bits that returns pLCPπ⁡[j] for any given j∈S in O⁢(1) time.

Proof.

We modify the proof in Lemma 5 as follows. Define a bit string C⁢[1⁢..⁢n], where C⁢[j]=1 iff j∈S. Define another bit string B=0fπ⁢(s1)⁢10fπ⁢(s2)−fπ⁢(s1)⁢10fπ⁢(s3)−fπ⁢(s2)⁢1⁢…, where si=𝗌𝖾𝗅𝖾𝖼𝗍C⁢(i,1). Maintain C and B as indexible dictionaries in O⁢(s⁢log⁡(n/s)) bits with efficient rank/select support. Given any j∈S, we find p=𝗋𝖺𝗇𝗄C⁢(j,1) in O⁢(1) time using a partial-rank query. Then find fπ⁢(j)=𝗌𝖾𝗅𝖾𝖼𝗍B⁢(p,1)−p and report pLCPπ⁡[j]=fπ⁢(j)−j. ◀

The Longest common suffix (LCS) array and the permuted longest common suffix (pLCS) array can also be generalized as follows.

LCSπ⁡[i]=LCE←⁢(PA⁡[i],PA⁡[i+π]), where ⁢i+π≤n
pLCSπ⁡[j]=LCSπ⁡[IPA⁡[j]]=LCE←⁢(j,PA⁡[IPA⁡[j]+π]), where ⁢IPA⁡[j]+π≤n

Since LCSπ and pLCSπ are equivalent to LCPπ and pLCPπ of the reverse of 𝖳, the following result is an immediate corollary of Lemma 6.

Corollary 7 (Sampled pLCSπ).

Let π≠0 be an integer parameter (positive or negative) and S⊆[n] be a set of size s. There exists a standalone structure of space O⁢(s⁢log⁡(n/s)) bits that returns pLCSπ⁡[j] for any given j∈S in O⁢(1) time.

3.2 The Data Structure

Assuming the availability of an FM-index of 𝖳 in its standard from as described in Section 2.4, we now present components in the relative encoding of the prefix array PA of 𝖳. For h∈[1,log∗⁡n], define Δh as (log(h)⁡n)2 round to the integer which is the next power of 2. i.e., Δh=2⌈2⁢log(h+1)⁡n⌉. Here log(h)⁡n=log⁡n if h=1 and is log⁡(log(h−1)⁡n) if h>1, and log∗⁡n is the smallest h where log(h)⁡n≤1. Therefore, Δlog∗⁡n=1. Also let Δ0=n+1. We denote the predecessor and successor of i that are multiples of Δh by ih′=Δh⋅⌊i/Δh⌋ and ih′′=Δh⋅⌈i/Δh⌉, respectively. Therefore, when Δh divides i, we have ih′=ih′′=i.

3.2.1 Technical Overview

If i is divisible by Δ1, we explicitly store PA⁡[i] using O⁢(log⁡n) bits. If i is divisible by Δ2, but not by Δ1, we encode PA⁡[i] relative to either PA⁡[i1′] or PA⁡[i1′′] (depending on the case, to be described) using log⁡Δ1 bits. Similarly, if i is divisible by Δ3, but not by Δ2, we encode PA⁡[i] relative to either PA⁡[i2′] or PA⁡[i2′′] using log⁡Δ2 bits. More generally, we encode PA⁡[i] relative to either PA⁡[if−1′] or PA⁡[if−1′′] using log⁡Δf−1 bits, where f≤log∗⁡n is the smallest integer such that i is divisible by Δf. The function Δh is chosen carefully such that the total space usage is bounded by a sum that converges to O⁢(n) bits. The algorithm for decoding PA⁡[i] works as follows: for h=1,2,…, decode either ih′ or ih′′ (depending on the case) and terminate at h=f where if′=if′′=i, thereby yielding PA⁡[i]. We present the details next.

3.2.2 Components of the Data Structure

For each h∈[1,log∗⁡n], maintain arrays PAh⁡[1,n/Δh] as described below.

  • ■

    If i is divisible by Δ1, we store PA⁡[i] explicitly in PA1 as PA1⁡[i/Δ1]=PA⁡[i].

  • ■

    If i is not divisible by Δ1, we find the smallest integer f where i is divisible by Δf; such an f∈[2,log∗⁡n] exists since Δlog∗⁡n=1. Then store a value θi in PAf as PAf⁡[i/Δf]=θi. The value θi is determined by certain nodes in the prefix tree, which in turn are based on if−1′ and if−1′′ as illustrated in Figure 1. Let u′=LCA⁡(ℓif−1′,ℓi) and u′′=LCA⁡(ℓi,ℓif−1′′), and u be the lowest node among u′ and u′′. Also let Q=str⁢(u) and node w be the child of u on the path to ℓi and β be the leading character on the edge from u to w. This means that a substring of 𝖳 matching β∘Q← ends at position PA⁡[i], and therefore starts at PA⁡[i]−|Q|. Consequently, SA⁡[𝗌𝗉⁢(β∘Q←)⁢..⁢𝖾𝗉⁢(β∘Q←)] must contain the entry PA⁡[i]−|Q|. Then θi is defined as the offset within the suffix range of β∘Q←, Specifically,

    SA⁡[𝗌𝗉⁢(β∘Q←)+θi]=PA⁡[i]−|Q|.

    Finally, 0≤θi≤𝖾𝗉⁢(β∘Q←)−𝗌𝗉⁢(β∘Q←)+1=𝗌𝗂𝗓𝖾⁢(w)<Δf−1; therefore, we can store θi using log⁡Δf−1=O⁢(log(f)⁡n) bits.

Figure 1: Here u=u′. The dashed lines denote the range leaves under the respective nodes.

While decoding PA⁡[i], the answer is readily available from PA1 if i is a multiple of Δ1. Otherwise, we utilize the relationship PA⁡[i]=SA⁡[𝗌𝗉⁢(β∘Q←)+θi]+|Q|, where θi is retrieved from PAf; however, |Q| and 𝗌𝗉⁢(β∘Q←) are not explicitly stored. To find them, we maintain the following auxiliary structures.

  • ■

    The succinct encodings of the topologies of both the suffix tree and the prefix tree.

  • ■

    For each h∈[1,log∗⁡n], we maintain a collection of structures as in Corollary 7. Precisely, for a fixed h, we assign S={j∣ISA⁡[j]⁢ is divisible by ⁢Δh−1} and make a separate structure for each non-zero value of π∈{−Δh−1,−Δh−1+Δh,…,Δh−1−Δh,Δh−1}. Note that for a fixed h, |S|=n/Δh−1 and the number of structures is 2⁢Δh−1/Δh.

This completes the description of our data structure.

3.2.3 Space Complexity Analysis

The length of PAh is n/Δh and each entry in PAh is encoded in log⁡Δh−1=O⁢(log(h)⁡n) bits. Therefore, space is n/Δh⋅log⁡Δh−1=O⁢(n/log(h)⁡n) bits for a fixed h and ∑h=1log∗⁡nnlog(h)⁡n=O⁢(n) bits for all h∈[1,log∗⁡n] combined. The tree topologies takes O⁢(n) bits. The space (in bits) required by all versions of the structures in Corollary 7 can also be bounded by O⁢(n), as shown below, resulting in an overall space complexity of O⁢(n) bits.

∑h=1log∗⁡n2⁢Δh−1Δh⋅nΔh−1⁢log⁡Δh−1=2⁢∑h=1log∗⁡nnlog(h)⁡n=O⁢(n).

3.3 Algorithm for Decoding 𝐏𝐀⁡[𝒊]

At first, compute f∈[1,log∗⁡n], the smallest integer such that Δf divides i. Then, identify nodes u′=LCA⁡(ℓif−1′,ℓi) and u′′=LCA⁡(ℓi,ℓif−1′′) in the prefix tree, and let u be the lowest node among them. This step takes only O⁢(1) time using tree encodings. Let Q=str⁢(u) and β be the leading character on the edge from u to its child w on the path to ℓi. Our next goal is to compute |Q| and the suffix range [𝗌𝗉⁢(β∘Q←),𝖾𝗉⁢(β∘Q←)] of β∘Q←, then return PA⁡[i]=SA⁡[𝗌𝗉⁢(β∘Q←)+θi]+|Q|. There are two cases.

  1. 1.

    Case u=u′ (i.e., u=u′=u′′ or u=u′≠u′′): In this case, PA⁡[i] is encoded relative to PA⁡[if−1′]. We start with an assumption that r=PA⁡[if−1′] has already been computed. Observe that |Q|=strlen⁢(u)=LCE←⁢(PA⁡[if−1′],PA⁡[i])=pLCSπ⁡[r], where π=i−if−1′. Note also that r∈S={j∣ISA⁡[j]⁢ is divisible by ⁢Δf−1} and π∈{Δh,2⁢Δh,…,Δh−1}. Recall that we already maintain the data structure of Corollary 7 for this specific choice of S and π; querying it yields pLCSπ⁡[r], and thus |Q|, in O⁢(1) time. We then infer Q←=𝖳⁢[r−|Q|+1⁢..⁢r] and invoke the steps below.

    1. (a)

      Find the suffix range [𝗌𝗉⁢(Q←),𝖾𝗉⁢(Q←)] of Q←: Find the leaf ℓg in the suffix tree, where g=ISA⁡[r−|Q|+1] (this leaf corresponds to the suffix 𝖳⁢[r−|Q|+1⁢..]), then find its ancestor v such that 𝗌𝗂𝗓𝖾⁢(v)=𝗌𝗂𝗓𝖾⁢(u), and return the range of leaves of v as the answer. Note that v exists and it can be computed via binary search, specifically O⁢(log⁡n) number of 𝗅𝖾𝗏𝖾𝗅⁢_⁢𝖺𝗇𝖼𝖾𝗌𝗍𝗈𝗋 queries. The first step requires an ISA query (in time ts⁢a), the second step takes O⁢(log⁡n) time and the third step takes O⁢(1) time.

    2. (b)

      Find β: Let [a,b] be the range of leaves of u (in the prefix tree) and let k=i−a+1. Then, ℓi will be the k-th leftmost leaf in the subtree of u, which implies β will be the k-th smallest character in BWT⁡[𝗌𝗉⁢(Q←)⁢..⁢𝖾𝗉⁢(Q←)]. So, perform a range quantile query in time tq⁢u⁢a⁢n⁢t⁢i⁢l⁢e and find β.

    3. (c)

      Find the suffix range [𝗌𝗉⁢(β∘Q←),𝖾𝗉⁢(β∘Q←)] of β∘Q←: Let x (resp., y) be the first (resp., last) occurrence of β in BWT⁡[𝗌𝗉⁢(Q←)⁢..⁢𝖾𝗉⁢(Q←)]. Then, [LF⁡[x],LF⁡[y]] will be the suffix range of β∘Q← which can be answered in O⁢(tw⁢t) time.

    4. (d)

      Compute PA⁡[i]=SA⁡[𝗌𝗉⁢(β∘Q←)+θi]+|Q| and return it. Note that θi is stored explicitly, and hence this step takes 𝒪⁢(ts⁢a) time.

    Total time is O⁢(ts⁢a+log⁡n+tq⁢u⁢a⁢n⁢t⁢i⁢l⁢e+tw⁢t).

  2. 2.

    Case u≠u′ (i.e, u=u′′≠u′): In this case, PA⁡[i] is encoded relative to PA⁡[if−1′′]. As before, we assume that r=PA⁡[if−1′′] has already been computed. Observe that |Q|=strlen⁢(u)=LCE←⁢(PA⁡[if−1′′],PA⁡[i])=pLCSπ⁡[r], where π=i−if−1′′. Note also that r∈S={j∣ISA⁡[j]⁢ is divisible by ⁢Δf−1} and π∈{−Δh,−2⁢Δh,…,−Δh−1}. Recall that we already maintain the structure of Corollary 7 for this specific choice of S and π; querying it yields |Q|=pLCSπ⁡[r] in O⁢(1) time. We then infer Q←=𝖳⁢[r−|Q|+1⁢..⁢r], invoke the same steps as before and obtain PA⁡[i] in O⁢(ts⁢a+log⁡n+tq⁢u⁢a⁢n⁢t⁢i⁢l⁢e+tw⁢t) time.

In summary, decoding PA⁡[i] reduces to decoding either PA⁡[if−1′] or PA⁡[if−1′′] (depending on the case) in O⁢(ts⁢a+log⁡n+tq⁢u⁢a⁢n⁢t⁢i⁢l⁢e+tw⁢t) time, which recursively reduces to decoding PA⁡[if−2′] or PA⁡[if−2′′], and so forth, until reaching PA⁡[i1′] or PA⁡[i1′′], which are explicitly stored. The overall time is O⁢((ts⁢a+log⁡n+tq⁢u⁢a⁢n⁢t⁢i⁢l⁢e+tw⁢t)⋅f)⊆O⁢((τ⋅tw⁢t+log⁡n+tq⁢u⁢a⁢n⁢t⁢i⁢l⁢e)⁢log∗⁡n).

Theorem 8.

Let the Burrows-Wheeler Transform (BWT) of a text 𝖳⁢[1⁢..⁢n] be maintained in a data structure that supports basic queries (𝗋𝖺𝗇𝗄, 𝗌𝖾𝗅𝖾𝖼𝗍, and 𝖺𝖼𝖼𝖾𝗌𝗌) in tw⁢t time, and range quantile queries in tq⁢u⁢a⁢n⁢t⁢i⁢l⁢e time. Then, for any parameter τ≥1, we can maintain a sampled subset of n/τ suffix array values using O⁢((n/τ)⁢log⁡n) bits of additional space, and support suffix array (SA), inverse suffix array (ISA), and longest common extension (LCE) queries in time ts⁢a=O⁢(τ⋅tw⁢t).

By maintaining an auxiliary structure of space O⁢(n) bits, we can support prefix array (PA) queries in time tp⁢a=O⁢((τ⋅tw⁢t+tq⁢u⁢a⁢n⁢t⁢i⁢l⁢e+log⁡n)⋅log∗⁡n).

By employing the multiary wavelet tree, where tw⁢t=O⁢(1+log⁡σ/log⁡log⁡n) and tq⁢u⁢a⁢n⁢t⁢i⁢l⁢e=O⁢(log⁡σ) [8], and setting τ=log⁡n, we obtain the following result.

Corollary 9.

For any text 𝖳⁢[1⁢..⁢n] over an alphabet of size σ, we can represent its Burrows–Wheeler Transform using a (multiary) wavelet tree in n⁢log⁡σ+o⁢(n)+O⁢(σ⁢log⁡n) bits of space, supporting basic wavelet tree operations (rank, select, access) in time O⁢(1+log⁡σ/log⁡log⁡n) and range quantile queries in time O⁢(log⁡σ). By maintaining some auxiliary structures of space O⁢(n) bits, we can support suffix array (SA), inverse suffix array (ISA), and longest common extension (LCE) queries in time ts⁢a=O⁢((1+log⁡σ/log⁡log⁡n)⁢log⁡n), and prefix array (PA) queries in time tp⁢a=O⁢(ts⁢a⋅log∗⁡n).

4 Relative Encoding of 𝐏𝐀 in Sublinear Space

In this section, we present an O⁢((n/δ)⁢log⁡δ)-bit (relative) encoding of PA, where δ>0 is an integer parameter. Without loss of generality, we assume that δ is a power of 2.

4.1 Basic Components

We now present several useful results.

Lemma 10 (Approximate pLCPπ in small space).

Let π≠0 be an integer parameter (positive or negative). There exists a standalone structure of space O⁢((n/δ)⁢log⁡δ) bits that returns pLCPπ≈⁡[j] in O⁢(log⁡δ) time, where pLCPπ⁡[j]−δ≤pLCPπ≈⁡[j]≤pLCPπ⁡[j].

Proof.

We obtain this result by modifying Lemma 6. The idea is to select a set S⊆{1,2,3,…,n} of sampled positions and store fπ⁢(j) values of only those j∈S. The set S is constructed as follows. Initially S={1}. Then for j=2 to n, we include j in S iff j is a multiple of δ or fπ⁢(j)−fπ⁢(j′)>δ, where j′<j is the largest value in S currently. The size of S is Θ⁢(n/δ) since fπ⁢(⋅)≤2⁢n and is non-decreasing. For a query j, we return fπ⁢(j′)−j as pLCPπ≈⁡[j], where j′ is the predecessor of j in S. The correctness follows from that fact that fπ⁢(j′)≤fπ⁢(j)=pLCPπ⁡[j]+j≤fπ⁢(j′)+δ and j′≤j≤j′+δ, which implies pLCPπ⁡[j]−δ≤fπ⁢(j′)−j≤pLCPπ⁡[j].

We now present the implementation details. Define a bit string C corresponding to S, where C⁢[j]=1 iff j∈S. Define another bit string B=0fπ⁢(s1)⁢10fπ⁢(s2)−fπ⁢(s1)⁢10fπ⁢(s3)−fπ⁢(s2)⁢1⁢…, where si=𝗌𝖾𝗅𝖾𝖼𝗍C⁢(i,1). We maintain both C and B as indexible dictionaries with efficient rank/select support. The space required is O⁢((n/δ)⁢log⁡δ) bits since both B and C are of size O⁢(n) with Θ⁢(n/δ) number of 1’s. To recover an approximate value of pLCPπ⁡[j], we first find k=δ⁢⌊j/δ⌋∈S and r=𝗋𝖺𝗇𝗄C⁢(k,1) using a partial rank query in O⁢(1) time. Then j′, the predecessor of j in S is 𝗌𝖾𝗅𝖾𝖼𝗍C⁢(t,1) for the t∈[r,r+δ], where 𝗌𝖾𝗅𝖾𝖼𝗍C⁢(t,1)≤j<𝗌𝖾𝗅𝖾𝖼𝗍C⁢(t+1,1), which can be computed in O⁢(log⁡δ) time via binary search. Finally, get fπ⁢(j′)=𝗌𝖾𝗅𝖾𝖼𝗍B⁢(t,1)−t and return pLCPπ≈⁡[j]=fπ⁢(j′)−j. ◀

Lemma 11 (Approximate pLCSπ in small space).

Let π≠0 be an integer parameter (positive or negative). There exists a standalone structure of space O⁢((n/δ)⁢log⁡δ) bits that returns pLCSπ≈⁡[j] in O⁢(log⁡δ) time, where pLCSπ⁡[j]−δ≤pLCSπ≈⁡[j]≤pLCSπ⁡[j].

Proof.

Follows from Lemma 10, because pLCSπ is equivalent to pLCPπ of text’s reverse. ◀

Lemma 12 (Exact pLCP in small space).

By maintaining an O⁢((n/δ)⁢log⁡δ)-bit auxiliary structure with the FM-index, we can return pLCP⁡[j] for any j in O⁢(δ⋅tw⁢t+ts⁢a) time.

Proof.

Maintain the structure in Lemma 10 for π=1. Let j′=SA⁡[ISA⁡[j]+1], then pLCP⁡[j]=LCE⁡(j,j′). Find h=pLCPπ≈⁡[j] first. Now we know LCE⁡(j,j′)=h+LCE⁡(j+h,j′+h) and LCE⁡(j+h,j′+h)≤δ. Therefore, simply extract the substrings 𝖳[j+h..j+h+δ) and 𝖳[j′+h..j′+h+δ) and compute LCE⁡(j+h,j′+h) naively. ◀

Lemma 13 (Exact LCE⁡(⋅,⋅) in small space).

By maintaining an O⁢((n/δ)⁢log⁡δ)-bit auxiliary structure with FM-index, we can return LCE⁡(i,j) in time tLCE=O⁢((δ⋅tw⁢t+ts⁢a)⋅δ) time.

Proof.

We divide the LCP array into blocks of size δ. i.e., LCP⁡[1⁢..⁢δ],LCP⁡[δ+1⁢..⁢2⁢δ],LCP⁡[2⁢δ+1⁢..⁢3⁢δ], etc. Also let LCP′⁡[x] be the smallest element in x-th block. Maintain a range minimum query structure over LCP′ array (space required is 2⁢n/δ+o⁢(n/δ) bits). Besides this, we will use the result in Lemma 12. When a query (i,j) comes, we compute LCE⁡(i,j) as follows. Let i′=ISA⁡[i] and j′=ISA⁡[j]. Without loss of generality, lets assume that i′<j′. To efficiently find our answer mink∈[i′,j′)⁡LCP⁡[k], we invoke the following procedure.

  • ■

    If j′−i′<3⁢δ, we extract LCP⁡[k]=pLCP⁡[SA⁡[k]]⁢∀k∈[i′,j′) and return the minimum.

  • ■

    Otherwise, we extract LCP⁡[k]=pLCP⁡[SA⁡[k]]⁢∀k∈[i′,i′+δ)∪(δ⋅k′,δ⋅k′+δ]∪(j′−δ,j′), where k′=RMQLCP′⁡(1+⌈i′/δ⌉,⌊j′/δ⌋) and return the minimum.

In both cases, we are required to make two ISA queries, O⁢(δ) number of SA queries, followed by O⁢(δ) number of pLCP⁡[⋅] queries, which makes the total time O⁢((δ⋅tw⁢t+ts⁢a)⁢δ). ◀

4.2 The Data Structure

4.2.1 Technical Overview

We categorize a query PA⁡[i] as Type-A if i is divisible by δ (recall that δ is a power of 2), and as Type-B otherwise. These two types are handled separately. For Type-A queries, we modify our O⁢(n)-bit solution in a relatively simple manner. Instead of maintaining structures up to log∗⁡n levels, we stop at an earlier stage, which suffices to handle such queries and also helps bound the space. Furthermore, we substitute the standard suffix and prefix tree topologies with their sampled counterparts. However, for Type-B queries, we first decode the PA values of the predecessor and the successor which are multiples of δ (i.e., i′=δ⁢⌊i/δ⌋ and i′′=δ⁢⌈i/δ⌉), by treating them as Type-A queries. Then, we decode all the entries in PA⁡[i′⁢..⁢i′′], first in an unsorted manner; afterward, we sort them to obtain PA⁡[i]. We accomplish this by splitting this range into the minimal number of subranges such that each subrange corresponds to a subtree of the prefix tree, and processing each subrange carefully. This part is more technical.

4.2.2 Handling Type-A Queries

Observe that our O⁢(n)-bit encoding of PA composed of two tree topologies and several components corresponding to each h∈[1,log∗⁡n]. However, only the components corresponding to h∈[1,f] are utilized when decoding PA⁡[i], where f is the smallest integer in [1,log∗⁡n] such that Δf divides i (recall that Δh is (log(h)⁡n)2 round to the next power of 2). We exploit this fact to design a space efficient structure for Type-A queries. Let λ∈[1,log∗⁡n] be the integer, where Δλ+1<δ2≤Δλ. We now maintain the components in Section 3.2.2 for only selected values of h (with some modifications) as follows:

  1. 1.

    All values of h∈[1,λ−1];

  2. 2.

    h=λ, but modify the value of Δh to δ2.

  3. 3.

    h=λ+1, but modify the value of Δh to δ.

The resulting space in bits is

2⁢∑h=1λ+1nΔh⁢log⁡Δh−1≤2⁢nδ⁢log⁡δ2+2⁢nδ2⁢log⁡Δλ−1+2⁢∑h=1λ−1nΔh⁢log⁡Δh−1=O⁢((n/δ)⁢log⁡δ).

Our previous algorithm (as described in Section 3.3) can be applied to determine PA⁡[i] with the same time complexity. However, the topologies of suffix tree and prefix tree still takes O⁢(n) bits. We replace them with the topologies of the sparse prefix tree (SPT) and sparse suffix tree (SST), which require less space. Additionally, we maintain the small space structure in Lemma 13 supporting LCE queries.

Replacing Prefix Tree with Sparse Prefix Tree (SPT)

We sample a subset of O⁢(n/δ) nodes in the prefix tree as follows:

  1. 1.

    leaves ℓk, where k is a multiple of δ;

  2. 2.

    the lowest common ancestor (LCA) of every pair of consecutive leaves sampled in step 1;

  3. 3.

    the leftmost and rightmost descendant leaves of sampled nodes obtained in step 2.

Let ℒ be the set of sampled leaves obtained after the above procedure. Then, the SPT is the compacted trie built from the reverse of circular prefixes corresponding only to the leaves in ℒ – that is, a sparse prefix tree. We maintain its topology in succinct space and a bit string B⁢[1⁢..⁢n], where B⁢[k]=1 iff ℓk∈ℒ, as an indexible dictionary. The space required is O⁢((n/δ)⁢log⁡δ) bits as there are 𝒪⁢(nδ) 1’s in B. We now present some useful results.

Lemma 14.

Given two sampled leaves ℓk,ℓk′ in the prefix tree, the size of their LCA can be returned in O⁢(1) time using SPT and the associated bit string.

Proof.

The sampled leaf ℓk (resp., ℓk′) in the prefix tree corresponds to the leaf ℓ𝗋𝖺𝗇𝗄B⁢(k,1) (resp., ℓ𝗋𝖺𝗇𝗄B⁢(k′,1)) in SPT. Therefore, find the range [s,e] of leaves in the subtree of the node LCA⁡(ℓ𝗋𝖺𝗇𝗄B⁢(k,1),ℓ𝗋𝖺𝗇𝗄B⁢(k′,1)) in SPT and return 𝗌𝖾𝗅𝖾𝖼𝗍B⁢(e,1)−𝗌𝖾𝗅𝖾𝖼𝗍B⁢(s,1)+1. ◀

The prefix tree topology play the following role in our earlier algorithm. Given i, (i) find which among the nodes u′=LCA⁡(ℓif−1′,ℓi) and u′′=LCA⁡(ℓi,ℓif−1′′) is lower (call it u) to decide which case to use in the decoding procedure and (ii) return the range of leaves [a,b] of u (note that we don’t require the pre-order rank of u). Since i,if−1′,if−1′′ are all divisible by δ (hence sampled) in the case of Type-A queries, we can apply Lemma 14 and find the range of leaves of u′ and u′′ first, then infer u=u′ iff the range of u′ is the same or contained within the range of u′′. The subsequent steps in the recurrence also work since both ih′ and ih′′ are divisible by δ for all h≤f. In summary, a sparse prefix tree topology can perform the required functionalities in our algorithm without any performance slowdown.

Replacing Suffix Tree with Sparse Suffix Tree (SST)

The SST is the compacted trie constructed from the circular suffixes corresponding to the leaves ℓk of the suffix tree, where k is a multiple of δ. We maintain its topology in succinct space, requiring O⁢(n/δ) bits.

The suffix tree topology serves the purpose of finding the suffix range [𝗌𝗉⁢(Q←),𝖾𝗉⁢(Q←)] of Q← in O⁢(log⁡n) time, given (i) the length of Q (this can be computed using pLCSπ as in Section 3.3), (ii) a leaf ℓg in the suffix tree, where Q← is a prefix of str⁢(ℓg), (iii) the size of the suffix range of Q, i.e., 𝖾𝗉⁢(Q←)−𝗌𝗉⁢(Q←)+1 (specifically, 𝗌𝗂𝗓𝖾⁢(u) is given, where u is a node in the prefix tree). It is worth noting that this task can be accomplished without the suffix tree topology, and even without the third input parameter. We can exploit the fact that LCE⁡(SA⁡[g],SA⁡[p])≥|Q| if and only if p∈[𝗌𝗉⁢(Q←),𝖾𝗉⁢(Q←)], and hence we can apply binary search on p and determine the answer using O⁢(log⁡n) LCE queries.

We speed up this process by using the additional information in (iii) as follows. If 𝗌𝗂𝗓𝖾⁢(u)≤2⁢δ, we still apply the binary search. The number of LCE/SA queries required is O⁢(log⁡δ). Otherwise, find an approximate range using SST first, and then apply binary search on ranges of size O⁢(δ) as follows.

  1. 1.

    Find a value g∗ closer to g, such that g∗ is a multiple of δ (thus ℓg∗ is sampled) and str⁢(ℓg∗) is also prefixed by Q← as follows. Let g′=δ⁢⌊g/δ⌋ and g′′=δ⁢⌈g/δ⌉. We fix g∗=g′ if LCE⁡(SA⁡[g],SA⁡[g′])≥|Q|, otherwise g∗=g′′ (in this case LCE⁡(SA⁡[g],SA⁡[g′′])≥|Q| is guaranteed as 𝗌𝗂𝗓𝖾⁢(u)>2⁢δ).

  2. 2.

    Find (g∗/δ)-th leaf in SST, and return the range [s⁢p∗,e⁢p∗] of leaves of its lowest ancestor with 𝗌𝗂𝗓𝖾⁢(⋅)≥⌊𝗌𝗂𝗓𝖾⁢(u)/δ⌋−1. This step takes only O⁢(log⁡n) time (via 𝗅𝖾𝗏𝖾𝗅⁢_⁢𝖺𝗇𝖼𝖾𝗌𝗍𝗈𝗋 queries as before, but on SST). Observe that our sampling scheme guarantees 𝗌𝗉⁢(Q←)∈[δ⋅s⁢p∗−O⁢(δ),δ⋅s⁢p∗] and 𝖾𝗉⁢(Q←)∈[δ⋅e⁢p∗,δ⋅e⁢p∗+O⁢(δ)]. Therefore we can now restrict our binary search into a smaller range of size O⁢(δ), requiring only O⁢(log⁡δ) LCE and SA queries.

This subroutine for finding suffix range [𝗌𝗉⁢(Q←),𝖾𝗉⁢(Q←)] of Q← takes O⁢(log⁡n+(ts⁢a+tLCE)⋅log⁡δ)∈O⁢(log⁡n+(δ⋅tw⁢t+ts⁢a)⁢δ⋅log⁡δ) time. After that, we continue with steps (b), (c), and (d) as in Section 3.3.

Figure 2: Illustration of Type-B queries.

By substituting the space–time complexities of the components, incorporating updated data structures, we obtain the following bound for Type-A queries.

Lemma 15 (Type-A Queries).

By maintaining auxiliary structures of space O⁢((n/δ)⁢log⁡δ) bits in total, we can answer Type-A queries in time

O⁢((log⁡n+tq⁢u⁢a⁢n⁢t⁢i⁢l⁢e+(δ⋅tw⁢t+ts⁢a)⁢δ⋅log⁡δ)⁢log∗⁡n).

4.2.3 Handling Type-B Queries

Type-B queries require a more involved solution than Type-A queries. Maintain the structure in Lemma 11 supporting pLCSπ≈ queries, for values of π in {−1,+1}. Also associate O⁢(log⁡δ) bits of satellite information (to be defined shortly) with each integer in [1,n] that is a multiple of δ. The total space is O⁢((n/δ)⁢log⁡δ) bits.

To retrieve PA⁡[i], where i is not divisible by δ, we employ a procedure that decodes a segment of PA containing PA⁡[i]. Let i′=δ⁢⌊i/δ⌋, i′′=δ⁢⌈i/δ⌉=i′+δ, and u=LCA⁡(ℓi′,ℓi′′). We now proceed to define some nodes in the prefix tree as illustrated in Figure 2.

  • ■

    x1,x2,…,xd are nodes that lie on the path from ℓi′ to u (excluding endpoints), ordered in descending 0⁢p⁢t⁢(⋅), such that x0=ℓi′ and xk for k∈[1,d] is the lowest ancestor of xk−1 whose child on the path to ℓi′ has a right sibling. Let [⋅,bk] denote the range of leaves of xk for k∈[0,d]. Therefore, (i′,bd] denotes the range of leaves after i′, such that the LCA of any of those leaves with ℓi′ is a node in {x1,x2,…,xd}. The following observation allows us to jump from node xk−1 to node xk for all k∈[1,d].

Observation 16.

For all k∈[1,d] we have LCA⁡(ℓbk−1,ℓbk−1+1)=xk; therefore strlen⁢(xk)=pLCS+1⁡[PA⁡[bk−1]].

  • ■

    y1,y2,…,yf are nodes that lie on the path from ℓi′′ to u (excluding endpoints), ordered by descending 0⁢p⁢t⁢(⋅), such that y0=ℓi′′ and yk for k∈[1,f] is the lowest ancestor of yk−1 whose child on the path to ℓi′′ has a left sibling. Let [ak,⋅] denote the range of leaves of yk for k∈[0,f]. Therefore, [af,i′′) denotes the range of leaves before i′′, such that the LCA of any of those leaves with ℓi′′ belongs to {y1,y2,…,yf}. The following observation allows us to jump from node yk−1 to node yk for all k∈[1,f].

Observation 17.

For all k∈[1,f], we have LCA⁡(ℓak−1,ℓak−1−1)=yk; therefore strlen⁢(yk)=pLCS−1⁡[PA⁡[ak−1]].

Our procedure for decoding PA⁡[i] depends on which of the intervals (i′,bd],[bd+1,af−1], or [af,i′′) contains i. The satellite information associated with i′ is (d,f,bd−i′,af−i′) (all four values are bounded by δ), which helps to decide the case.

CASE 𝒊∈(𝒃𝟎,𝒃𝒅]

First obtain PA⁡[i′] using a Type-A query, then initialize b0=i′ and strlen⁢(x0)=PA⁡[b0], the length of the prefix ending at b0. Then decode PA⁢(b0,bd] in d steps; at step k∈[1,d], we compute strlen⁢(xk),𝗌𝗂𝗓𝖾⁢(xk),bk and PA⁢(bk−1,bk]. Note that (b0,bd]=(b0,b1]∪(b1,b2]∪…⁢(bd−1,bd]. Let Qt be the prefix of str⁢(ℓi′) of length t and αt be the (t+1)-th character of str⁢(ℓi′). Therefore, Qt←=𝖳⁢[PA⁡[i′]−t+1⁢..⁢PA⁡[i′]] and αt=𝖳⁢[PA⁡[i′]−t]. When t=strlen⁢(xk), we let Q=Qt and α=αt.

  1. 1.

    Finding 𝐬𝐭𝐫𝐥𝐞𝐧⁢(xk): Observe that strlen⁢(xk) is the largest t<strlen⁢(xk−1) such that BWT⁡[𝗌𝗉⁢(Qt←),𝖾𝗉⁢(Qt←)] contains a character βt>αt. However, finding [𝗌𝗉⁢(Qt←),𝖾𝗉⁢(Qt←)] can be expensive. Thankfully, we have an alternative procedure to verify this condition for a given t. Find z=ISA⁡[PA⁡[i′]−t+1], which is an entry in [𝗌𝗉⁢(Qt←),𝖾𝗉⁢(Qt←)], then find the largest number z′ before z, and the smallest number z′′ after z, such that BWT⁡[z′],BWT⁡[z′′]>αt=BWT⁡[z], using wavelet tree queries. The condition is satisfied if and only if LCE⁡(ISA⁡[z],ISA⁡[z′])≥t or LCE⁡(ISA⁡[z],ISA⁡[z′′])≥t. We next determine an l such that strlen⁢(xk)∈[l−δ,l], meaning we only need to iterate over the values of t in [l−δ,l] for finding strlen⁢(xk). To find l, we rely on observation 16 that xk=LCA⁡(ℓbk−1,ℓbk−1+1) and strlen⁢(xk)=pLCS⁡[PA⁡[bk−1]]. Therefore, pLCS1≈⁡[PA⁡[bk−1]]≤strlen⁢(xk)≤pLCS1≈⁡[PA⁡[bk−1]]+δ, and we compute pLCS1≈⁡[PA⁡[bk−1]] in O⁢(log⁡δ) time (see Lemma 11), and set l=min⁡{strlen⁢(xk−1)−1,pLCS1≈⁡[PA⁡[bk−1]]+δ}. The total time is O⁢((tw⁢t+ts⁢a+tLCE)⁢δ)⊆O⁢(tLCE⋅δ).

  2. 2.

    Finding 𝗌𝗂𝗓𝖾⁢(xk): At first, we find an approximation 𝗌𝗂𝗓𝖾≈⁢(xk)∈[𝗌𝗂𝗓𝖾⁢(xk)−2⁢δ,𝗌𝗂𝗓𝖾⁢(xk)] using SPT and the associated bit vector B as follows. Note that xk=LCA⁡(ℓi′,ℓbk−1+1) and the leaf ℓi′ is sampled (recall SPT’s construction). Therefore, if ℓbk−1+1 is also sampled (i.e., B[bk−1+1]=1), then we can find the exact value of 𝗌𝗂𝗓𝖾⁢(xk) in O⁢(1) time using Lemma 14. Otherwise, find the leaves ℓ𝗋𝖺𝗇𝗄B⁢(bk−1+1,1),ℓ𝗋𝖺𝗇𝗄B⁢(bk−1+1,1)+1 in SPT, the child of their LCA on the path to ℓ𝗋𝖺𝗇𝗄B⁢(i′,1), and the range [s,s′] of leaves of that child. Then return 𝗌𝖾𝗅𝖾𝖼𝗍B⁢(s′,1)−𝗌𝖾𝗅𝖾𝖼𝗍⁢(s,1)+1 as 𝗌𝗂𝗓𝖾≈⁢(xk). Our sampling scheme guarantees that the value returned lies in the range [𝗌𝗂𝗓𝖾⁢(xk)−2⁢δ,𝗌𝗂𝗓𝖾⁢(xk)]. The time complexity is O⁢(1). We now proceed to computing the exact value of 𝗌𝗂𝗓𝖾⁢(xk). Since Q=str⁢(xk), we have 𝗌𝗂𝗓𝖾⁢(xk)=𝖾𝗉⁢(Q←)−𝗌𝗉⁢(Q←)+1. Therefore we compute the range [𝗌𝗉⁢(Q←),𝖾𝗉⁢(Q←)] as follows. To begin with, we know an entry ISA⁡[PA⁡[i′]−|Q|+1]∈[𝗌𝗉⁢(Q←),𝖾𝗉⁢(Q←)], as well as 𝗌𝗂𝗓𝖾≈⁢(xk). At the point, we can follow the same procedure detailed in Section 4.2.2, where we first identify an approximate range that is sufficiently close to the actual one using sparse suffix tree in O⁢(log⁡n) time, then perform a binary search requiring only O⁢(log⁡δ) LCE and ISA queries. The time required is O⁢(log⁡n+(ts⁢a+tLCE)⋅log⁡δ)⊆O⁢(log⁡n+tLCE⋅log⁡δ).

  3. 3.

    Finding bk: Let α be the leading character on the path from xk to its child on the path to ℓi′. Count the entries in BWT⁡[𝗌𝗉⁢(Q←),𝖾𝗉⁢(Q←)] that are above α=𝖳⁢[PA⁡[i′]−|Q|] (using a wavelet tree query). This gives the number of leaves in the range (bk−1,bk]. Therefore we simply add bk−1 with this count and return as bk. Time required is O⁢(tw⁢t).

  4. 4.

    Finding 𝐏𝐀⁢(bk−𝟏,bk]: The set 𝒫={SA⁡[z]+|Q|−1⁢∣z∈[𝗌𝗉⁢(Q←),𝖾𝗉⁢(Q←)],BWT⁡[z]>⁢α} is a collection of elements in PA⁢(bk−1,bk], which can be obtained in O⁢(tw⁢t+ts⁢a) time per element using wavelet tree and SA⁡[⋅] queries. However, we do not know the order in which they appear in PA⁢(bk−1,bk]; therefore our next goal is to recover PA⁢(bk−1,bk] by sorting the elements in 𝒫 in the ascending order of their IPA⁡[⋅] values. We first present a simple solution, and then describe a slightly improved one.

    1. (a)

      A simple solution using 𝐋𝐂𝐄←⁢(⋅,⋅) queries: By fixing D=δ⁢log⁡n, we maintain the structure in Lemma 4 without changing the asymptotic space complexity, which supports LCE←⁢(⋅,⋅) queries in O⁢(tLCE⋅log⁡(δ⁢log⁡n)) time. Then, for any p,q∈𝒫, we can decide the relative order of IPA⁡[p] and IPA⁡[q] by comparing the characters 𝖳⁢[p−LCE←⁢(p,q)] and 𝖳⁢[q−LCE←⁢(p,q)]. Therefore, an efficient comparison-based sorting algorithm (such as merge sort) can be used to sort the elements of 𝒫 in ascending order of their IPA⁡[⋅] values using O⁢((bk−bk−1)⁢log⁡(bk−bk−1)) number of LCE←⁢(⋅,⋅) queries. The resulting time complexity for this step is

      (bk−bk−1)log(bk−bk−1)⋅tLCE⋅(log(δlogn)⊆O((bk−bk−1)logδ⋅tLCE⋅(logδ+loglogn)).
    2. (b)

      An alternative solution: Our goal here is to avoid the direct use of LCE←⁢(⋅,⋅) queries, and thereby removing the log⁡log⁡n term in the previous time complexity. To achieve this, we reconstruct the subtree rooted at xk on the fly. For any node w in the subtree rooted at xk, let 𝒫⁢(w)⊆𝒫 denotes the set of PA⁡[⋅] values corresponding to the leaves in the subtree of w. Iterating over p∈𝒫, our algorithm return the sets 𝒫⁢(w1),𝒫⁢(w2),…, in that order, where nodes w1,w2,… are the children (in the left to right order) of node w=LCA⁡(ℓIPA⁡[p],ℓIPA⁡[p]+1). Note that the preorder rank of w is not known even after processing p. Therefore, based on 𝒫⁢(w), we assign to w a unique label, defined as the ordered pair consisting of the size of 𝒫⁢(w) and the smallest element of 𝒫⁢(w). With this labeling and parent–child information for all internal nodes, we can easily reconstruct the tree in a top-down fashion and recover PA⁢(bk−1,bk]. We now present the details of processing a specific p∈𝒫. The first step is to compute strlen⁢(w)=pLCS⁡[p], which is given by the expression below when p≠PA⁡[bk] (in that case PA⁡[IPA⁡[p]+1]∈𝒫); when p=PA⁡[bk], it will not return any value.

      max⁡{LCE←⁢(p,q)∣q∈𝒫\{p},T⁢[1⁢..⁢q]←⁢ comes after ⁢T⁢[1⁢..⁢p]←⁢ lexicographically}

      Instead of evaluating this expression by applying LCE←⁢(⋅,⋅) directly, we compute L=pLCS≈⁡[p] in O⁢(log⁡δ) time (see Lemma 11), where pLCS⁡[p]−δ≤L≤pLCS⁡[p]. Then, iterate over q∈𝒫, compute LCE⁡(p−L+1,q−L+1), and consider the following two cases:

      1. i.

        If LCE⁡(p−L+1,q−L+1)<L, then we know LCE←⁢(p,q)<L≤strlen⁢(w). Therefore discard q.

      2. ii.

        Otherwise we have LCE←⁢(p,q)=L+LCE←⁢(p−L,q−L). In that case, extract the substrings 𝖳⁢[p−L−δ⁢..⁢p−L] and 𝖳⁢[q−L−δ⁢..⁢q−L] and compare them. If the substrings differ, we can compute LCE←⁢(p−L,q−L) (thus compute LCE←⁢(p,q)) and determine their lexicographic order (and thus the lexicographic order of T⁢[1⁢..⁢q]← and T⁢[1⁢..⁢p]←). If the substrings match, we infer that LCE←⁢(p,q)>L+δ≥strlen⁢(w), and therefore both ℓIPA⁡[q] and ℓIPA⁡[p] lie in the subtree of the same child of w, and T⁢[1⁢..⁢q]← comes before T⁢[1⁢..⁢p]← in lexicographically.

      The above step for a specific p,q takes O⁢(tLCE+ts⁢a+δ⋅tw⁢t) time. By taking the maximum value of LCE⁡(p,q)← over all q that satisfy the required condition on the lexicographic order, we obtain strlen⁢(w). We next collect all positions q such that LCE←⁢(p,q)≥strlen⁢(w), group them into sets according to the character T⁢[q−strlen⁢(w)], and output these sets in order of increasing character value they correspond to. It is straightforward to verify that the sets produced in this manner are exactly 𝒫⁢(w1),𝒫⁢(w2),…. Moreover, every internal node in the subtree rooted at xk will be processed after we have iterated over all p∈𝒫\{PA⁡[bk]}. The overall time complexity of this step is O⁢((bk−bk−1)2⋅(tLCE+ts⁢a+δ⋅tw⁢t))⊆O⁢((bk−bk−1)2⋅tLCE).

    We use the second method, although its time complexity is quadratic in the size of the tree, because the first method would add extra log⁡log⁡n factors to the time complexity.

The combined time for all 4 steps for all k∈[1,d], where d≤δ is bounded as follows:

∑k=1d(tLCE⋅δ+(log⁡n+tLCE⋅log⁡δ)+tw⁢t+(bk−bk−1)2⋅tLCE)
≤tLCE⋅δ2+(log⁡n+tLCE⋅log⁡δ)⋅δ+tw⁢t⋅δ+(bd−b0)2⋅tLCE

By substituting bd−b0=O⁢(δ) and tLCE=O⁢((ts⁢a+δ⋅tw⁢t)⁢δ), the expression simplifies to O⁢(δ⋅log⁡n+(ts⁢a+δ⋅tw⁢t)⁢δ3).

CASE 𝒊∈[𝒃𝒅+𝟏,𝒂𝒇−𝟏]

Let Q=str⁢(u) and α be the leading character on the path from u to its child on the path to ℓi′ and β be the leading character on the path from u to its child on the path to ℓi′′. Then the set 𝒫={SA⁡[z]+|Q⁢|−1∣⁢z∈[𝗌𝗉⁢(Q←),𝖾𝗉⁢(Q←)],BWT⁡[z]∈[α+1,β−1]} is the collection of elements in PA⁡[bd+1,af−1]. Since 𝗌𝗂𝗓𝖾⁢(u), strlen⁢(u),PA⁡[i′],PA⁡[i′′] are readily available (via Type-A query), the elements in the set 𝒫 can be easily extracted in time O⁢(tw⁢t+ts⁢a) per element, but not in the order as they appear in PA. Finally, to recover PA⁡[bd+1,af−1], we follow the same procedure as in the first case. The resulting time is O⁢((ts⁢a+δ⋅tw⁢t)⁢δ3).

CASE 𝒊∈[𝒂𝒇,𝒊′′)

Here we obtain PA⁡[i′′] first using a Type-A query, then initialize a0=i′′ and strlen⁢(y0)=PA⁡[a0], the length of the prefix ending at a0. Then decode PA⁢[af,a0) in f steps, where at step k∈[1,f], we compute strlen⁢(yk), 𝗌𝗂𝗓𝖾⁢(yk), ak and PA⁢[ak,ak−1). Note that [af,a0)=[af,af−1)∪⋯∪[a2,a1)∪[a1,a0). Suppose Q=str⁢(yk) and β=𝖳⁢[PA⁡[i′′]−|Q|], then the set elements in PA⁢[ak,ak−1) is given by 𝒫={SA⁡[z]+|Q⁢|−1∣⁢z∈[𝗌𝗉⁢(Q←),𝖾𝗉⁢(Q←)],BWT⁡[z]<β}. This is analogous to that of the first case, therefore we invoke a symmetric procedure to handle this case. In contrast to the first case, where we rely on Observation 16 and use pLCS1≈⁡[⋅] queries, here we rely on Observation 17 and use pLCS−1≈⁡[⋅] queries. Total time is O⁢(δ⋅log⁡n+(ts⁢a+δ⋅tw⁢t)⁢δ3) time (similar to the first case).

Lemma 18 (Type-B Queries).

The combined space of all auxiliary structures for Type-B queries is O⁢((n/δ)⁢log⁡δ) bits and the query time is O⁢(δ⋅log⁡n+(δ⋅tw⁢t+ts⁢a)⁢δ3).

By combining Lemma 15 and Lemma 18, we obtain the Theorem below.

Theorem 19.

Let the Burrows-Wheeler Transform (BWT) of a text 𝖳⁢[1⁢..⁢n] be maintained in a data structure that supports basic queries (𝗋𝖺𝗇𝗄, 𝗌𝖾𝗅𝖾𝖼𝗍, and 𝖺𝖼𝖼𝖾𝗌𝗌) in tw⁢t time, and range quantile queries in tq⁢u⁢a⁢n⁢t⁢i⁢l⁢e time. Then, for any parameter τ≥1, we can maintain a sampled subset of n/τ suffix array values using O⁢((n/τ)⁢log⁡n) bits of additional space, and support suffix array (SA) and inverse suffix array (ISA) queries in time ts⁢a=O⁢(τ⋅tw⁢t). By maintaining an auxiliary structure of space O⁢((n/δ)⁢log⁡δ) bits for a parameter δ, we can support prefix array (PA) queries in time

tp⁢a=O((logn⋅(log∗n+δ)+tq⁢u⁢a⁢n⁢t⁢i⁢l⁢e⋅log∗n+(δ+τ)⋅tw⁢t⋅(δlogδlog∗n+δ3))
⊆O⁢((log⁡n+tq⁢u⁢a⁢n⁢t⁢i⁢l⁢e+(δ+τ)⋅tw⁢t)⋅(δ⁢log⁡δ⁢log∗⁡n+δ3)).

Additionally we can support LCE⁡(⋅,⋅) queries in time tLCE=O⁢((δ⋅tw⁢t+ts⁢a)⁢δ) and LCE←⁢(⋅,⋅) queries in time O⁢(tLCE⋅(log⁡δ+log⁡log⁡n)).

By employing the multiary wavelet tree, where tw⁢t=O⁢(1+log⁡σ/log⁡log⁡n), tq⁢u⁢a⁢n⁢t⁢i⁢l⁢e=O⁢(log⁡σ) and setting δ=κ⁢log⁡κ and τ=κ⁢log⁡n, we obtain the following result.

Corollary 20.

Let 𝖳⁢[1⁢..⁢n] be a text over an alphabet of size σ. We can maintain its Burrows-Wheeler Transform (BWT) as a wavelet tree data structure in n⁢log⁡σ+o⁢(n)+O⁢(σ⁢log⁡n) bits that supports basic queries (rank, select, access) in time O⁢(1+log⁡σ/log⁡log⁡n) and range quantile queries in time O⁢(log⁡σ). For an integer parameter κ, we can maintain an auxiliary structure of space O⁢(n/κ) bits and support suffix array (SA) and inverse suffix array (ISA) queries in time ts⁢a=O⁢((1+log⁡σ/log⁡log⁡n)⋅κ⁢log⁡n), and prefix array (PA) queries in time tp⁢a=ts⁢a⋅O⁢((κ3⁢log⁡κ+κ⁢log∗⁡n)⋅log2⁡κ).

Additionally we can support LCE⁡(⋅,⋅) queries in time tLCE=O⁢(ts⁢a⋅κ⁢log⁡κ) and LCE←⁢(⋅,⋅) queries in time O⁢(tLCE⋅(log⁡κ+log⁡log⁡n)).

5 A Note On Inverse Prefix Array (IPA) Queries

We present a simple approach for supporting IPA⁡[⋅] queries. Assuming the availability of data structures supporting PA⁡[⋅] and LCE⁡(⋅,⋅) queries, we maintain the auxiliary structure from Lemma 4 with the parameter set to D=κ⁢log⁡n. This structure requires O⁢(n/κ) additional bits of space and supports LCE←⁢(⋅,⋅) queries in LCE←⁢(⋅,⋅) time O⁢(tLCE⋅log⁡(κ⁢log⁡n)).

Given a text position j, we compute IPA⁡[j] by performing a binary search over i∈[1,n]. For a candidate index i, we first compute x=PA⁡[i]. If x=j, we return i and terminate the search. Otherwise, we compute l=LCE←⁢(x,j) and compare the characters 𝖳⁢[x−l] and 𝖳⁢[j−l] (which must be different). If 𝖳⁢[x−l]<𝖳⁢[j−l], then we conclude that i<IPA⁡[j]; otherwise, i>IPA⁡[j]. This provides the necessary comparison predicate for binary search. The time complexity is O⁢((tp⁢a+tLCE⋅log⁡(κ⁢log⁡n))⁢log⁡n)⊆O⁢(tp⁢a⋅log⁡n⋅log⁡log⁡n).

Theorem 21.

With the structure described in Theorem 19, we can maintain an auxiliary data structure of space O⁢(n/κ) bits that supports inverse prefix array (IPA) queries in time O⁢(tp⁢a⋅log⁡n⋅log⁡log⁡n).

6 Conclusions

We present a solution for encoding the suffix array and inverse suffix array of the reversed text, assuming the availability of the FM-index of the original text. We can answer suffix array queries on the reversed text in time close to that of suffix array queries on the original text. However, for inverse suffix array queries on the reversed text, we require roughly a factor of (log⁡n) more time than for inverse suffix array queries on the original text. Narrowing this gap is an interesting problem, which we leave open for future research.

References

  • [1] Paniz Abedin, Oliver A. Chubet, Daniel Gibney, and Sharma V. Thankachan. Contextual pattern matching in less space. In Data Compression Conference, DCC 2023, Snowbird, UT, USA, March 21-24, 2023, pages 160–167. IEEE, 2023. doi:10.1109/DCC55655.2023.00024.
  • [2] Amihood Amir, Dmitry Keselman, Gad M. Landau, Moshe Lewenstein, Noa Lewenstein, and Michael Rodeh. Text indexing and dictionary matching with one error. J. Algorithms, 37(2):309–325, 2000. doi:10.1006/JAGM.2000.1104.
  • [3] Djamal Belazzougui, Travis Gagie, Simon Gog, Giovanni Manzini, and Jouni Sirén. Relative fm-indexes. In String Processing and Information Retrieval: 21st International Symposium, SPIRE 2014, Ouro Preto, Brazil, October 20-22, 2014. Proceedings 21, pages 52–64. Springer, 2014. doi:10.1007/978-3-319-11918-2_6.
  • [4] Philip Bille, Inge Li Gørtz, Mathias Bæk Tejs Knudsen, Moshe Lewenstein, and Hjalte Wedel Vildhøj. Longest common extensions in sublinear space. In Ferdinando Cicalese, Ely Porat, and Ugo Vaccaro, editors, Combinatorial Pattern Matching - 26th Annual Symposium, CPM 2015, Ischia Island, Italy, June 29 - July 1, 2015, Proceedings, volume 9133 of Lecture Notes in Computer Science, pages 65–76. Springer, 2015. doi:10.1007/978-3-319-19929-0_6.
  • [5] Michael Burrows. A block-sorting lossless data compression algorithm. SRS Research Report, 124, 1994.
  • [6] Andrea Farruggia, Travis Gagie, Gonzalo Navarro, Simon J Puglisi, and Jouni Sirén. Relative suffix trees. The Computer Journal, 61(5):773–788, 2018. doi:10.1093/COMJNL/BXX108.
  • [7] Paolo Ferragina and Giovanni Manzini. Opportunistic data structures with applications. In Proceedings of the 41st Annual Symposium on Foundations of Computer Science, pages 390–398. IEEE, 2000. doi:10.1109/SFCS.2000.892127.
  • [8] Paolo Ferragina, Giovanni Manzini, Veli Mäkinen, and Gonzalo Navarro. Compressed representations of sequences and full-text indexes. ACM Trans. Algorithms, 3(2):20, 2007. doi:10.1145/1240233.1240243.
  • [9] Johannes Fischer and Volker Heun. Space-efficient preprocessing schemes for range minimum queries on static arrays. SIAM J. Comput., 40(2):465–492, 2011. doi:10.1137/090779759.
  • [10] Travis Gagie, Gonzalo Navarro, and Nicola Prezza. Fully functional suffix trees and optimal text searching in BWT-runs bounded space. J. ACM, 67(1):2:1–2:54, 2020. doi:10.1145/3375890.
  • [11] Travis Gagie, Simon J. Puglisi, and Andrew Turpin. Range quantile queries: Another virtue of wavelet trees. In String Processing and Information Retrieval (SPIRE), volume 5721 of Lecture Notes in Computer Science, pages 1–6. Springer, Berlin, Heidelberg, 2009. arXiv:0903.4726. doi:10.1007/978-3-642-03784-9_1.
  • [12] Arnab Ganguly, Daniel Gibney, Sahar Hooshmand, M. Oguzhan Külekci, and Sharma V. Thankachan. Fm-index reveals the reverse suffix array. In Inge Li Gørtz and Oren Weimann, editors, 31st Annual Symposium on Combinatorial Pattern Matching, CPM 2020, Copenhagen, Denmark, June 17-19, 2020, volume 161 of LIPIcs, pages 13:1–13:14. Schloss Dagstuhl – Leibniz-Zentrum für Informatik, 2020. doi:10.4230/LIPIcs.CPM.2020.13.
  • [13] Roberto Grossi, Ankur Gupta, and Jeffrey Scott Vitter. High-order entropy-compressed text indexes. In Proceedings of the 14th Annual ACM-SIAM Symposium on Discrete Algorithms, pages 841–850. SIAM, 2003. URL: http://dl.acm.org/citation.cfm?id=644108.644250.
  • [14] Roberto Grossi and Jeffrey Scott Vitter. Compressed suffix arrays and suffix trees with applications to text indexing and string matching. SIAM J. Comput., 35(2):378–407, 2005. doi:10.1137/S0097539702402354.
  • [15] Jesper Jansson, Kunihiko Sadakane, and Wing-Kin Sung. Ultra-succinct representation of ordered trees with applications. J. Comput. Syst. Sci., 78(2):619–631, 2012. doi:10.1016/J.JCSS.2011.09.002.
  • [16] Dominik Kempa and Tomasz Kociumaka. Collapsing the hierarchy of compressed data structures: Suffix arrays in optimal compressed space. In 64th IEEE Annual Symposium on Foundations of Computer Science, FOCS 2023, Santa Cruz, CA, USA, November 6-9, 2023, pages 1877–1886. IEEE, 2023. doi:10.1109/FOCS57990.2023.00114.
  • [17] Tak Wah Lam, Ruiqiang Li, Alan Tam, Simon C. K. Wong, Edward Wu, and Siu-Ming Yiu. High throughput short read alignment via bi-directional BWT. In 2009 IEEE International Conference on Bioinformatics and Biomedicine, BIBM 2009, Washington, DC, USA, November 1-4, 2009, Proceedings, pages 31–36. IEEE Computer Society, 2009. doi:10.1109/BIBM.2009.42.
  • [18] Ben Langmead, Cole Trapnell, Mihai Pop, and Steven L. Salzberg. Ultrafast and memory-efficient alignment of short dna sequences to the human genome. Genome Biology, 10(3):R25, 2009.
  • [19] Moshe Lewenstein. Orthogonal range searching for text indexing. In Andrej Brodnik, Alejandro López-Ortiz, Venkatesh Raman, and Alfredo Viola, editors, Space-Efficient Data Structures, Streams, and Algorithms - Papers in Honor of J. Ian Munro on the Occasion of His 66th Birthday, volume 8066 of Lecture Notes in Computer Science, pages 267–302. Springer, 2013. doi:10.1007/978-3-642-40273-9_18.
  • [20] Heng Li and Richard Durbin. Fast and accurate short read alignment with burrows-wheeler transform. Bioinformatics, 25(14):1754–1760, 2009. doi:10.1093/BIOINFORMATICS/BTP324.
  • [21] Udi Manber and Gene Myers. Suffix arrays: A new method for on-line string searches. SIAM Journal on Computing, 22(5):935–948, 1993. doi:10.1137/0222058.
  • [22] Edward M. McCreight. A space-economical suffix tree construction algorithm. Journal of the ACM, 23(2):262–272, 1976. doi:10.1145/321941.321946.
  • [23] J. Ian Munro and Venkatesh Raman. Succinct representation of balanced parentheses and static trees. SIAM J. Comput., 31(3):762–776, 2001. doi:10.1137/S0097539799364092.
  • [24] Gonzalo Navarro. Wavelet trees for all. J. Discrete Algorithms, 25:2–20, 2014. doi:10.1016/J.JDA.2013.07.004.
  • [25] Gonzalo Navarro. Contextual pattern matching. In International Symposium on String Processing and Information Retrieval, pages 3–10. Springer, 2020. doi:10.1007/978-3-030-59212-7_1.
  • [26] Gonzalo Navarro. Indexing highly repetitive string collections, part I: repetitiveness measures. ACM Comput. Surv., 54(2):29:1–29:31, 2022. doi:10.1145/3434399.
  • [27] Gonzalo Navarro. Indexing highly repetitive string collections, part II: compressed indexes. ACM Comput. Surv., 54(2):26:1–26:32, 2022. doi:10.1145/3432999.
  • [28] Mihai Pătraşcu. Succincter. In 49th Annual IEEE Symposium on Foundations of Computer Science, FOCS 2008, October 25-28, 2008, Philadelphia, PA, USA, pages 305–313. IEEE Computer Society, 2008. doi:10.1109/FOCS.2008.83.
  • [29] Rajeev Raman, Venkatesh Raman, and Srinivasa Rao Satti. Succinct indexable dictionaries with applications to encoding k-ary trees, prefix sums and multisets. ACM Trans. Algorithms, 3(4):43, 2007. doi:10.1145/1290672.1290680.
  • [30] Luís MS Russo, Gonzalo Navarro, and Arlindo L Oliveira. Fully-compressed suffix trees. In LATIN 2008: Theoretical Informatics: 8th Latin American Symposium, Búzios, Brazil, April 7-11, 2008. Proceedings 8, pages 362–373. Springer, 2008. doi:10.1007/978-3-540-78773-0_32.
  • [31] Kunihiko Sadakane. Compressed suffix trees with full functionality. Theory Comput. Syst., 41(4):589–607, 2007. doi:10.1007/S00224-006-1198-X.
  • [32] Dirk Strothmann. The affix array data structure and its applications to RNA secondary structure analysis. Theor. Comput. Sci., 389(1-2):278–294, 2007. doi:10.1016/J.TCS.2007.09.029.
  • [33] Esko Ukkonen. On-line construction of suffix trees. Algorithmica, 14(3):249–260, 1995. doi:10.1007/BF01206331.
  • [34] Peter Weiner. Linear pattern matching algorithms. 14th Annual Symposium on Switching and Automata Theory, pages 1–11, 1973. doi:10.1109/SWAT.1973.13.