Efficient tree-structured categorical retrieval

We study a document retrieval problem in the new framework where $D$ text documents are organized in a {\em category tree} with a pre-defined number $h$ of categories. This situation occurs e.g. with taxomonic trees in biology or subject classification systems for scientific literature. Given a string pattern $p$ and a category (level in the category tree), we wish to efficiently retrieve the $t$ \emph{categorical units} containing this pattern and belonging to the category. We propose several efficient solutions for this problem. One of them uses $n(\log\sigma(1+o(1))+\log D+O(h)) + O(\Delta)$ bits of space and $O(|p|+t)$ query time, where $n$ is the total length of the documents, $\sigma$ the size of the alphabet used in the documents and $\Delta$ is the total number of nodes in the category tree. Another solution uses $n(\log\sigma(1+o(1))+O(\log D))+O(\Delta)+O(D\log n)$ bits of space and $O(|p|+t\log D)$ query time. We finally propose other solutions which are more space-efficient at the expense of a slight increase in query time.

Index terms-pattern matching, document retrieval, category tree, spaceefficient data structures

Introduction
Data is often structured using category hierarchies represented by trees.In many applications, such hierarchies play a crucial guiding role: for example, the International Classification of Diseases (ICD) provides a hierarchical classification of all human disesases and constitues a common reference for diagnostics.In this paper, we are interested in sequence data, such as biological sequences or text documents, that are linked to a given hierarchy.More precisely, in our framework sequences are associated to leaves of a hierarchy, and tree nodes are mapped to several fixed levels, also called ranks.
This situation is common and occurs in several important applications.One is biology where species are classified according to the famous Linnaean taxonomy including eight common taxonomic ranks: species, genus, family, order, class, phylum, kingdom, domain.Then, given a set of sequences (DNA, RNA or protein) belonging to known species, one can associate them to the corresponding leaves of the taxonomic tree.Such a structure is used, for example, for phylogeny-based metagenomic classification where one considers the tree of known genomic sequences as a reference for classifying sequences of a metagenomic sample, see e.g.[23].A classification procedure may involve queries asking for the taxonomic units (i.e.internal nodes of the tree) of a certain rank whose sequences contain a given pattern, or similar type of queries.
Another example is provided by text documents such as scientific papers.The latter are usually annotated by subjects belonging to a fixed hierarchical nomenclature, such as ACM Computing Classification System (CCS) or Mathematics Subject Classification (MSC).Those subject hierarchies have a predefined number of levels: four levels for CCS and three for MSC.Given a corpus of scientific papers, one could ask about subject categories at a certain level whose documents contain a given pattern.This is a natural information retrieval scenario.
Here we study this problem from the stringology perspective (see e.g.[14,8]).Assume we are given a set of D documents of total length n over an alphabet of size σ, organized in a tree of height h.The tree has D leaves, each associated with a distinct document, and the leaves are all at level h of the tree.The total number of nodes in the tree is denoted by ∆.The tree specifies a hierarchy of categories: each level of the tree corresponds to a category, and each internal node corresponds to a categorical unit.
The basic type of query we study in this paper is the following.
Given a pattern p, and a tree level (rank) i ∈ [1..h], return all nodes (categorical units) d 1 , • • • , d t at level i that have at least one leaf (document) in their subtree that contains pattern p.
For example, given a large collection of genomic sequences organized in a taxonomic tree (for example, all known animal genomes), one may ask which animal families have a given sequence in the genomes of their members.Or, given a large hierarchy of documents (for example, all Computer Science papers), one may wonder in which subfields of Computer Science (corresponding to a certain level of the hierarchy) the term 'suffix tree' is used.This basic type of queries can be further extended in different ways.For example, one may impose an additional requirement of the mimimum number of documents of the categorical unit containing the given pattern.In this first study, we focus on the basic query type.
In this work, we propose several algorithms for this problem.Our first solution (Section 3) is based on the approach of Muthukrishnan [16] to the document retrieval problem.By combining several algorithmic tools -efficient text index, colored range reporting queries, and level ancestor queries -we obtain a solution with n(log σ(1 bits of space and O(|p| + t) query time, where t is the output size, i.e. the number of retrieved categorical units.To improve the space bound, in particular to get rid of the O(nh) term which can be as big as O(nD), we then develop a solution based on a wavelet tree built on top of the input category tree (Section 4).On this way, we first obtain a solution taking n(log σ + log D) + O(D log n) bits and O(|p| + t • h log D) query time.We further improve it using the technique of heavy path decomposition, to obtain a solution in n(log σ(1 + o(1)) + log D) + O(∆) bits of space and O(|p| + t log D) query time.In the final part of the paper (Section 5), we focus on solutions using succinct and compressed data structures, on top of the input data.That is, our main goal here is to replace the n log D bits by respectively n log σ or by nH 0 + o(n log σ) in representing the document array.We obtain memory-time trade-offs showing how this goal can be achieved at the price of a slight increase of query time.
We summarize our main results in the following 2 Preliminaries We first briefly present main algorithmic tools used by our algorithms.

Level ancestor queries on trees
Consider a rooted tree.To each node in the tree we associate its level so that the level of the root is 1, and the level of a child node is 1 more than the level of its parent.The height of a tree is defined as the maximal level of any node in the tree.We denote by ℓ α the level of a node α.
We will use the implementation of level ancestor queries specified by the following lemma.

Lemma 1 ([19]
) There exists a data structure that represents a tree with n nodes within space 2n + o(n) and allows answering the following queries in constant time: 1. given a level ℓ and a node α at level at least ℓ, return the ancestor node β of α at level ℓ, 2. given an integer i, return the node α where α is the leaf number i in left-to-right order.
We denote by LAQ(α, i) the query which asks for the ancestor at level i of node α.We denote by leafselect(i) the query which returns the i-th leaf of the tree in left to right order.

rank/select queries and wavelet trees
rank and select queries on sequences constitute basic building blocks of many succinct data structures [13].Given a string S [1..n] on an alphabet Σ, a query rank c (S, i), with c ∈ Σ and i ∈ [1..n], asks for the number of occurrences of c in S[1..i] and select c (S, j) asks for the unique position i such that S[i] = c and rank c (S, i) = j.
Consider first the important case of binary sequences (bitvectors).The following result is well-known, see [18].
.n] can be represented using n+o(n) bits of space, so that queries rank and select are answered in constant time.
In the case of non-binary alphabet, rank/select queries can be efficiently answered using wavelet trees.The wavelet tree has been formally introduced in [9], but a similar structure has been used earlier [3].Suppose we are given a sequence S of length n over an alphabet Σ.
The (binary) wavelet tree is a binary tree representation of S that is defined recursively as follows.Let Σ 0 = ∅ and Σ 1 = ∅ form a partition of Σ (that is, Σ = Σ 0 ∪ Σ 1 and Σ 0 ∩ Σ 1 = ∅).Then the root of the binary wavelet tree will contain a binary vector B, such that Let the sequence S 0 (resp., S 1 ) be formed by keeping only the elements of S that belong to Σ 0 (resp., Σ 1 ), in the same order.Then, the left (resp., right) child is defined recursively using S 0 (resp., S 1 ) and a binary partition of Σ 0 (resp., Σ 1 ).The recursion stops whenever we reach a leaf that corresponds to a singleton subset of Σ.Such nodes will form the leaves of the wavelet tree.We refer the reader to the survey [17] for more details about wavelet trees.We will make use of the following lemma: Lemma 3 ([9]) The wavelet tree over the alphabet [1..σ] can be represented using n(log σ + o(1)) + O(σ log n) bits of space, supporting rank and select queries in O(log σ) time.
The definition of binary wavelet tree can be readily generalized to the non-binary case.As in the binary case, to any node α labeled by an interval Σ α is (implicitly) associated the sequence S α which is the subsequence of S[1..n] consisting of all characters belonging to Σ α .If a node α of a wavelet tree has d children, then the alphabet interval Σ α ⊆ [1..σ] assigned to α is partitioned into d disjoint subintervals instead of two, and α stores a sequence

Text indexes
We assume familiarity with main text indexing structures: suffix trees, suffix arrays and BWT-indexes.Here we only recall some basic facts about them.
Given a text T over an alphabet Σ = [1.
.σ], a suffix tree [22] is a tree data structure that stores in its leaves the suffixes of T $, where $ is a special character that does not appear in T and is lexicographically smaller than any character of T .Each suffix is associated with its starting position in T $.Suffix tree allows answering basic string pattern matching queries: given a pattern p, return the set of starting positions of p in T .
The suffix array of T is a related but more space-efficient data structure defined as the array SA[1..n + 1] obtained by sorting all the suffixes of T $ in lexicographic order and setting SA[i] = j if and only if the suffix T [j..n]$ has lexicographic rank i among all suffixes of T $.
A suffix tree occupies O(n log n) bits of space and a matching query needs access to the original text T in addition to the suffix tree.The query time is O(|p| log σ).The suffix array [15] is an alternative to the suffix tree which occupies the same O(n log n) bits of space, but has lower constant factors in space and supports matching queries in O(|p| + log n) time.
The BWT-index (FM-index) is a space-efficient alternative to suffix arrays and suffix trees which uses O(n log σ) bits of space only.It was originally proposed in [4] and has seen many improvements.We will use the following version of BWT-index with alphabet-independent query time.

Lemma 4 ([1])
Given a text T of length n over alphabet [1..σ], we can build a BWT-index which occupies n log σ(1+o(1)) bits of space and supports computing the range of suffixes prefixed by a pattern p in time O(|p|).
Note that computing the range of suffixes answers also whether the pattern occurs in the text at all, and if so, reports the number of its occurrences (the size of the lexicographic order interval).For this reason, the query presented in the lemma above is usually refered to as a count query.The BWT-index is usually augmented with position information so that it becomes able to report the location of each occurrence of the pattern in addition to the number of occurrences.This can be achieved using fo the example the compressed suffix array representation: Lemma 5 ( [10]) Given a text T of length n over alphabet [1..σ] and a constant ǫ > 0, we can build a data structure which occupies O(n log σ) bits of space and that returns SA All the above-mentioned text indexes can trivially be extended to support the same type of queries on a collection of documents instead of a single document.More precisely, given a collection of texts T 1 , T 2 , . . ., T D over the same alphabet Σ, the same queries can be supported by constructing an index of the string T 1 $T $ . . .T D $.

Colored range reporting and document retrieval
Muthukrishnan [16] was the first to study the problem of efficiently retrieving documents containing a given string pattern.Through the use of a text index, he reduced the problem to the one of color range reporting, i.e. reporting all distinct values ("colors") occuring in a given interval of an array.His data structure relies on the use of range minimum query data structures -a data structure that can find in constant time the smallest element in an sub-range of an array.His algorithm was subsequently improved in terms of space (Theorem 4 in [20]).We will use the following result on color range reporting, which can be obtained by using the optimal range-minimum query data structure [5] in the method of [20]: .σ] n , we can build a static data structure that occupies 2n + o(n) bits that allows reporting all d distinct values occurring in a query interval A[i..j] in time O(d) (O(1) time per reported value).The query will make read-only access to the data structure, read-only random access to elements of the array A and read-write access to a bitvector B of size σ.The bitvector needs to be initalized to zero before the first query and is reset to zero at the end of each query.

