<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.0 20120330//EN" "JATS-archivearticle1.dtd">
<article xmlns:xlink="http://www.w3.org/1999/xlink">
  <front>
    <journal-meta />
    <article-meta>
      <title-group>
        <article-title>Engineering a Lightweight External Memory Sux Array Construction Algorithm⇤</article-title>
      </title-group>
      <contrib-group>
        <contrib contrib-type="author">
          <string-name>Juha K¨arkka¨inen</string-name>
          <email>Juha.Karkkainen@cs.helsinki.fi</email>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <contrib contrib-type="author">
          <string-name>Dominik Kempa</string-name>
          <email>Dominik.Kempa@cs.helsinki.fi</email>
          <xref ref-type="aff" rid="aff0">0</xref>
        </contrib>
        <aff id="aff0">
          <label>0</label>
          <institution>Department of Computer Science, University of Helsinki</institution>
          ,
          <country country="FI">Finland</country>
        </aff>
        <aff id="aff1">
          <label>1</label>
          <institution>Dominik.Kempa</institution>
        </aff>
        <aff id="aff2">
          <label>2</label>
          <institution>Juha.Karkkainen</institution>
        </aff>
      </contrib-group>
      <fpage>53</fpage>
      <lpage>60</lpage>
      <abstract>
        <p>We describe an external memory sux array construction algorithm based on constructing sux arrays for blocks of text and merging them into the full sux array. The basic idea goes back over 20 years and there has been a couple of later improvements, but we describe several further improvements that make the algorithm much faster. In particular, we reduce the I/O volume of the algorithm by a factor O(log n). Our experiments show that the algorithm is the fastest sux array construction algorithm when the size of the text is within a factor of about five from the size of the RAM in either direction, which is a common situation in practice.</p>
      </abstract>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>-</title>
      <p>
        The sux array [
        <xref ref-type="bibr" rid="ref12 ref9">12, 9</xref>
        ], a lexicographically sorted array of the suxes of a text,
is the most important data structure in modern string processing. It is the basis
of powerful text indexes such as enhanced sux arrays [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ] and many compressed
full-text indexes [
        <xref ref-type="bibr" rid="ref14">14</xref>
        ]. Modern text books spend dozens of pages in describing
applications of sux arrays, see e.g. [
        <xref ref-type="bibr" rid="ref16">16</xref>
        ]. In many of the applications, the construction
of the sux array is the main bottleneck in space and time, even though a great
e↵ort has gone into developing better algorithms [
        <xref ref-type="bibr" rid="ref17">17</xref>
        ].
      </p>
      <p>
        For internal memory, there exists an essentially optimal sux array construction
algorithm (SACA) that runs in linear time using little extra space in addition to
what is needed for the input text and the output sux array [
        <xref ref-type="bibr" rid="ref15">15</xref>
        ]. However, little
extra space is not good enough for large text collections such as web crawls, Wikipedia
Copyright c by the paper’s authors. Copying permitted only for private and academic purposes.
⇤ Supported by the Academy of Finland grant 118653 (ALGODAN).
or genomic databases, which may be too big for holding even the text alone in RAM.
There are also external memory SACAs that are theoretically optimal with
inter⇣ ⌘ ⇣ ⌘
nal work O n logM/B(n/B) and I/O complexity O (n/B) logM/B(n/B) [
        <xref ref-type="bibr" rid="ref11 ref4">11, 4</xref>
        ],
where M is the size of the RAM and B is the disk block size. Furthermore, they are
practical and have implementations [
        <xref ref-type="bibr" rid="ref4 ref7">7, 4</xref>
        ] that are fully scalable in the sense that
they are not seriously limited by the size of the RAM. However, constant factors
in practical running time and disk space usage are significant. The currently best
implementation, eSAIS [
        <xref ref-type="bibr" rid="ref4">4</xref>
        ], needs 28n bytes of disk space, which is probably the
main factor limiting its practical scalability.
      </p>
      <p>In this paper, we focus on an algorithm, which we call SAscan, that lies between
