Abstract 1 Introduction 2 Preliminaries 3 Warm-ups 4 Main algorithm 5 First analysis 6 Proof of Lemma 1 7 Optimization References Appendix A Proof of Lemma 7

Merging RLBWTs Adaptively

Travis Gagie ORCID Faculty of Computer Science, Dalhousie University, Halifax, Canada
Abstract

We show how to merge two run-length compressed Burrows-Wheeler Transforms (RLBWTs) into a run-length compressed extended Burrows-Wheeler Transform (eBWT) in O(r) space and O((r+L)log(m+n)) time, where m and n are the lengths of the uncompressed strings, r is the number of runs in the final eBWT and L is the sum of its irreducible LCP values.

Keywords and phrases:
Burrows-Wheeler Transform, run-length compression, RLBWT, construction, merging
Copyright and License:
[Uncaptioned image] © Travis Gagie; licensed under Creative Commons License CC-BY 4.0
2012 ACM Subject Classification:
Theory of computation Pattern matching
Funding:
Funded by NSERC Discovery Grant RGPIN-07185-2020.
Editors:
Philip Bille and Nicola Prezza

1 Introduction

The Burrows-Wheeler Transform (BWT) [8] is an important tool in modern genomics. As DNA sequencing technologies have advanced and researchers have started working with pangenomic references, they have begun using run-length compressed BWTs (RLBWTs). There are good algorithms for building RLBWTs for massive pangenomic references in which all the genomes are similar [4, 14] but the case when the reference contains many genomes from each of many species is still challenging. One possible solution is to build a separate RLBWT for each species and then merge them into a single RLBWT or run-length compressed extended BWT (eBWT) [19].

Merging BWTs is an established research topic [11, 12, 24] and merging RLBWTs [23, 17] is a natural extension of that. As far as we know, however, until recently all algorithms for merging RLBWTs were based on dynamic RLBWTs [22, 2] and used time at least roughly linear in the size of the uncompressed inputs, even if they used compressed space. Díaz-Domínguez et al. [9] gave an algorithm for merging BWTs that can be extended to RLBWTs and works faster when the inputs are individually repetitive but not similar to each other. Because it is based on prefix-free parsing, however, it does not have good worst-case bounds. In this paper we show how to merge two RLBWTs into a run-length compressed eBWT in O(r) space and O((r+L)log(m+n)) time, where m and n are the lengths of the uncompressed strings, r is the number of runs in the final eBWT and L is the sum of the longest common prefix (LCP) values at the beginnings of those runs (known as its irreducible LCP values). It is known that LO((m+n)logδ) [15], where δr is a powerful measure of the eBWT’s compressibility [16].

We describe here only how to merge the RLBWTs of two strings. Our algorithm can easily be extended to merge many RLBWTs or run-length compressed eBWTs, but we leave that to the full version of the paper. In Section 2 we review some preliminary concepts. As warm-ups, in Section 3 we present simple algorithms for merging positional BWTs (PBWTs) and RLBWTs. In Section 4 we present our main algorithm and in Section 5 we present a first analysis that yields a time bound of O((rlogr+L)log(m+n)). In Section 6 we give the proof of a technical lemma we use, whose details we refer to in Section 7 when we optimize our algorithm slightly to reduce the rlogr in our time bound to r, so the whole bound becomes O((r+L)log(m+n)).

2 Preliminaries

For the sake of brevity, we assume readers are familiar with run-length compression, the Burrows-Wheeler Transform (BWT), run-length compressed BWTs (RLBWTs), positional BWTs (PBWTs) [10], suffix arrays (SAs), the Ψ function and longest common prefix (LCP) arrays; see Mäkinen et al.’s [18] and Navarro’s [20] texts for an introduction. The extended BWT (eBWT) [19] of two strings S[1..m] and T[1..n] is an interleaving BWTS,T[1..m+n] of the characters BWTS[1..m] and BWTT[1..n] of S and T. Since BWTS and BWTT are subsequences of BWTS,T, if it has r runs then they each have at most r runs. For convenience, we write BWTS, BWTT and BWTS,T to denote both the BWTs and the RLBWTs, stating when they are run-length compressed.

For 1hm+n, BWTS,T[h] has the lexicographically hth smallest context. The contexts of BWTS[i] and BWTT[j] are

contextS(i) = S[SAS[i]..m]S[1..SAS[i]1]
contextT(j) = T[SAT[j]..n]T[1..SAT[j]1]

(unless SAS[i]=1, in which case contextS(i) is just S[1..m], or SAT[j]=1, in which case contextT(j) is just T[1..n]), where denotes concatenation. If we assume S and T are each terminated by an end-of-string symbol that occurs nowhere else in S and T then two characters in the same BWT cannot have the same context, and a character in BWTS and a character in BWTT have the same context if and only if S=T and the characters are in the same positions (in which case we can break ties arbitrarily without affecting BWTS,T).

We can store a move structure [21] (see also [6]) for the Ψ function ΨS of S in O(r) space such that, given BWTS and position i in it, we can extract BWTS[i]’s context

S[SAS[i]..n]S[1..SAS[i]1]=BWTS[ΨS(i)]BWTS[ΨS2(i)]BWTS[ΨS3(i)]BWTS[ΨSn(i)]

character by character by iteratively evaluating ΨS in O(logr) time plus constant time per iteration or, equivalently, per character extracted. Brown [5] and Bertram et al. [3] (see also [7]) showed how we can build such a move structure in O(rlogr) time. An analogous result holds for T.

Lemma 1.

Given the RLBWTs BWTS and BWTT, in O(rlogr) time we can build O(r)-space data structures for iteratively evaluating the Ψ functions for S and T in O(logr) time plus constant time per iteration.

It follows that we can compare contextS(i) and contextT(j) in O(logr) time plus time proportional to the length of their longest common prefix. We give a proof of Lemma 1 in Section 6 and then explain in Section 7 how we can pay the O(logr) overhead only three times during a binary search to find, for example, the smallest value j with contextT(j) lexicographically larger than contextS(i), denoted contextT(j)contextS(i), rather than paying it at every step of the search.

3 Warm-ups