Solution based on Muthukrishnan's data structure
Our first solution will be a combination of tools presented in the previous section.We first build a text index for the concatenation of documents T 1 $T 2 . . .T D $.More specifically, we build an instance of the text index of Lemma 4 which occupies n log σ(1 + o( 1)) bits and allows to locate the interval of all suffixes of the documents that start with p in time O(|p|).
We also build the document array A[1.
.n], of size n log D, indexed by the document suffixes sorted in lexicographic order and storing the documents each of the suffixes belongs to.We further store h instances C 1 , . . .C h of the data structure of Lemma 6, one instance per level of the tree, defined as follows.Consider d (virtual) arrays A i [1.
.n], one per level i ∈ [1..h] of the tree, such that A i [j] stores the ancestor at level i of document A[j].Then, each C i is the data structure of Lemma 6 for supporting range reporting queries on array A i .Thus, C i allows to return, for any interval [r..ℓ], all distinct elements in A i [r..ℓ] in constant time per element provided that a random-access to each element in A i is supported in constant time.
Note that according to Lemma 6, a query will need to use D bits of working space1 since it will need to use a temporary bitvector B of size D i ≤ D where D i is the number of nodes at level i of the tree2 .By Lemma 6, each C i occupies only 2n + o(n).Finally, in order to simulate constant-time random access to entries of arrays A i , 1 ≤ i ≤ h, we build a data structure for constant-time level ancestor queries on the category tree (Lemma 1).Notice that we can access cell A i [j] using the formula A i [j] = LAQ(leafselect(A[j]), i).The data structure will occupy 2∆+o(∆) bits of space, where ∆ is the total number of nodes in the tree.
To answer a query consisting of a pattern p and level i, we proceed as follows.We first compute, in time O(|p|), the interval [ℓ..r] of suffixes using the BWT-index (Lemma 4).The documents containing p are then those contained in A[ℓ..r].We then have to output all distinct ancestors at level i of documents A[ℓ..r], i.e. all distinct elements of A i [ℓ..r].This is done in constant time per reported element using C i , as follows from Lemma 6 and constant-time access to elements of A i using LAQ and leafselect queries.
The document array occupies n log D bits of space.The text index is built on top of the n log σ(1 + o(1)) bits.Each of the h instances of the data structure of Lemma 6 will occupy 2n + o(n) bits of space each for a total space of 2nh + o(hn) bits of space.The data structure built on top of the category tree occupies 2∆ + o(∆) bits of space.
We thus have proved the following theorem: Theorem 1 Given a collection of D documents of total length n over alphabet [1.
.σ] so that the documents are organized in a hierarchy of documents represented by a tree of total size ∆ and of height h, we can build a data structure of size n(log σ(1 + o(1)) + log D + O(h)) + O(∆) bits of space that, given a pattern p, can find all t categories of documents at a given level i that have at least one document that contains the pattern in total time O(|p| + t).
This data structure will be good enough whenever h is small, for example, when h = log D, which holds for example when each internal node in the tree has at least two children.