internal memory SACAs and eSAIS in scalability. SAscan is a true external memory
algorithm in the sense that it can handle texts that do not fit in internal memory,
but its time complexity ⌦( n2/M ) makes it hopelessly slow when the text is much
larger than the RAM. However, when the text is too large for an internal memory
SACA, i.e., larger than about one fifth of the RAM size, but not too much bigger
than the RAM, SAscan is probably the fastest SACA in practice. SAscan is also
lightweight in the sense that it uses less than half of the disk space of eSAIS, and
can be implemented to use little more than what is needed for the text and the
sux array.</p>
      <p>
        The basic approach of SAscan was developed already in the early days of sux
arrays by Gonnet, Baeza-Yates and Snider [
        <xref ref-type="bibr" rid="ref9">9</xref>
        ]. The idea is to partition the text
into blocks that are small enough so that the sux array for each block can be
constructed in RAM. The block sux arrays are then merged into the full sux
array. After constructing the sux array for each block, the algorithm scans the
previously processed part of the text and determines how each sux of the scanned
text compares to the suxes of the current block. The information collected during
the scan is then used for performing the merging.
      </p>
      <p>
        The early version of SAscan depended heavily on the text not having long repeats
and thus had a poor worst case time complexity. This problem was solved by
Crauser and Ferragina [
        <xref ref-type="bibr" rid="ref6">6</xref>
        ], who developed an improved version with worst case time
complexity O (n2/M ) log M and I/O complexity of O n2/(M B) . The algorithm
was further improved by Ferragina, Gagie and Manzini [
        <xref ref-type="bibr" rid="ref8">8</xref>
        ], who reduced the time
complexity to O (n2/M ) log , where is the size of the text alphabet, and the
disk space usage to little more than what is needed for the input and the output.
      </p>
      <p>
        In this paper, we describe several further improvements to the SAscan algorithm.
The first improvement is a new merging technique that reduces the I/O complexity
of SAscan to O n2/(M B log n) + n/B and provides a substantial speedup in
practice too. Another target of improvement is the rank data structure that plays
a key role in the algorithm. In theory, we observe that the time complexity can
be reduced to O (n2/M ) log(2 + (log / log log n)) by plugging in the rank data
structure of Belazzougui and Navarro [
        <xref ref-type="bibr" rid="ref3">3</xref>
        ]. In practice, we improve the rank data
structure used in the implementation by Ferragina, Gagie and Manzini by applying
alphabet partitioning [
        <xref ref-type="bibr" rid="ref2">2</xref>
        ] and fixed block boosting [
        <xref ref-type="bibr" rid="ref10">10</xref>
        ]. Finally, we reduce the size
of the internal memory data structures by more than one third, which allows the
algorithm to use bigger and fewer blocks improving the running time significantly.
      </p>
      <p>We show experimentally that our practical improvements reduce the running
time of SAscan by more than a factor of three. We also show that the algorithm
is faster than eSAIS when the text size is less than about six times the available
RAM, at which point the disk space usage of eSAIS is already well over 150 times
the available RAM.
2</p>
    </sec>
    <sec id="sec-2">
      <title>Preliminaries</title>
      <p>Let X = X[0..m) be a string over an integer alphabet [0.. ). For i = 0, . . . , m 1
we write X[i..m) to denote the sux of X of length m i, that is X[i..m) =
X[i]X[i + 1] . . . X[m 1]. Similarly, we write X[i..j) to denote the substring X[i]X[i +
1] . . . X[j 1] of length j i. If i = j, the substring X[i..j) is the empty string, also
denoted by ".</p>
      <p>
        The sux array SAX of X contains the starting positions of the non-empty
suxes of X in the lexicographical order, i.e., it is an array SAX[0..m) which contains
a permutation of the integers [0..m) such that X[SAX[0]..m) &lt; X[SAX[
        <xref ref-type="bibr" rid="ref1">1</xref>
        ]..m) &lt; · · · &lt;
X[SAX[m 1]..m).
      </p>
      <p>
        The partial sux array SAX:Y is the lexicographical ordering of the suxes of
XY with a starting position in X, i.e., it is an array SAX:Y[0..m) that contains a
permutation of the integers [0..m) such that X[SAX:Y[0]..m)Y &lt; X[SAX:Y[
        <xref ref-type="bibr" rid="ref1">1</xref>
        ]..m)Y &lt;