Suppose we have the PBWTs for two sets of haplotypes from the same species, with the same number of columns (but not necessarily the same number of rows) and with the columns representing the same variation sites, and we want the PBWT for all the haplotypes. For example, consider the PBWTs shown in Figure 1, with the bottom PBWT being the merge of the top two (and the example from [13] with indexing from 1 for consistency with the rest of this paper). The entries of the prefix arrays (showing what haplotype each PBWT entry corresponds to) are shown in parentheses. Cells are red if their information is for one of the first 10 haplotypes and blue if it is for one of the second 10. This makes it easy to see that, by the definition of the PBWT, each column in the merged PBWT is an interleaving of the corresponding columns in the two input PBWTs.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1 (1) 1 (5) 0 (1) 1 (1) 1 (9) 0 (1) 0 (1) 0 (1) 0 (1) 0 (1) 0 (1) 1 (1) 1 (8) 1 (2) 1 (5)
1 (2) 1 (6) 0 (2) 1 (2) 0 (1) 1 (5) 0 (10) 0 (10) 1 (10) 1 (9) 0 (5) 1 (5) 0 (2) 1 (10) 1 (6)
1 (3) 1 (7) 0 (3) 1 (3) 1 (2) 1 (6) 0 (9) 0 (9) 0 (9) 0 (5) 0 (6) 1 (6) 0 (10) 0 (5) 1 (7)
1 (4) 1 (8) 0 (4) 1 (4) 1 (3) 1 (7) 0 (2) 1 (2) 0 (5) 0 (6) 0 (7) 1 (7) 1 (1) 0 (6) 1 (3)
0 (5) 1 (9) 0 (5) 1 (5) 1 (4) 1 (8) 0 (3) 1 (3) 0 (6) 0 (7) 0 (8) 0 (8) 0 (5) 0 (7) 1 (4)
0 (6) 1 (10) 0 (6) 1 (6) 0 (5) 0 (10) 0 (4) 1 (4) 0 (7) 0 (8) 0 (2) 0 (2) 0 (6) 0 (3) 1 (9)
0 (7) 0 (1) 0 (7) 1 (7) 0 (6) 0 (9) 0 (5) 0 (5) 0 (8) 0 (2) 0 (3) 1 (3) 0 (7) 0 (4) 1 (8)
0 (8) 0 (2) 0 (8) 1 (8) 0 (7) 0 (2) 0 (6) 0 (6) 0 (2) 0 (3) 0 (4) 1 (4) 0 (3) 0 (9) 1 (1)
0 (9) 0 (3) 0 (9) 0 (9) 0 (8) 0 (3) 0 (7) 0 (7) 0 (3) 0 (4) 0 (10) 0 (10) 0 (4) 0 (8) 1 (2)
0 (10) 0 (4) 0 (10) 1 (10) 0 (10) 0 (4) 0 (8) 0 (8) 0 (4) 0 (10) 1 (9) 1 (9) 0 (9) 0 (1) 1 (10)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0 (11) 1 (11) 0 (11) 1 (11) 1 (12) 0 (15) 0 (15) 0 (15) 1 (15) 0 (17) 0 (17) 1 (17) 1 (20) 1 (11) 1 (19)
0 (12) 1 (12) 0 (12) 0 (12) 1 (13) 0 (16) 0 (16) 0 (16) 1 (16) 0 (12) 1 (12) 1 (19) 1 (15) 0 (19) 0 (12)
0 (13) 1 (13) 0 (13) 0 (13) 1 (14) 1 (18) 0 (11) 0 (11) 1 (11) 0 (19) 0 (19) 1 (18) 1 (16) 0 (12) 1 (13)
0 (14) 1 (14) 0 (14) 0 (14) 0 (15) 0 (11) 0 (17) 0 (17) 0 (17) 0 (18) 0 (18) 0 (20) 0 (11) 0 (13) 1 (14)
0 (15) 1 (15) 0 (15) 0 (15) 0 (16) 0 (17) 0 (12) 0 (12) 0 (12) 0 (20) 0 (20) 0 (15) 1 (17) 0 (14) 1 (20)
0 (16) 1 (16) 0 (16) 0 (16) 0 (18) 0 (12) 0 (13) 0 (13) 1 (13) 0 (15) 0 (15) 0 (16) 0 (19) 0 (20) 1 (15)
0 (17) 1 (17) 0 (17) 1 (17) 1 (19) 0 (13) 0 (14) 0 (14) 1 (14) 0 (16) 0 (16) 0 (11) 1 (18) 0 (15) 1 (16)
1 (18) 1 (19) 1 (19) 0 (18) 1 (20) 0 (14) 0 (19) 0 (19) 0 (19) 0 (11) 0 (11) 1 (12) 0 (12) 0 (16) 1 (17)
0 (19) 1 (20) 1 (20) 0 (19) 0 (11) 0 (19) 1 (20) 0 (18) 0 (18) 0 (13) 1 (13) 1 (13) 0 (13) 0 (17) 1 (18)
0 (20) 1 (18) 0 (18) 0 (20) 0 (17) 0 (20) 0 (18) 0 (20) 0 (20) 0 (14) 1 (14) 1 (14) 0 (14) 0 (18) 1 (11)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1 (1) 1 (5) 0 (1) 1 (1) 1 (9) 0 (15) 0 (15) 0 (15) 1 (15) 0 (1) 0 (1) 1 (1) 1 (8) 1 (2) 1 (19)
1 (2) 1 (6) 0 (2) 1 (2) 1 (12) 0 (16) 0 (16) 0 (16) 1 (16) 0 (17) 0 (17) 1 (17) 1 (20) 1 (10) 1 (5)
1 (3) 1 (7) 0 (3) 1 (3) 1 (13) 1 (18) 0 (1) 0 (1) 0 (1) 1 (9) 1 (12) 1 (19) 0 (2) 1 (11) 1 (6)
1 (4) 1 (8) 0 (4) 1 (4) 1 (14) 0 (1) 0 (10) 0 (10) 1 (10) 0 (12) 0 (19) 1 (18) 1 (15) 0 (19) 1 (7)
0 (5) 1 (9) 0 (5) 1 (5) 0 (15) 1 (5) 0 (11) 0 (11) 1 (11) 0 (19) 0 (18) 1 (5) 1 (16) 0 (5) 1 (3)
0 (6) 1 (10) 0 (6) 1 (6) 0 (16) 1 (6) 0 (17) 0 (17) 0 (17) 0 (18) 0 (5) 1 (6) 0 (10) 0 (6) 1 (4)
0 (7) 1 (11) 0 (7) 1 (7) 0 (18) 1 (7) 0 (9) 0 (9) 0 (9) 0 (5) 0 (6) 1 (7) 0 (11) 0 (7) 0 (12)
0 (8) 1 (12) 0 (8) 1 (8) 1 (19) 1 (8) 0 (12) 0 (12) 0 (12) 0 (6) 0 (7) 0 (8) 1 (1) 0 (3) 1 (13)
0 (9) 1 (13) 0 (9) 0 (9) 1 (20) 0 (10) 0 (13) 0 (13) 1 (13) 0 (7) 0 (8) 0 (20) 1 (17) 0 (4) 1 (14)
0 (10) 1 (14) 0 (10) 1 (10) 0 (1) 0 (11) 0 (14) 0 (14) 1 (14) 0 (8) 0 (20) 0 (2) 0 (19) 0 (12) 1 (9)
0 (11) 1 (15) 0 (11) 1 (11) 1 (2) 0 (17) 0 (19) 0 (19) 0 (19) 0 (20) 0 (2) 1 (3) 1 (18) 0 (13) 1 (8)
0 (12) 1 (16) 0 (12) 0 (12) 1 (3) 0 (9) 1 (20) 1 (2) 0 (18) 0 (2) 0 (3) 1 (4) 0 (5) 0 (14) 1 (20)
0 (13) 1 (17) 0 (13) 0 (13) 1 (4) 0 (12) 0 (2) 1 (3) 0 (5) 0 (3) 0 (4) 0 (15) 0 (6) 0 (9) 1 (15)
0 (14) 1 (19) 0 (14) 0 (14) 0 (5) 0 (13) 0 (3) 1 (4) 0 (6) 0 (4) 0 (15) 0 (16) 0 (7) 0 (8) 1 (16)
0 (15) 1 (20) 0 (15) 0 (15) 0 (6) 0 (14) 0 (4) 0 (18) 0 (7) 0 (15) 0 (16) 0 (10) 0 (3) 0 (20) 1 (1)
0 (16) 0 (1) 0 (16) 0 (16) 0 (7) 0 (19) 0 (18) 0 (5) 0 (8) 0 (16) 0 (10) 0 (11) 0 (4) 0 (15) 1 (17)
0 (17) 0 (2) 0 (17) 1 (17) 0 (8) 0 (20) 0 (5) 0 (6) 0 (20) 0 (10) 0 (11) 1 (12) 0 (12) 0 (16) 1 (18)
1 (18) 0 (3) 1 (19) 0 (18) 0 (10) 0 (2) 0 (6) 0 (7) 0 (2) 0 (11) 1 (13) 1 (13) 0 (13) 0 (1) 1 (2)
0 (19) 0 (4) 1 (20) 0 (19) 0 (11) 0 (3) 0 (7) 0 (8) 0 (3) 0 (13) 1 (14) 1 (14) 0 (14) 0 (17) 1 (10)
0 (20) 1 (18) 0 (18) 0 (20) 0 (17) 0 (4) 0 (8) 0 (20) 0 (4) 0 (14) 1 (9) 1 (9) 0 (9) 0 (18) 1 (11)
Figure 1: Two PBWTs for 10 haplotypes each (above), and the PBWT for all 20 haplotypes (below). The entries of the prefix arrays are shown in parentheses. Cells are red if their information is for one of the first 10 haplotypes and blue if it is for one of the second 10.