Wavelet-tree-based solution
If each node of our tree is branching, i.e. has two or more children, then h = O(log D) and the solution of Secton 3 takes O(n(log σ + log D)) bits of space.(Recall that all leaves of our tree occur at level h) However, this may not be the case as the tree may have many non-branching (unary) nodes.In the extreme case, we may have h = Ω(D) and the space of Theorem 1 will become Ω(nD) which can be too large if D is large.In this section, we deal with this issue and present solutions based on wavelet trees.As in Secton 3, we assume that we first located an interval [ℓ..r] in the document array A that corresponds to the occurrences of the query pattern p.The goal is then to return all internal nodes at level i containing documents from A[ℓ..r] in their subtree.In Section 4.1, we present the first "warm-up" solution that we subsequently improve in Section 4.2.

Basic wavelet-tree-based solution
We build our wavelet tree on top of the input tree representing the hierarchy of the documents.Therefore, our initial wavelet tree is generally non-binary and non-balanced.As does the input tree, our wavelet tree has height h and O(∆) nodes in total.To save space, we will eliminate unary nodes from the wavelet tree (such a node α stores a trivial sequence C α = 1 |Sα| , see Section 2.2) and only encode O(D) branching nodes.For each branching node α we store its depth denoted δ α .Besides the wavelet tree, we will need a data structure for level ancestor queries (Lemma 1) for the input tree that occupies O(∆) bits of space and answers queries in constant time.
Our alphabet Σ will be defined to be the set of documents [1..D].The alphabet interval Σ α assigned to a node α will be the indices of documents occurring in the subtree rooted at α.The string S for which the tree is built will be the document array A[1..n].
Our wavelet tree may have nodes with more than two children and we implement them by local binarization.If a node has d children, we will encode it using a binary wavelet tree of log d levels, called a local wavelet tree.In total, the wavelet tree occupies n(h log D) bits, since the tree contains h levels and each of the n elements of the document array will contribute at most log D bits to each level.
Consider now a query which is defined by a pattern p and a level i in the input tree.Once we computed the document array interval corresponding to p, say A[ℓ..r], we use our wavelet tree to identify the desired nodes at level i. Starting from the root, we traverse the tree top-down through all the nodes α whose assigned sub-alphabet Σ α ⊆ [1..D] intersects with elements of A[ℓ..r].This is done by recomputing the current interval for each traversed node.An invariant of this computation is that querying a node α with an interval [i..j] ensures that all elements of A[ℓ..r] ∩ Σ α are within S α [i..j].Interval computation is done using rank queries on binary vectors B α stored at nodes α of the wavelet tree, we refer to [7] where this computation is described in detail.We stop the traversal at a node α as soon as δ α ≥ i and report its ancestor at level i using the level ancestor data structure.
The original tree has at most h levels and each node is replaced by a local wavelet tree with at most log D levels, therefore a root-to-leaf path in the wavelet tree has at most h log D nodes, and the total worst-case query time will be O(h log D) per reported node.
We now analyse the space usage of the data structure.Since the wavelet tree has D leaves and all nodes are branching, the total number of nodes is O(D).Thus, the total space used by the wavelet trees is n( Lemma 3).The space used by the BWT-index is n log σ(1 + o( 1)) (Lemma 4) and the space used by the document array is n log D bits.The space used by the data structure for level-ancestor queries is O(∆) bits (Lemma 1).We thus proved the following theorem.
Theorem 2 Given a collection of D documents of total length n over alphabet [1..σ] and so that the documents are organized in a hierarchy of docu-ments represented by a tree of height h, we can build a data structure of size n(log σ + (h + 1) log D)(1 + o(1)) + O(D log n) + O(∆) bits of space that can, given a pattern p, find all t categories of documents at level i that have at least one document that contains the pattern in total time O(|p| + t • h log D).