· · · &lt; X[SAX:Y[m 1]..m)Y. Note that SAX:" = SAX and that SAX:Y is usually similar
but not identical to SAX. Also, SAX:Y can be obtained from SAXY by removing all
entries that are larger or equal to m.
3
      </p>
    </sec>
    <sec id="sec-3">
      <title>Overview of the Algorithm</title>
      <p>Let a string T[0..n) be the text. It is divided into blocks of size (at most) m, where
m is chosen so that all the in-memory data structures of O(m log n) bits fit in the
RAM. The blocks are processed starting from the end of the text. Assume that
so far we have processed Y = T[i..n) and constructed the sux array SAY. Next
we will construct the partial sux array SAX:Y for the block X = T[i m..i) and
merge it with SAY to form SAXY.</p>
      <p>The suxes in SAX:Y and SAY are in the same relative order as in SAXY and
we just need to know how to merge them. For this purpose, we compute the
gap array gapX:Y[0..m], where gapX:Y[i] is the number of suxes of Y that are
lexicographically between the suxes SAX:Y[i 1] and SAX:Y[i] of XY. Formally,
for i 2 [1..m),
gapX:Y[0] = |{j 2 [0..|Y|) : Y[j..|Y|) &lt; X[SAX:Y[0]..m)Y}|
gapX:Y[i] = |{j 2 [0..|Y|) : X[SAX:Y[i</p>
      <p>1]..m)Y &lt; Y[j..|Y|) &lt; X[SAX:Y[i]..m)Y}|
gapX:Y[m] = |{j 2 [0..|Y|) : X[SAX:Y[m
1]..m)Y &lt; Y[j..|Y|)}| .</p>
      <p>The construction of gapX:Y scans Y and is the computational bottleneck of the
algorithm.</p>
      <p>The merging of SAX:Y and SAY is trivial with the help of gapX:Y but involves a
lot of I/O for reading SAY and writing SAXY. The total I/O volume is O n2/m
in units of O(log n)-bit words. However, we can reduce the I/O by delaying the
merging. We write SAX:Y and gapX:Y to disk and then proceed to process the
next block. Once all partial sux arrays and gap arrays have been computed, we
perform one multiway merging of the partial sux arrays with the help of the gap
arrays. The I/O volume for merging is reduced to O(n) words.</p>
      <p>Suppose that during the construction of SAX:Y or gapX:Y we need to compare
two suxes of SAXY, at least one of which begins in X. In the worst case, the
suxes could have a very long common prefix, much longer than m, making it
impossible to perform the comparison without a lot of I/O — unless we have extra
information about the order of the suxes. In our case, that extra information is
provided by a bitvector gtY, which tells whether each sux of Y is lexicographically
smaller or larger than Y itself. Formally, for all i 2 [0..|Y|),
gtY[i] =</p>
      <p>The output bitvector gtXY is needed as input for the next block. The two other
arrays SAX:Y and gapX:Y are stored on disk until all blocks have been processed.
The final phase of the algorithm takes all the partial sux arrays and gap arrays
as input and produces the full sux array SAT.
4</p>
      <p>
        Details and Analysis
The first stage in processing a block X is constructing the partial sux array
SAX:Y. In the full paper, we show how to construct a string Z such that SAZ =
SAX:Y. We can then construct the sux array using any standard SACA; In the
implementation we use Yuta Mori’s divsufsort [
        <xref ref-type="bibr" rid="ref13">13</xref>
        ].
      </p>
      <p>
        The partial Burrows–Wheeler transform [
        <xref ref-type="bibr" rid="ref5">5</xref>
        ] of X is an array BWTX:Y[0..m)
defined by:
      </p>
      <p>
        BWTX:Y[i] =