The first column from the left of the merged PBWT is the concatenation of the the first columns of the two input PBWTs. Suppose we have already merged the (j1)st columns of the input PBWTs into the (j1)st column of the merged PBWT, and now we want to merge their jth columns into its jth column. In particular, suppose we know how the (j1)st column of the merged PBWT is divided into maximal blocks of consecutive bits that all come from the same input PBWT. In our example, the blocks in the 9th column have lengths 2,2,2,1,5,4,1,3 and alternate between blue and red with the first block being blue.

To compute the jth column of the merged PBWT after computing the (j1)st column, we first consider all the 0s in the (j1)st column and list the next bits in their haplotypes (in the 0s’ order in the (j1)st column), then consider all the 1s in the (j1)st column and list the next bits in their haplotypes (in the 1s’ order in the (j1)st column); the jth column of the merged PBWT is the concatenation of the two lists. By induction, the bits in the jth column are in the co-lexicographic order of the preceding prefixes in their haplotypes.

Because the jth columns of the two input PBWTs already contain all those next bits and in the correct order, we can use the input PBWTs instead of the explicit haplotypes. To do this, we start with an empty draft of the jth column of the merged PBWT and scan the (j1)st column of the merged PBWT twice. During the first scan, whenever we see a 0 we copy a bit (the next bit in that 0’s haplotype) from the jth column of the input PBWT that is the source of that 0. During the second scan, whenever we see a 1 we copy a bit (the next bit in that 1’s haplotype) from the jth column of the input PBWT that is the source of that 1. However, our algorithm may work more efficiently considering blocks rather than literally bit by bit.

Suppose the (j1)st column of the merged PBWT consists of b blocks. For k from 1 to b, if there are c copies of 0 in the kth block in the (j1)st column then we append to our draft of the jth column of the merged PBWT the next c bits of the jth column of the input PBWT that is the source of the bits in the kth block. After that, for k from 1 to b, if there are c copies of 1 in the kth block of the (j1)st column then we append to our draft of the jth column of the merged PBWT the next c bits of the jth column of the input PBWT that is the source of the bits in the kth block.

In our example, there are no copies of 0s in the first block of the 9th column, which is blue, so we append no bits from the 10th column of the blue PBWT; there is 1 copy of 0 in the second block of the 9th column, which is red, so we append 1 bit (0) from the 10th column of the red PBWT (from haplotype (1)); then 1 bit (0) from the blue PBWT (from haplotype (17)); then 1 bit (1) from the red PBWT (from haplotype (9)); then 3 bits (000) from the blue PBWT (from haplotypes (12), (19) and (18)); then 4 bits (0000) from the red PBWT (from haplotypes (5), (6), (7) and (8)); then 1 bit (0) from the blue PBWT (from haplotype (20)); then 3 bits (000) from the red PBWT (from haplotypes (2), (3) and (4)).

There are 2 copies of 1 in the first block of the 9th column, which is blue, so we append 2 bits (00) from the 10th column of the blue PBWT (from haplotypes (15) and (16)); then 1 bit (0) from the from the red PBWT (from haplotype (10)); then 1 bit (0) from the blue PBWT (from haplotype (11)); then no bits from the red PBWT; then 2 bits (00) from the blue PBWT (from haplotypes (13) and (14)). When we are finished, we know the 10th column of the merged PBWT is 00100000000000000000 and we know its blocks have lengths 1, 1, 3, 4, 1, 3, 2, 1, 3; its prefix array is (1) (17) (9) (12) (19) (18) (5) (6) (7) (8) (20) (2) (3) (4) (15) (16) (10) (11) (13) (14).