Solutions based on heavy path decomposition
We now describe a more sophisticated solution based on the heavy path decomposition [21,11] of the wavelet tree from the previous section.Here we present a high-level description of our algorithms, full details will be given in the extended version of the paper.
There are several variants of the definition of heavy path decomposition, with slight differences between the variants.In what follows we will use the following variant.With each node α of a given tree T , we associate a weight w(α) equal to the number of leaves in the subtree rooted at α.The heavy child β of α is the child of α with the greatest weight, with ties resolved arbitrarily.The other children of α are called light.The edge between α and its heavy child is called a heavy edge, whereas all the other edges from α to its children are called light edges.
The heavy path decomposition of a tree T is a decomposition of T into paths defined recursively as follows.We first compute the heavy path (i.e. a path consisting of heavy edges) from the root of T to a leaf, and then recursively apply the decomposition to all subtrees rooted at all light children of the heavy path nodes.An interesting property of the heavy path decomposition is that the number of light edges on any root-to-leaf path is at most log D, where D is the number of leaves in the tree.

First solution based on heavy path decomposition
Our first solution will be neither space-nor time-optimal.For each heavy path starting at a node α for which the number of light children of nodes of the path is ℓ α , the alphabet will be of size ℓ α .We can order the nodes (light children) by increasing depths.The sequence S α that is associated with a heavy path α = α 1 , . . .α k , will be of length n α over alphabet [1..ℓ α ], where n α is the total number of occurrences of leaves (documents) in the subtree rooted at α in the document array A. That is, the sequence will be a subsequence of A[1..n], where only the documents that belong to the leaves under α are kept, and the encoding of each element in the subsequence will be the index of the (light) children of the heavy path nodes under which the document appears.Let the depths of the nodes in the heavy path be denoted by d 1 < . . .< d k .We additionally store a bitvector B α marking the node depths of the different nodes.That is, we initialize the bitvector B α by all zeros and then set B α [d i ] = 1 for every i ∈ [1..k].
A query for level i will now proceed as follows.We traverse the tree top-down.For each heavy path, we do the following.
1. We first use the bitvector that marks the node depths to determine a subrange [1..r] of the alphabet that will be used for the query (the light nodes included in the range will have depths at most i, whereas the nodes in the range [r + 1. .h] will have depth more than i).
2. We traverse the wavelet tree of the current heavy path.Such a query will spend time O(t log ℓ α ) for a heavy path with ℓ α light children, in which t distinct light children appear in the sequence.
It is easy to see that the total space will be O(n log 2 D) bits, since the alphabet size is O(log ℓ α ) for each node α with n α stored elements and each element of A will incur at most log D elements in the wavelet trees stored in the heavy paths of the tree.The query time can be bounded to be O(log 2 D) per reported document by a similar argument (we traverse log D heavy paths and each traversal costs log D time).
We thus obtain the following result.
Theorem 3 Given a collection of D documents of total length n over alphabet [1.
.σ] so that the documents are organized in a hierarchy of documents represented by a tree of total size ∆, we can build a data structure of size O(n log 2 D + ∆) bits of space that can, given a pattern p, find all t categories of documents at level i that have at least one document containing the pattern in total time O(|p| + t log 2 D).