⇢ X[SAX:Y[i]
$
if SAX:Y[i] &gt; 0
if SAX:Y[i] = 0
where $ is a special symbol that does not appear in the text. For a character
c and an integer i 2 [0..m], the answer to the rank query rankBWTX:Y (c, i) is the
number of occurrences of c in BWTX:Y[0..i). Rank queries can be answered in
O(log(2 + (log / log log n))) time using a linear space data structure [
        <xref ref-type="bibr" rid="ref3">3</xref>
        ]. In
practice, we use a simpler data structure, described in the full paper, that requires
4.125m bytes of space.
      </p>
      <p>For a string S, let sufrankX:Y(S) be the number of suxes of XY starting in X
that are lexicographically smaller than S. Let C[0.. ) be an array, where C[c] is the
number of positions i 2 [0..m) such that X[i] &lt; c. In the full paper, we prove the
following lemma.
Lemma 4.1 Let k = sufrankX:Y(S) for a string S. For any symbol c,
sufrankX:Y(cS) = C[c] + rankBWTX:Y (c, k) +</p>
      <p>Note that when S = Y[j..|Y|), we can replace the comparison Y &lt; S with gtY[j] =
1. Thus, given sufrankX:Y(Y[j..|Y|)), we can easily compute sufrankX:Y(Y[j 1..|Y|))
using the lemma, and we only need to access Y[j 1] in Y and gtY[j] in gtY. Hence,
we can compute sufrankX:Y(Y[j..|Y|)) for j = |Y| 1, . . . , 0 with a single sequential
pass over Y and gtY. This is all that is needed to compute gapX:Y and gtXY, which
are the output of the second stage of processing X.</p>
      <p>The final phase of the algorithm is merging the partial sux arrays into
the full sux array SAT. For k 2 [0..dn/me), let Xk = T[km..(k + 1)m),
Yk = T[(k + 1)m..n), SAk = SAXk:Yk and gapk = gapXk:Yk . The algorithm shown
below moves suxes from the input sux arrays to the output sux array in
ascending lexicographical order.
1: for k = 0 to dn/me
2: for i = 0 to n 1 do
3: k 0
4: while gapk[ik] &gt; 0 do
5: gapk[ik] gapk[ik]
6: k k + 1
7: SAT[i] SAk[ik] + km
8: ik ik + 1
1 do ik
1</p>
      <p>0
The correctness of the algorithm is based on the following invariants maintained by
the algorithm: (1) ik is the number of suxes already moved from SAk to SAT, and
(2) gapk[ik] is the number of suxes remaining in SAk+1, SAk+2, . . . , SAdn/me 1
that are smaller than SAk[ik].</p>
      <p>
        Theorem 4.2 SAscan can be implemented to construct the sux array of a
text of length n over an alphabet of size in O⇣ nM2 log ⇣2 + lolgolgog n ⌘⌘ time and
O MB log n + Bn log MB Bn ⌘ I/Os in the standard external memory model (see [
        <xref ref-type="bibr" rid="ref18">18</xref>
        ])
⇣ n2 log
with RAM size M and disk block size B, both measured in units of ⇥(log n)-bit
words. Under the reasonable assumption that M B log n, the I/O complexity is
O⇣ Bn ⇣1 + Mn lloogg n ⌘⌘.
      </p>
      <p>In the full paper, we describe an implementation that needs 5.2m bytes of RAM
and at most 11.5n bytes of disk space, and could be implemented to use just 6.5n
bytes of disk space.
5</p>
      <p>Experimental Results
We performed experiments on a machine with a 3.16GHz Intel Core 2 Duo CPU
with 6144KiB L2 cache running Linux (Ubuntu 12.04, 64bit, kernel 3.2). All
4 6
Input size GiB
●
●
●
8
eSAIS
bwtdisk
SAscan
●
●
10
8
6
4
2
0
●
●
2
●
●
●</p>
      <p>●
4 6
Input size GiB
●
●
eSAIS
bwtdisk
SAscan
● ●
8
enwik
hg
programs were compiled using g++ version 4.6.4 with -O3 -DNDEBUG options. To
reduce the time to run the experiments, we artificially restricted the RAM size to
2GiB using the Linux boot option mem, and the algorithms were allowed to use at
most 1.5GiB. We used two big test files: a concatenation of three di↵erent Human
genomes1,2,3 (hg) and a prefix of the English Wikipedia dump4 (enwik).</p>
      <p>The first experiment measures the scalability of our new algorithm. We
computed the sux array for varying length prefixes of each testfile using our algorithm
and compared to eSAIS – currently the fastest algorithm for building SA in external
memory. In addition, we also show the runtimes of bwtdisk5, which is essentially
the Ferragina–Gagie–Manzini version of SAscan though it constructs the BWT
instead of the sux array. The sux array version of bwtdisk would be slower as it
needs more I/O during merging. The results are given in Figure 1. SAscan is faster
than eSAIS up to input sizes of about 9GiB, which is about six times the size of the
RAM available to the algorithms. It is this ratio between the input size and the
RAM size that primarily determines the relative speeds of SAscan and eSAIS. Note
that the main limitation to the scalability of eSAIS is the disk space requirement,
which is about 170 times the available RAM at the crossing point. The runtime of
bwtdisk is always at least 3.5 times the runtime of SAscan, showing the dramatic
e↵ect of our improvements. In the second experiment, we take a closer look at
the e↵ect of our improvements on the runtime. More precisely, we show a detailed
runtime breakdown after turning on individual improvements one by one: the fast
merging of partial sux arrays, the space-ecient representation of the gap array
(which reduces the RAM usage from 8m to 5.2m bytes), and the optimized rank
data structure. The results are presented in Figure 2. Each of the improvements
produces a significant speedup. The combined e↵ect is more than a factor of three.
1http://hgdownload.soe.ucsc.edu/goldenPath/hg19/chromosomes/
2ftp://public.genomics.org.cn/BGI/yanhuang/fa/
3ftp.ncbi.nlm.nih.gov/genbank/genomes/Eukaryotes/vertebrates_mammals/Homo_
sapiens/
4http://dumps.wikimedia.org/enwiki/
5http://people.unipmn.it/manzini/bwtdisk/
enwik (4GiB)
hg (4GiB)
  4</p>
      <p>B
s i
 M3
e
iTm 2
6
5
1
0
merge
gap
other
6
5
4
3
2
1
0
merge
gap
other
e
n
i
l
e
s
a
b
e
g
r
e
m
t
s
a
f</p>
    </sec>
  </body>
  <back>
    <ref-list>
      <ref id="ref1">
        <mixed-citation>
          [1]
          <string-name>
            <given-names>M. I.</given-names>
            <surname>Abouelhoda</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S.</given-names>
            <surname>Kurtz</surname>
          </string-name>
          , and
          <string-name>
            <given-names>E.</given-names>
            <surname>Ohlebusch</surname>
          </string-name>
          .
          <article-title>Replacing sux trees with enhanced sux arrays</article-title>
          .
          <source>J. Discrete Algorithms</source>
          ,
          <volume>2</volume>
          (
          <issue>1</issue>
          ):
          <fpage>53</fpage>
          -
          <lpage>86</lpage>
          ,
          <year>2004</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref2">
        <mixed-citation>
          [2]
          <string-name>
            <given-names>J.</given-names>
            <surname>Barbay</surname>
          </string-name>
          ,
          <string-name>
            <given-names>T.</given-names>
            <surname>Gagie</surname>
          </string-name>
          , G. Navarro, and
          <string-name>
            <given-names>Y.</given-names>
            <surname>Nekrich</surname>
          </string-name>
          .
          <article-title>Alphabet partitioning for compressed rank/select and applications</article-title>
          .
          <source>In Proc. ISAAC</source>
          , pages
          <fpage>315</fpage>
          -
          <lpage>326</lpage>
          ,
          <year>2010</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref3">
        <mixed-citation>
          [3]
          <string-name>
            <given-names>D.</given-names>
            <surname>Belazzougui</surname>
          </string-name>
          and
          <string-name>
            <given-names>G.</given-names>
            <surname>Navarro</surname>
          </string-name>
          .
          <article-title>New lower and upper bounds for representing sequences</article-title>
          .
          <source>In Proc. ESA</source>
          , pages
          <fpage>181</fpage>
          -
          <lpage>192</lpage>
          ,
          <year>2012</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref4">
        <mixed-citation>
          [4]
          <string-name>
            <given-names>T.</given-names>
            <surname>Bingmann</surname>
          </string-name>
          ,
          <string-name>
            <given-names>J.</given-names>
            <surname>Fischer</surname>
          </string-name>
          , and
          <string-name>
            <given-names>V.</given-names>
            <surname>Osipov</surname>
          </string-name>
          .
          <article-title>Inducing sux and LCP arrays in external memory</article-title>
          .
          <source>In Proc. ALENEX</source>
          , pages
          <fpage>103</fpage>
          -
          <lpage>112</lpage>
          ,
          <year>2013</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref5">
        <mixed-citation>
          [5]
          <string-name>
            <given-names>M.</given-names>
            <surname>Burrows</surname>
          </string-name>
          and
          <string-name>
            <given-names>D.</given-names>
            <surname>Wheeler</surname>
          </string-name>
          .
          <article-title>A block sorting lossless data compression algorithm</article-title>
          .
          <source>Technical Report 124</source>
          , Digital Equipment Corporation, Palo Alto, California,
          <year>1994</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref6">
        <mixed-citation>
          [6]
          <string-name>
            <given-names>A.</given-names>
            <surname>Crauser</surname>
          </string-name>
          and
          <string-name>
            <given-names>P.</given-names>
            <surname>Ferragina</surname>
          </string-name>
          .
          <article-title>A theoretical and experimental study on the construction of sux arrays in external memory</article-title>
          .
          <source>Algorithmica</source>
          ,
          <volume>32</volume>
          (
          <issue>1</issue>
          ):
          <fpage>1</fpage>
          -
          <lpage>35</lpage>
          ,
          <year>2002</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref7">
        <mixed-citation>
          [7]
          <string-name>
            <given-names>R.</given-names>
            <surname>Dementiev</surname>
          </string-name>
          , J. K¨arkk¨ainen, J. Mehnert, and
          <string-name>
            <given-names>P.</given-names>
            <surname>Sanders</surname>
          </string-name>
          .
          <article-title>Better external memory sux array construction</article-title>
          .
          <source>ACM J. Experimental Algorithmics, 12:Article 3.4</source>
          ,
          <year>2008</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref8">
        <mixed-citation>
          [8]
          <string-name>
            <given-names>P.</given-names>
            <surname>Ferragina</surname>
          </string-name>
          ,
          <string-name>
            <given-names>T.</given-names>
            <surname>Gagie</surname>
          </string-name>
          , and
          <string-name>
            <given-names>G.</given-names>
            <surname>Manzini</surname>
          </string-name>
          .
          <article-title>Lightweight data indexing and compression in external memory</article-title>
          .
          <source>Algorithmica</source>
          ,
          <volume>63</volume>
          (
          <issue>3</issue>
          ):
          <fpage>707</fpage>
          -
          <lpage>730</lpage>
          ,
          <year>2012</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref9">
        <mixed-citation>
          [9]
          <string-name>
            <given-names>G. H.</given-names>
            <surname>Gonnet</surname>
          </string-name>
          ,
          <string-name>
            <given-names>R. A.</given-names>
            <surname>Baeza-Yates</surname>
          </string-name>
          , and
          <string-name>
            <given-names>T.</given-names>
            <surname>Snider</surname>
          </string-name>
          .
          <article-title>New indices for text: Pat trees and Pat arrays</article-title>
          .
          <source>In Information Retrieval: Data Structures &amp; Algorithms</source>
          , pages
          <fpage>66</fpage>
          -
          <lpage>82</lpage>
          . Prentice-Hall,
          <year>1992</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref10">
        <mixed-citation>
          [10]
          <string-name>
            <surname>J. K</surname>
          </string-name>
          <article-title>¨arkk¨ainen and</article-title>
          <string-name>
            <given-names>S. J.</given-names>
            <surname>Puglisi</surname>
          </string-name>
          .
          <article-title>Fixed-block compression boosting in FMindexes</article-title>
          .
          <source>In Proc. SPIRE</source>
          , pages
          <fpage>174</fpage>
          -
          <lpage>184</lpage>
          ,
          <year>2011</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref11">
        <mixed-citation>
          [11]
          <string-name>
            <surname>J. K</surname>
          </string-name>
          <article-title>¨arkk</article-title>
          ¨ainen, P. Sanders, and
          <string-name>
            <given-names>S.</given-names>
            <surname>Burkhardt</surname>
          </string-name>
          .
          <article-title>Linear work sux array construction</article-title>
          .
          <source>J. ACM</source>
          ,
          <volume>53</volume>
          (
          <issue>6</issue>
          ):
          <fpage>918</fpage>
          -
          <lpage>936</lpage>
          ,
          <year>2006</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref12">
        <mixed-citation>
          [12]
          <string-name>
            <given-names>U.</given-names>
            <surname>Manber</surname>
          </string-name>
          and
          <string-name>
            <given-names>G. W.</given-names>
            <surname>Myers</surname>
          </string-name>
          .
          <article-title>Sux arrays: a new method for on-line string searches</article-title>
          .
          <source>SIAM J. Computing</source>
          ,
          <volume>22</volume>
          (
          <issue>5</issue>
          ):
          <fpage>935</fpage>
          -
          <lpage>948</lpage>
          ,
          <year>1993</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref13">
        <mixed-citation>
          [13]
          <string-name>
            <given-names>Y.</given-names>
            <surname>Mori</surname>
          </string-name>
          <article-title>. libdivsufsort, a C library for sux array construction</article-title>
          . http://code. google.com/p/libdivsufsort/.
        </mixed-citation>
      </ref>
      <ref id="ref14">
        <mixed-citation>
          [14]
          <string-name>
            <given-names>G.</given-names>
            <surname>Navarro</surname>
          </string-name>
          and
          <string-name>
            <surname>V.</surname>
          </string-name>
          <article-title>M¨akinen. Compressed full-text indexes</article-title>
          .
          <source>ACM Computing Surveys</source>
          ,
          <volume>39</volume>
          (
          <issue>1</issue>
          ):Article 2,
          <year>2007</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref15">
        <mixed-citation>
          [15]
          <string-name>
            <given-names>G.</given-names>
            <surname>Nong. Practical</surname>
          </string-name>
          linear
          <article-title>-time O(1)-workspace sux sorting for constant alphabets</article-title>
          .
          <source>ACM Trans. Inf</source>
          . Syst.,
          <volume>31</volume>
          (
          <issue>3</issue>
          ):Article 15,
          <year>2013</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref16">
        <mixed-citation>
          [16]
          <string-name>
            <given-names>E.</given-names>
            <surname>Ohlebusch</surname>
          </string-name>
          . Bioinformatics Algorithms: Sequence Analysis,
          <string-name>
            <given-names>Genome</given-names>
            <surname>Rearrangements</surname>
          </string-name>
          , and
          <string-name>
            <given-names>Phylogenetic</given-names>
            <surname>Reconstruction</surname>
          </string-name>
          . Oldenbusch Verlag,
          <year>2013</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref17">
        <mixed-citation>
          [17]
          <string-name>
            <given-names>S. J.</given-names>
            <surname>Puglisi</surname>
          </string-name>
          ,
          <string-name>
            <given-names>W. F.</given-names>
            <surname>Smyth</surname>
          </string-name>
          ,
          <article-title>and</article-title>
          <string-name>
            <given-names>A.</given-names>
            <surname>Turpin</surname>
          </string-name>
          .
          <article-title>A taxonomy of sux array construction algorithms</article-title>
          .
          <source>ACM Computing Surveys</source>
          ,
          <volume>39</volume>
          (
          <issue>2</issue>
          ):Article 4,
          <year>2007</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref18">
        <mixed-citation>
          [18]
          <string-name>
            <given-names>J. S.</given-names>
            <surname>Vitter</surname>
          </string-name>
          .
          <article-title>Algorithms and data structures for external memory</article-title>
          .
          <source>Foundations and Trends in Theoretical Computer Science</source>
          ,
          <volume>2</volume>
          (
          <issue>4</issue>
          ):
          <fpage>305</fpage>
          -
          <lpage>474</lpage>
          ,
          <year>2006</year>
          .
        </mixed-citation>
      </ref>
    </ref-list>
  </back>
</article>