If a block in the (j1)st column of the merged PBWT overlaps t runs of bits in that column, then computing the numbers of 0s and 1s in that block takes O(t) time. We perform one append operation for the 0s in that block and another for the 1s. If the input PBWTs are run-length compressed and we want only the jth column and its block structure – which is all we need to continue merging the two input PBWTs – but not its prefix array, then each append operation takes time proportional to the number of runs in the substring of bits we append. It follows that we can merge two PBWTs in time O(r+B), where r and B are the total numbers of runs and blocks in all the columns of the merged PBWT, respectively.

Theorem 2.

We can merge two PBWTs with run-length compressed columns in O(r+B) time, where r and B are the total numbers of runs and blocks in all the columns of the merged PBWT, respectively.

Theorem 2 may be of independent interest but we have proven it mainly as a warm-up. As a second warm-up, we now give a simple algorithm for merging RLBWTs that uses O(r) space and O(rlogr+(blogr+B+σ)log(m+n)) time, where r is the number of runs in the resulting eBWT, b is the number of maximal blocks of characters in that eBWT that all come from the same input RLBWT, B is the sum of the LCP values at the beginnings of those blocks, σ is the size of the alphabet, and m and n are the lengths of the uncompressed input BWTs.

Suppose we are to merge the RLBWTs BWTS[1..m] and BWTT[1..n] of strings S[1..m] and T[1..n] into the run-length compressed eBWT BWTS,T[1..m+n] of S and T together, and we have already built the data structures for Ψ for S and T described in Lemma 1 so that we can compare characters’ contexts. For example, if S is the concatenation of the $-terminated strings GATTACAT, GATACAT and GATTAGATA and T is the concatenation of those three strings’ $-terminated reverse complements, then

BWTS = TAT5C2G4A3$3A3TATA2
BWTT = C3T2A2T2$2T6CG2$A6
BWTS,T = C2TATCT6C2G2A2T2$2G2T3A2TA$3T2A3CGTATG$A8,

with exponents indicating run lengths, and BWTS and BWTT are interleaved in BWTS,T as shown in Figure 2. In this toy example, r=27, b=18, B=18, σ=5 and m+n=54.

0 $ATGTAATC$ATGTATC$TATCTAAT C
$ATGTATC$TATCTAATC$ATGTAAT C
1 $GATACAT$GATTAGATA$GATTACA T
$GATTACAT$GATACAT$GATTAGAT A
$GATTAGATA$GATTACAT$GATACA T
1 $TATCTAATC$ATGTAATC$ATGTAT C
0 A$GATTACAT$GATACAT$GATTAGA T
1 AATC$ATGTAATC$ATGTATC$TATC T
AATC$ATGTATC$TATCTAATC$ATG T
1 ACAT$GATACAT$GATTAGATA$GAT T
ACAT$GATTAGATA$GATTACAT$GA T
AGATA$GATTACAT$GATACAT$GAT T
AT$GATACAT$GATTAGATA$GATTA C
AT$GATTAGATA$GATTACAT$GATA C
ATA$GATTACAT$GATACAT$GATTA G
ATACAT$GATTAGATA$GATTACAT$ G
2 ATC$ATGTAATC$ATGTATC$TATCT A
ATC$ATGTATC$TATCTAATC$ATGT A
ATC$TATCTAATC$ATGTAATC$ATG T
ATCTAATC$ATGTAATC$ATGTATC$ T
ATGTAATC$ATGTATC$TATCTAATC $
ATGTATC$TATCTAATC$ATGTAATC $
2 ATTACAT$GATACAT$GATTAGATA$ G
ATTAGATA$GATTACAT$GATACAT$ G
0 C$ATGTAATC$ATGTATC$TATCTAA T
C$ATGTATC$TATCTAATC$ATGTAA T
C$TATCTAATC$ATGTAATC$ATGTA T
1 CAT$GATACAT$GATTAGATA$GATT A
CAT$GATTAGATA$GATTACAT$GAT A
1 CTAATC$ATGTAATC$ATGTATC$TA T
0 GATA$GATTACAT$GATACAT$GATT A
GATACAT$GATTAGATA$GATTACAT $
GATTACAT$GATACAT$GATTAGATA $
GATTAGATA$GATTACAT$GATACAT $
1 GTAATC$ATGTATC$TATCTAATC$A T
GTATC$TATCTAATC$ATGTAATC$A T
0 T$GATACAT$GATTAGATA$GATTAC A
T$GATTAGATA$GATTACAT$GATAC A
TA$GATTACAT$GATACAT$GATTAG A
2 TAATC$ATGTAATC$ATGTATC$TAT C
TAATC$ATGTATC$TATCTAATC$AT G
2 TACAT$GATACAT$GATTAGATA$GA T
TACAT$GATTAGATA$GATTACAT$G A
TAGATA$GATTACAT$GATACAT$GA T
2 TATC$TATCTAATC$ATGTAATC$AT G
TATCTAATC$ATGTAATC$ATGTATC $
TC$ATGTAATC$ATGTATC$TATCTA A
TC$ATGTATC$TATCTAATC$ATGTA A
TC$TATCTAATC$ATGTAATC$ATGT A
TCTAATC$ATGTAATC$ATGTATC$T A
TGTAATC$ATGTATC$TATCTAATC$ A
TGTATC$TATCTAATC$ATGTAATC$ A
1 TTACAT$GATACAT$GATTAGATA$G A
TTAGATA$GATTACAT$GATACAT$G A
Figure 2: The lexicographically sorted cyclic shifts of the concatenation of the three $-terminated strings GATTACAT, GATACAT and GATTAGATA (in red), and of the concatenation of those three strings’ $-terminated reverse complements (in blue), with the LCP values shown at block boundaries (in black). The eBWT of the two concatenations is the last column of the matrix, slightly set from the rest. The red subsequence of the eBWT is the BWT of the first concatenation and the blue subsequence is the BWT of the second.