Second solution based on heavy path decomposition
Our second solution based on heavy path decomposition will rely on a more fine-grained encoding.We will make use of Huffman-shaped wavelet tree [6] for each heavy path, such that the wavelet tree node corresponding to a light node of relative weight w (the weight light node divided by weight of the root of heavy path) will be encoded using log(1/w) + O(1) bits and the correponding wavelet tree leaf will be at depth log(1/w) + O(1).It is now easy to see that the encoding of each element of A will take O(log D) bits and, furthermore, the cost of a query can be upper-bounded by just O(log D).
Both bounds rely on a telescoping argument.We have the following result.
Theorem 4 Given a collection of D documents of total length n over alphabet [1.
.σ] and so that the documents are organized in a hierarchy of documents represented by a tree of total size ∆, we can build a data structure of size n(log σ(1 + o(1)) + O(log D)) + O(∆) + O(D log n) bits of space that can, given a pattern p, find all t categories of documents at a level i that have at least one document that contains the pattern in total time O(|p| + t log D).

Compact and compressed data structures for categorical data queries
In this section we explore more space-effcient versions of the problem.More in detail, we are interested in studying the problem under succinct and compressed-space constraints.Namely, our aim is to use O(n log σ) bits for the succinct case and nH 0 + o(n log σ) + O(D log n) bits of space for the compressed case.To achieve this, we will improve the solution of Section 3.More precisely, we avoid the storage of the document array and simulate direct access to the document array using Lemma 5.As a consequence, we can achieve time O(log ǫ n) to get the given document index A[i] for any i ∈ [1.
.n].This will reduce the space to represent the document array from O(n log D) to O(n log σ) bits.Now the space used by the range minimum query data structures will become the bottleneck.To reduce the space usage we will make use of sparsification.More precisely, we will divide the document array into blocks and sample just the values of the A array that are the smallest in each block.The space becomes O(n/α) bits where α is the sparsification factor.For details on how the sparsification is used to simulate the reporting of distinct documents that appear in interval A[i..j], we refer the reader to [2,12].Here we just mention that the time per reported document becomes O(α log ǫ n) and entails O(α) accesses to the document array, each of which requires O(log ǫ n) time.We thus have the following result.
Theorem 5 Given a parameter α ≥ 1 and a collection of D documents of total length n over alphabet [1..σ] and so that the documents are organized in a hierarchy of documents represented by a tree of height h, we can build a data structure of size O(n log σ) + O(nh/α) bits of space that can, given a pattern p, find all t categories of documents at level i that have at least one document that contains the pattern in total time O(|p| + t • α log ǫ n).
Corollary 1 Given a parameter α and collection of D documents of total length n over alphabet [1..σ] and so that the documents are organized in a hierarchy of documents represented by a tree of height h, we can build a data structure of size O(n log σ) bits of space that can, given a pattern p, find all t categories of documents at level i that have at least one document that contains the pattern in total time O(|p| + (t + 1) • log ǫ n(1 + h log σ )).
Whenever h = log D (e.g.every internal node is branching), the query time simplifies to O(|p| + (t + 1) • log σ D • log ǫ n) ∈ O(|p| + (t + 1) log 1+ǫ n).We can also get compressed space.Namely, we can use a compressed suffix array [9] with query time log n log log n and space nH k + o(n) to represent the document array.We will combine the compressed suffix array with the alphabet-independent variant of BWT-index presented in [1].We then get an index that uses space nH k + o(n log σ) with query time O(|p|) to find the suffix array interval of a pattern and O(log n log log n) time to access an element of the suffix array.Notice that we can translate access to a suffix array element to an access to a document array element using O(D log n) bits of space.Summing up, we get the following theorem.
Theorem 6 Given a parameter α and a collection of D documents of total length n over alphabet [1..σ] and so that the documents are organized in a hierarchy of documents represented by a tree of height h, we can build a data structure of size nH k + o(n log σ) + O(D log n) + O(nh/α) bits of space that can, given a pattern p, find all t categories of documents at level i that have at least one document that contains the pattern in total time O(|p| + t • α log n log log n).