We first set i and j to 1, then compare contextS(i) and contextT(j) to check whether the first block of characters in BWTS,T is from BWTS or BWTT, and set a Boolean flag to true in the former case and false in the latter. As long as im and jn, if the flag is true then we use a doubling search in BWTS[i..m] to find the largest value i with contextS(i)contextT(j), output BWTS[i..i], reset i to i+1, and reset the flag to false. If the flag is false then we use a doubling search in BWTT[j..n] to find the largest value j with contextT(j)contextS(i), output BWTT[j..j], reset j to j+1, and reset the flag to true. Eventually, when i=m+1 or j=n+1, we output either BWTT[j..n] or BWTS[i..m], respectively. The pseudocode for our algorithm is shown in Algorithm 1.

Algorithm 1 Pseudocode for merging BWTS[1..m] and BWTT[1..n] into BWTS,T[1..m+n].

By induction, during each pass through the while loop, we output the next block of BWTS,T, from BWTS if the flag is true and from BWTT if the flag is false. If the flag is true then all of the O(logm) comparisons we perform during the current pass are against contextT(j), which is in the block from BWTT we will output during the next pass, so the number of characters we extract for each of those comparisons is at most 1 plus the maximum of the LCP values at the boundaries of that block from BWTT. If the flag is false then all of the O(logn) comparisons we perform during the current pass are against contextS(i), which is in the block from BWTS we will output during the next pass, so the number of characters we extract for each of those comparisons is at most 1 plus the maximum of the LCP values at the boundaries of the block from BWTS.

It follows that we can charge all the comparisons to blocks of BWTS,T such that each block is charged O(log(m+n)) comparisons and for each comparison charged to a block, the number of characters we extract is at most 1 plus the maximum of the LCP values at the boundaries of that block. Since at most σ of those LCP values are 0, this means we use O(rlogr+(blogr+B+σ)log(m+n)) total time, including the O(rlogr) time to build the data structures for comparing contexts and the O(logr) overhead for each of the O(blog(m+n)) comparisons. Our algorithm is adaptive in the sense that it takes advantage of cases when b and B are small, which is likely when S and T are individually repetitive but dissimilar.

Theorem 3.

Given the RLBWTs BWTS[1..m] and BWTT[1..n], we can merge them into the run-length compressed eBWT BWTS,T[1..m+n] using O(r) space and O(rlogr+(blogr+B+σ)log(m+n)) time, where r is the number of runs in the resulting eBWT, b is the number of maximal blocks of characters in that eBWT that all come from the same input RLBWT, B is the sum of the LCP values at the beginnings of those blocks, σ is the size of the alphabet, and m and n are the lengths of the uncompressed input BWTs.

4 Main algorithm

Again, suppose we are to merge the RLBWTs BWTS[1..m] and BWTT[1..n] of strings S[1..m] and T[1..n] into the run-length compressed eBWT BWTS,T[1..m+n] of S and T together, and we have already built the data structures for Ψ for S and T described in Lemma 1 so that we can compare characters’ contexts. The pseudocode for our algorithm is shown in Algorithm 2.

Algorithm 2 Pseudocode for merging BWTS[1..m] and BWTT[1..n] into BWTS,T[1..m+n].

Assume we have already merged BWTS[1..i1] and BWTT[1..j1] into BWTS,T[1..i+j2] correctly. When we first reach the while loop (lines 3–43 in Algorithm 2) i=j=1 so this assumption is trivially true. If i>m then BWTS,T[i+j1..m+n]=BWTT[j..n] (line 45) and if j>n then BWTS,T[i+j1..m+n]=BWTS[i..m] (line 47), so assume im and jn and consider only the while loop. Let k and be the lengths of the leading runs of BWTS[i..m] and BWTT[j..n] respectively (lines 4 and 5).

First suppose BWTS[i]=BWTT[j] (lines 7–21), meaning the leading runs BWTS[i..i+k1] and BWTT[j..j+1] of BWTS[i..m] and BWTT[j..n] consist of copies of the same character. If there exists a character BWTS[i+k] after the run BWTS[i..i+k1] and contextS(i+k)contextT(j+1) (lines 8–11) then BWTS[i+k] precedes some non-empty suffix BWTT[j..j+1] of the run BWTT[j..j+1] in BWTS,T, with j being the smallest value with contextT(j)contextS(i+k). We use binary search to find j in the range [j,j+) (line 8), output

BWTS[i..i+k1]BWTT[j..j1]=(BWTS[i])k+jj

(line 9) and reset i to i+k (line 10) and j to j (line 11). Since the characters we output are all equal, we need not consider their order to merge the RLBWTs. (We note, however, that we would need to consider the characters’ order if we were also merging the RLBWTs’ SAs.) The case when there exists a character BWTT[j+] after the run BWTT[j..j+1] and contextT(j+)contextS(i+k1) (lines 13–16) is symmetric.

By the definition of the eBWT, it is impossible for BWTS[i+k] to precede a non-empty suffix of the run BWTT[j..j+1] in BWTS,T and for BWTT[j+] to precede a non-empty suffix of the run BWTS[i..i+k1] in BWTS,T in BWTS,T, since then BWTS[i+k] would have to both precede and follow BWTT[j+]. Therefore, the only remaining case with BWTS[i]=BWTT[j] is when either i+k=m+1 or BWTS[i+k] follows the entire run BWTT[j..j+1] in BWTS,T and either j+=n+1 or BWTT[j+] follows the entire run BWTS[i..i+k1] in BWTS,T. In this case, we output

BWTS[i..i+k1]BWTT[j..j+1]=(BWTS[i])k+

(line 18) and reset i to i+k (line 19) and j to j+ (line 20).

Now suppose BWTS[i]BWTT[j] (lines 23–42). Because S[SAS[i]1]=BWTS[i] (or S[m]=BWTS[i] if SAS[i]=1 so S[1..SAS[i]1] is empty) and T[SAT[j]1]=BWTT[j] (or T[n]=BWTT[j] if SAT[j]=1 so T[1..SAT[j]1] is empty), contextS(i) and contextT(j) differ on their last characters. Therefore, we consider only two cases: when contextS(i)contextT(j) (lines 24–31) and when contextS(i)contextT(j) (lines 33–40).

Suppose contextS(i)contextT(j), meaning BWTS[i] precedes BWTT[j] in BWTS,T. If contextS(i+k1)contextT(j) then the entire run BWTS[i..i+k1] precedes BWTT[j] in BWTS,T, so we output that run (line 25) and reset i to i+k (line 26). Otherwise, some non-empty prefix BWTS[i..i1] of the run BWTS[i..i+k1] precedes BWTT[j] in BWTS,T and some non-empty suffix BWTS[i..i+k1] follows it, with i being the smallest value with contextS(i)contextT(j). We use binary search (line 28) to find i in the range (i,i+k1], comparing the context of a character in BWTS[i+1..i+k1] to contextT(j) at each step. We output BWTS[i..i1] (line 29) and reset i to i (line 30). The case when contextS(i)contextT(j) is symmetric.