Conclusions
In this paper, we proposed several solutions for the problem of categorical retrieval.Possible extensions of our work include the case when the document hierarchy is a DAG rather than a tree.This situation occurs, for example, with phylogenetic networks.The solution in Section 3 could easily be extended to DAG structured categories if there was an efficient support for level ancestor queries on DAGs.Other possible extensions includes topk queries in which categories are either ordered by a static order or by the total frequency of the pattern in the documents that belong to the reported categories.
In combination with text indexing, colored range reporting allows supporting document retrieval queries.More precisely, define the document array as follows: given a collection of D documents T 1 , T 2 . . .T D of total length n, lexicographically sort all the suffixes of the text T * = T 1 $T 2 $ . . .T D $, and set A[i] = j iff the suffix of T * of lexicographic rank i starts inside T j (if the suffix starts with $, then set A[i] = 0).Document array A can be easily obtained from a text index of T * = T 1 $T 2 $ . . .T D $.For this, one can construct a bitmap of length |T * | with 1's at positions of $ in T * and 0's otherwise.Then A[i] = rank 1 (A, SA[i]) + 1 for i > D and A[i] = 0 for i ≤ D. It is then immediate that using these data structures, Lemmas 4, 5, and 6 lead to solving the document retrieval problem in time O(|p| + d log ǫ n), where d is the number of resulting documents.For this, we can use the document alphabet-independent BWT index to compute the range [i..j] of occurrences of p in O(|p|) time and then report the d distinct documents that appear in the range A[i..j] in O(d log ǫ n) time.
= h • log log n, we get space nH k + o(n log σ) + O(D log n) bits and query time O(|p| + t • h log n(log log n) 2 ).The latter becomes O(|p| + t log D log n(log log n) 2 ) whenever h = O(log D). table.