We exit the while loop only after having consumed all of at least one of BWTS and BWTT. If we have not consumed all of the other, we output the rest of it (lines 44 to 48).

5 First analysis

Building the structures in Lemma 1 takes O(rlogr)O(rlog(m+n)) time, where r is the number of runs in BWTS,T. Since BWTS and BWTT both consist of at most r runs, outputting BWTS[i..m] (line 45) or BWTT[j..n] (line 47) in run-length compressed form takes O(r) time. Therefore, we can focus on the complexity of the while loop.

Lemma 4.

During each pass through the while loop, we output an entire run in BWTS,T.

Proof.

Whenever we reach line 9 we have contextS(i+k)contextT(j) so, after we output

BWTS[i..i+k1]BWTT[j..j1]=(BWTS[i])k+jj,

the next character we output is BWTS[i+k]BWTS[i] and it starts a new run in BWTS,T. Symmetrically, after we reach line 14 and output

BWTS[i..i1]BWTT[j..j+1]=(BWTS[i])ii+,

the next character we output is BWTT[j+]BWTT[j] and it starts a new run in BWTS,T. After we reach line 18 and output

BWTS[i..i+k1]BWTT[j..j+1]=(BWTS[i])k+,

the next character we output (if there is one) is either BWTS[i+k]BWTS[i] or BWTT[j+]BWTT[j] and it starts a new run in BWTS,T. After we reach line 25 and output

BWTS[i..i+k1]=(BWTS[i])k,

the next character we output is either BWTS[i+k]BWTS[i] or BWTT[j]BWTS[i] and it starts a new run in BWTS,T. Symmetrically, after we reach line 34 and output

BWTT[j..j+1]=(BWTT[j]),

the next character we output is either BWTT[i+]BWTT[j] or BWTS[i]BWTT[j] and it starts a new run in BWTS,T. After we reach line 29 and output

BWTS[i..i1]=(BWTS[i])ii,

the next character we output is BWTT[j]BWTS[i] and it starts a new run in BWTS,T. Symmetrically, after we reach line 38 and output

BWTT[j..j1]=(BWTT[j])jj,

the next character we output is BWTS[i]BWTT[j] and it starts a new run in BWTS,T. It follows from Lemma 4 that we make O(r) passes through the while loop. Since BWTS and BWTT and BWTS,T are run-length compressed, the only operations that can take more than constant time during a single pass through the while loop are comparisons between characters’ contexts, of which we make O(log(m+n)) during each pass, so O(rlog(m+n)) in total.

Lemma 5.

Whenever we compare two characters’ contexts

  • those two characters are not equal, so they are in different runs in BWTS,T;

  • at least one of those two characters is in the run in BWTS,T output during the current pass through the while loop or the run in BWTS,T output during the next pass.

Proof.

When we check whether contextS(i+k)contextT(j+1) in line 7,

BWTS[i+k]BWTS[i]=BWTT[j]=BWTT[j+1]

and we output either BWTS[i+k] or BWTT[j+] during the next pass. The comparison in line 12 is symmetric. When we perform the binary search in line 8, in each step we check whether contextT(j)contextS(i+k) for some j<j+ with

BWTT[j]=BWTT[j]=BWTS[i]BWTS[i+k]

and we output BWTS[i+k] during the next pass. The binary search in line 13 is symmetric. When we check whether contextS(i)contextT(j) in line 23, BWTS[i]BWTT[j] and we output either BWTS[i] or BWTT[j] during the current pass. When we check whether contextS(i+k1)contextT(j) in line 24,

BWTS[i+k1]=BWTS[i]BWTT[j]

and we output either BWTS[i+k1] during the current pass or BWTT[j] during the next pass. The comparison in line 33 is symmetric. When we perform the binary search in line 28, in each step we check whether contextS(i)contextT(j) for some i<i+k with

BWTS[i]=BWTS[i]BWTT[j]

and we output BWTT[j] during the next pass. The binary search in line 37 is symmetric. It follows from Lemma 5 that we can charge all the context comparisons to runs in BWTS,T such that

  • each run in BWTS,T has O(log(m+n)) context comparisons charged to it;

  • if a comparison between two characters’ contexts is charged to a run in BWTS,T then one of the characters is in that run and the other is not.

The number of characters we extract to compare the context of a character in a run BWTS,T[a..b] to the context of a character in another run is at most

1+max(LCPS,T[a],LCPS,T[b+1])

(unless b=m+n, in which case the number is just LCPS,T[a]), where LCPS,T[1]=0 and, for 1<hm+n, LCPS,T[h] is the length of the longest common prefix of the contexts of the hth and (h1)st characters in BWTS,T. This takes

O(logr+max(LCPS,T[a],LCPS,T[b+1]))

time. Therefore, the time for the context comparisons charged to BWTS,T[a..b] is

O((logr+max(LCPS,T[a],LCPS,T[b+1]))log(m+n)).

Summing over the r runs in BWTS,T, the total time for context comparisons is

O((rlogr+L)log(m+n)),

where L is the sum of its irreducible LCP values. Combined with our previous observations, this gives us a preliminary result:

Theorem 6.

Given the RLBWTs BWTS[1..m] and BWTT[1..n], we can merge them into the run-length compressed eBWT BWTS,T[1..m+n] using O(r) space and O((rlogr+L)log(m+n)) time, where m and n are the lengths of the uncompressed strings, r is the number of runs in BWTS,T and L is the sum of its irreducible LCP values.

6 Proof of Lemma 1

The logr in Theorem 6’s time bound comes from paying the O(logr) overhead in Lemma 1 at every step of each binary search. In Section 7 we will explain how to avoid that and pay the overhead only three times during a binary search, but first it helps to examine the proof of Lemma 1.

If an RLBWT for a string of length n has r runs then its Ψ function is a permutation on {1,,n} with

|{1}{i: 1in,Ψ(i)Ψ(i1)+1}|=r.

Given the RLBWT, in O(rlogr) total time we can first build the set

{(1,Ψ(1))}{(i,Ψ(i)): 1in,Ψ(i)Ψ(i1)+1};

then apply Lemma 7 below to obtain a slightly larger superset P with useful properties; and finally build a move structure with which, given i and i’s predecessor in P, in constant time we can find Ψ(i) and Ψ(i)’s predecessor in P. Given only i, we can find i’s predecessor in P in O(logr), then use the move structure to iterate ψ and extract the context of the ith character in the RLBWT character by character in constant time per character; Lemma 1 follows.

We refer readers to Nishimoto and Tabei’s [21], Brown et al.’s [6] and Bertram et al.’s [3] papers and Brown’s [5] thesis for more details on building move structures. For the sake of completeness, we include a proof of Lemma 7 in the appendix, mostly following Brown et al.’s and Bertram et al.’s presentation but with a potential-function argument by Alhadi [1].

Lemma 7.

Let π be a permutation on {1,,n} and

P={1}{i: 1<in,π(i)π(i1)+1}.

Given the set {(i,π(i)):iP} and an integer d2, we can build a set {(i,π(i)):iP}, where

  • PP{1,,n},

  • if a and b are consecutive elements in {π(i):iP}{n+1} then |[a,b)P|<2d,

  • |P|d|P|d1.

This takes O(|P|log|P|) time in general but O(|P|log|P|d) time when n is polynomial in |P|.

7 Optimization

The O(logr) overhead in Lemma 1 comes from a predecessor query on a set of size O(r), as described in Section 6. For our algorithm, that is multiplied by the O(r) passes we make through the while loop and by the O(log(m+n)) context comparisons we may make during each pass if we reach line 8, 13, 28 or 37 and perform a binary search in an RLBWT. If we do not perform such a binary search during a pass then we make only a constant number of context comparisons in that pass and they contribute only O(logr)O(log(m+n)) overhead, so we need not worry about this case.

To see how to speed up the binary searches in the RLBWTs, consider how we search for the smallest value j with contextT(j)contextS(i+k) in line 8, for example. We repeatedly choose candidate values j in [j,j+) and, for each one, compare contextT(j) with contextS(i+k). If we choose the candidate values j naïvely, then each context comparison starts with a predecessor query on PT, where PT is the set we build with Lemma 7 as part of building a move structure for Ψ on T. If we choose jPT or already knowing the predecessor of j in PT, however, then we do not need such a predecessor query and we do not pay the O(logn) overhead for that step of the binary search.

In an optimized binary search for j, we first pay the O(logr) overhead once to be able to extract contextS(i+k). We then pay O(logr) overheads twice more to find the successor of j and the predecessor of j+1 in PT. We then use binary search to find the smallest value p[j,j+)PT with contextT(p)contextS(i+k), if there is one. Since p[j,j+)PTPT, we do not pay the O(logn) overhead for these steps. Whether p exists or not, we can now focus our search on interval of [j,j+) in which all the elements have the same predecessor in PT, so we do not pay the O(logn) overhead for these steps either. Binary searches on BWTS can be sped up symmetrically.

Lemma 5 still holds and we can charge all the context comparisons as before. Now, however, the time for the context comparisons charged to a run BWTS,T[a..b] in BWTS,T is only

O(logr+(1+max(LCPS,T[a],LCPS,T[b+1]))log(m+n)).

Summing over the r runs in BWTS,T, the total time for context comparisons is

O(rlogr+(r+L)log(m+n))=O((r+L)log(m+n)).

This gives us our main result:

Theorem 8.

Given the RLBWTs BWTS[1..m] and BWTT[1..n], we can merge them into the run-length compressed eBWT BWTS,T[1..m+n] using O(r) space and O((r+L)log(m+n)) time, where m and n are the lengths of the uncompressed strings, r is the number of runs in BWTS,T and L is the sum of its irreducible LCP values.

With care, it is possible to combine Theorems 3 and 8 and obtain the advantages of each – using doubling search among run boundaries and achieving adaptivity with respect to b, B and L simultaneously (better than simply dovetailing) – but we leave that as an exercise for the reader until we publish the full version of this paper.

References

  • [1] Anas Alhadi. Personal communication, 2026.
  • [2] Hideo Bannai, Travis Gagie, and Tomohiro I. Refining the r-index. Theoretical Computer Science, 812, 2020. doi:10.1016/J.TCS.2019.08.005.
  • [3] Nico Bertram, Johannes Fischer, and Lukas Nalbach. Move-r: Optimizing the r-index. In Proceedings of the 22nd Symposium on Experimental Algorithms (SEA), 2024. doi:10.4230/LIPIcs.SEA.2024.1.
  • [4] Christina Boucher, Travis Gagie, Alan Kuhnle, Ben Langmead, Giovanni Manzini, and Taher Mun. Prefix-free parsing for building big BWTs. Algorithms for Molecular Biology, 14, 2019. doi:10.1186/S13015-019-0148-5.
  • [5] Nathaniel K. Brown. BWT-runs compressed data structures for pan-genomics text indexing. Mcs thesis, Dalhousie University, 2023.
  • [6] Nathaniel K. Brown, Travis Gagie, and Massimiliano Rossi. RLBWT tricks. In Proceedings of the 20th Symposium on Experimental Algorithms (SEA), 2022. doi:10.4230/LIPIcs.SEA.2022.16.
  • [7] Nathaniel K. Brown and Ben Langmead. Bounding the average move structure query for faster and smaller RLBWT permutations. In Proceedings of the 24th Symposium on Experimental Algorithms (SEA), 2026.
  • [8] Michael Burrows and David J. Wheeler. A block-sorting lossless data compression algorithm. Technical report, Digital Equipment Corporation, 1994.
  • [9] Diego Díaz-Domínguez, Travis Gagie, Veronica Guerrini, Ben Langmead, Zsuzsanna Lipták, Giovanni Manzini, Francesco Masillo, and Vikram Shivakumar. Prefix-free parsing for merging big BWTs. In Proceedings of the 32nd Symposium on String Processing and Information Retrieval (SPIRE), 2025.
  • [10] Richard Durbin. Efficient haplotype matching and storage using the positional Burrows–Wheeler transform (PBWT). Bioinformatics, 30, 2014. doi:10.1093/BIOINFORMATICS/BTU014.
  • [11] Paolo Ferragina, Travis Gagie, and Giovanni Manzini. Lightweight data indexing and compression in external memory. Algorithmica, 63, 2012. doi:10.1007/S00453-011-9535-0.
  • [12] James Holt and Leonard McMillan. Merging of multi-string BWTs with applications. Bioinformatics, 30, 2014. doi:10.1093/BIOINFORMATICS/BTU584.
  • [13] Uwaise Ibna Islam, Davide Cozzi, Travis Gagie, Rahul Varki, Vincenza Colonna, Erik Garrison, Paola Bonizzoni, and Christina Boucher. Scalable PBWT queries with minimum-length SMEM constraints. bioRxiv, 2025.
  • [14] Dominik Kempa. Optimal construction of compressed indexes for highly repetitive texts. In Proceedings of the 30th Symposium on Discrete Algorithms (SODA), 2019.
  • [15] Dominik Kempa and Tomasz Kociumaka. Resolution of the Burrows-Wheeler transform conjecture. Communications of the ACM, 65, 2022. doi:10.1145/3531445.
  • [16] Tomasz Kociumaka, Gonzalo Navarro, and Nicola Prezza. Toward a definitive compressibility measure for repetitive sequences. IEEE Transactions on Information Theory, 69, 2022.
  • [17] Heng Li. BWT construction and search at the terabase scale. Bioinformatics, 40, 2024.
  • [18] Veli Mäkinen, Djamal Belazzougui, Fabio Cunial, and Alexandru I. Tomescu. Genome-Scale Algorithm Design: Bioinformatics in the Era of High-Throughput Sequencing. Cambridge University Press, 2nd edition, 2023.
  • [19] Sabrina Mantaci, Antonio Restivo, Giovanna Rosone, and Marinella Sciortino. An extension of the Burrows–Wheeler transform. Theoretical Computer Science, 387, 2007. doi:10.1016/J.TCS.2007.07.014.
  • [20] Gonzalo Navarro. Compact Data Structures: A Practical Approach. Cambridge University Press, 2016.
  • [21] Takaaki Nishimoto and Yasuo Tabei. Optimal-time queries on BWT-runs compressed indexes. In Proceedings of the 48th International Colloquium on Automata, Languages, and Programming (ICALP), 2021. doi:10.4230/LIPIcs.ICALP.2021.101.
  • [22] Tatsuya Ohno, Kensuke Sakai, Yoshimasa Takabatake, Tomohiro I, and Hiroshi Sakamoto. A faster implementation of online RLBWT and its application to LZ77 parsing. Journal of Discrete Algorithms, 52, 2018.
  • [23] Marco Oliva, Massimiliano Rossi, Jouni Sirén, Giovanni Manzini, Tamer Kahveci, Travis Gagie, and Christina Boucher. Efficiently merging r-indexes. In Proceedings of the 31st Data Compression Conference (DCC), 2021.
  • [24] Jouni Sirén. Burrows-Wheeler transform for terabases. In Proceedings of the 26th Data Compression Conference (DCC), 2016.

Appendix A Proof of Lemma 7

Lemma 0.

Let π be a permutation on {1,,n} and

P={1}{i: 1<in,π(i)π(i1)+1}.

Given the set {(i,π(i)):iP} and an integer d2, we can build a set {(i,π(i)):iP}, where

  • PP{1,,n},

  • if a and b are consecutive elements in {π(i):iP}{n+1} then |[a,b)P|<2d,

  • |P|d|P|d1.

This takes O(|P|log|P|) time in general but O(|P|log|P|d) time when n is polynomial in |P|.

Proof.

Let Q={π(i):iP}{n+1}. We build AVL trees TP and TQ storing the elements of P and Q, respectively. For each iP we store π(i) as satellite data with i in TP, and we store i as satellite data with π(i) in TQ. For each pair of consecutive elements a and b in Q, if |[a,b)P|2d then we store the pair (a,b) in a list L. The bottleneck is sorting P and Q, which takes O(|P|log|P|) time in general but O(|P|) time when n is polynomial in |P|.

We work in rounds and maintain the relationships between TP, TQ and L. In each round we check if L is empty and, if so, we return each element i in TP together with its satellite data π(i) and then stop; if not, we remove 1 element from L and then insert 1 element into TP, 1 element into TQ and up to 2 elements into L.

Let Pj and Qj be the contents of TP and TQ after j rounds, so P0=P and Q0=Q. Suppose we remove (s,e) from L during the (j+1)st round, meaning [s,e)Pj2d. We use TP to find the (d+1)st smallest element p in [s,e)Pj. We use TQ to find π1(p) by finding the predecessor q of p in Qj and adding pq to π1(q), which is stored as satellite data with q. We insert π1(p) into TP with p as satellite data, and insert p into TQ with π1(p) as satellite data. Therefore Qj+1={π(i):iPj+1}{n+1}.

To see why π1(p)=π1(q)+pq and suppose π(x)=y. If xPj then yQj, so if yQj then xPj. Therefore, if yQj then π(x)=π(x1)+1 and so y1=π(x1); applying π1 to both sides we have π1(y1)=x1 and so π1(y)=π1(y1)+1. Since q is p’s predecessor in Qj, it follows that π1(p)=π1(q)+pq.

We use TP and TQ to check first whether |[p,e)Pj+1|2d; if so, we add (p,e) to L. We then use TP and TQ to find the predecessor s of π1(p) in Qj+1 and next element e after s in Qj+1, and to check whether |[s,e)Pj+1|=2d; if so, we add (s,e) to L. Notice that if |[s,e)Pj+1|>2d then |[s,e)Pj|2d so (s,e) was already in L. This completes the (j+1)st round, which takes O(log|Pj|) total time.

To bound the number of rounds we use, let

f(k)={max([a,b)Pkd,0):a and b are consecutive elements in Qk}

and consider how we obtain f(j+1) from f(j). We subtract the term max(|[s,e)Pj|d,0); add the terms max(|[s,p)Pj|d,0) and max(|[p,e)Pj|d,0); and finally increment the term max(|[s,e)Pj|d,0), to make everything with respect to Pj+1 instead of Pj. Since

2d|[s,e)Pj|=|[s,p)Pj|+|[p,e)Pj|=d+|[p,e)Pj|,

we have

max(|[s,e)Pj|d,0) = |[p,e)Pj|,
max(|[s,p)Pj|d,0) = 0,
max(|[p,e)Pj|d,0) = |[p,e)Pj|d.

It follows that f(j+1)f(j)(d1).

Since f(0)|P| and we stop if f(j+1)=0 and |Pj+1||Pj|+1, we use at most |P|d1 rounds and return P with

|P||P|+|P|d1=d|P|d1.

Since the (j+1)st round takes O(log|Pj|)=O(log|P|) time for all j, over all the rounds we use O(|P|log|P|d) total time.