Abstract 1 Introduction 2 Preliminaries 3 A Lower Bound and an Upper Bound on 𝒓~ 4 The Three-Overlap Constraint and a Normalization Algorithm 5 Constructing Sub-Runs and Bounding Their Number 6 The Data Structure for Constant-Time fore/back Queries 7 Applications 8 Conclusions References Appendix A The Figure Omitted from Section 5 Appendix B The Figure Omitted from Section 6 Appendix C The Pseudocode for Prefix Searches

Optimal-Time Mapping in Run-Length Compressed PBWT

Paola Bonizzoni ORCID Department of Computer Science, University of Milano-Bicocca, Italy    Davide Cozzi ORCID Department of Computer Science, University of Milano-Bicocca, Italy    Younan Gao ORCID Department of Computer Science, University of Milano-Bicocca, Italy
Abstract

The Positional Burrows–Wheeler Transform (PBWT) is a data structure designed for efficiently representing and querying large collections of sequences, such as haplotype panels in genomics. Forward and backward stepping operations – analogues to LF- and FL-mapping in the traditional BWT – are fundamental to the PBWT, underpinning many algorithms based on the PBWT for haplotype matching and related analyses. Although the run-length encoded variant of the PBWT (also known as the μ-PBWT) achieves O(r~)-word space usage, where r~ is the total number of runs, no data structure supporting both forward and backward stepping in constant time within this space bound was previously known. In this paper, we consider the multi-allelic PBWT that is extended from its original binary form to a general ordered alphabet {0,,σ1}. We first establish bounds on the size r~ and then introduce a new O(r~)-word data structure built over a list of haplotypes {S1,,S0pt}, each of length 0pt, that supports constant-time forward and backward stepping.

We further revisit two key applications – haplotype retrieval and prefix search – leveraging our efficient forward stepping technique. Specifically, we design an O(r~)-word space data structure that supports haplotype retrieval in O(loglogwh+0pt) time. For prefix search, we present an O(0pt+r~)-word data structure that answers queries in O(mloglogwσ+occ) time, where m denotes the length of the longest common prefix returned and occ denotes the number of haplotypes prefixed the longest prefix.

Keywords and phrases:
PBWT, LF-Mapping, prefix searches, run-length encoding
Copyright and License:
[Uncaptioned image] © Paola Bonizzoni, Davide Cozzi, and Younan Gao; licensed under Creative Commons License CC-BY 4.0
2012 ACM Subject Classification:
Theory of computation Data structures design and analysis
Acknowledgements:
The authors would like to thank Travis Gagie for bringing prefix searches to their attention.
Funding:
All authors have received funding from the European Union’s Horizon 2020 research and innovation programme under the Marie Skłodowska-Curie grant agreement PANGAIA No. 872539, as well as from grant MIUR 2022YRB97K (PINC, Pangenome Informatics: From Theory to Applications), funded by the European Union under the NextGenerationEU programme, Mission 4.
Editors:
Philip Bille and Nicola Prezza

1 Introduction

Background and motivation.

The Positional Burrows–Wheeler Transform (PBWT) [5] is a data structure designed for efficiently representing and querying large collections of sequences, such as haplotype panels in genomics. Originally proposed by Durbin [5], the PBWT stores a set of 0pt haplotypes across 0pt variant sites in a 0pt×0pt binary matrix, where the rows at each column j are arranged in co-lexicographic order according to the prefixes of the haplotypes up to column j1. This ordering facilitates efficient querying between a given haplotype and the panel, enabling the identification of set-maximal exact matches (SMEMs).

Two fundamental operations are defined on the PBWT: forward stepping and backward stepping. Forward stepping, denoted by fore[i][j], maps the position of a haplotype in the permutation of the PBWT at site j to its position in the permutation at site j+1, while backward stepping, denoted by back[i][j], performs the inverse mapping, tracing a haplotype’s position at site j+1 back to its position at site j. These operations play an essential role in many PBWT-based algorithms for haplotype matching and analysis.

Although the PBWT enables efficient computations, its memory usage grows rapidly with large haplotype datasets, posing a challenge for population-scale cohorts like the UK Biobank [8]. To address this limitation, the μ-PBWT [4], also discussed in [2], was introduced as a compressed variant of the PBWT that leverages run-length encoding (RLE) to reduce space usage. A run in a sequence is defined as a maximal contiguous block of identical symbols, and the μ-PBWTs storage requirement is O(r~) words, where r~ denotes the total number of runs in the corresponding PBWT across all 0pt sites. This run-length compression reduces the μ-PBWT’s memory usage to only a fraction of that of the original PBWT, making it feasible to index and query massive haplotype panels such as those in the UK Biobank [8].

Beyond space efficiency, the μ-PBWT’s structure has proven particularly useful for downstream applications such as computing matching statistics [4, 3], Minimal Positional Substring Covers (MPSC) [3], and SMEMs [4, 3]. Each of these applications relies on repeated forward and backward stepping operations. However, within the O(r~)-space bound of the μ-PBWT, no data structure supporting both operations in constant time was known prior to our work. Achieving faster stepping operations would directly improve the performance of all these applications and further enhance the efficiency of run-length compressed PBWT indexing for large-scale genomic analyzes.

Related work.

Durbin [5] noted that, due to the co-lexicographic ordering of the PBWT, the forward (resp, backward) stepping operation is the natural analogue of the LF- (resp, FL-) mapping in the classical Burrows–Wheeler Transform (BWT). Gagie et al. [7, Lemma 2.1] presented a data structure requiring O(r) words of space, built over a text of length n, that supports LF- and FL-mappings on the BWT in O(loglogw(n/r)) time, where r is the number of runs in the BWT of the text and w is the number of bits in a machine word. By applying this data structure to each column of the PBWT, we can achieve, for every site j, an O(rj)-word data structure that supports both forward and backward stepping queries in O(loglogw(0pt/rj)) time, where rj denotes the number of runs at site j.

Nishimoto and Tabei [12] recently proposed the move structure to accelerate LF-mapping operations on the BWT. Their approach first divides the r runs in the BWT into at most 2r sub-runs, and then constructs an O(r)-word data structure over these sub-runs. Given a position i in the BWT and the index of the sub-run containing i, the structure can compute LF(i) and determine the index of the sub-run containing LF(i) in constant time.

Typically, in applications of the PBWT, forward and backward stepping are performed iteratively. For example, to traverse a haplotype in the PBWT from site j to site j, the forward stepping procedure is invoked sequentially jj times. However, efficient (e.g., constant-time) forward and backward stepping in the run-length encoded PBWT cannot be achieved simply by applying the move structure independently at each site. Indeed, the move structure only returns the index of the sub-run at site j that contains fore[i][j], whereas continuing the forward step from site j+1 to site j+2 requires the index of the sub-run at site j+1 that contains fore[i][j]. See Figure 1 for an example. Hence, new methods are needed to accelerate fore and back queries while maintaining the run-length encoded PBWT.

(a) The Input haplotypes.
(b) The PBWT with runs.
(c) PA.
Figure 1: Example of PBWT and PA built for bi-allelic haplotypes {S1,S2,S3,S4,S5}. The operation fore[5][4] returns 2, and the position 2 is in the first run of the fifth column of the PBWT.

Two key applications of the back and fore queries on the PBWT are haplotype retrieval and prefix search [6]. In haplotype retrieval, the goal is to extract any haplotype from the PBWT. In prefix search, the objective is to find the longest common prefix P[1..m] between any haplotype and a query pattern P[1..m], and to list the indices of all haplotypes prefixed by P[1..m]. Using the data structure from [7, Lemma 2.1], built over each column of the PBWT, haplotype retrieval can be performed in O(0ptloglogwh) time by invoking forward stepping iteratively 0pt times, with an overall space usage of O(r~) words. Gagie et al. [6] present a textbook solution based on the PBWT that uses O(0pt0pt) words of space and supports each prefix query in O(mlog0pt+occ) time, where occ denotes the number of reported indices. They also provide various time-space tradeoffs in the same work. Nishimoto and Tabei [12] propose a data structure for prefix search that combines a BWT built over all haplotypes, a compact trie [10], the move data structure, and at most 20pt1 marked positions. The structure supports computing the longest prefix P[1..m] in O(m) time, using O(r+0pt) words of space, where r denotes the number of runs in the BWT of the concatenated sequence.

Our results.

We consider the multi-allelic PBWT as described in [11]. We propose a “move data structure”style solution specifically tailored for the PBWT. Our approach introduces a simple yet effective algorithm that partitions the r~ runs of the PBWT into at most 2r~ sub-runs across all 0pt columns of the PBWT (Section 4). We then design an O(r~)-word data structure over the sub-runs (Theorem 13) that supports O(1)-time computation of both forward and backward stepping operations, allowing to be invoked iteratively (Section 5).

As a first application, we present a PBWT-based solution for prefix searches. Specifically, assuming all haplotypes have the same length, we design an O(r~+0pt)-word data structure that finds the longest common prefix P[1..m] between any haplotype and a query pattern P[1..m] in O(mloglogwσ+occ) time. When the haplotypes are sorted lexicographically, we can further reduce the space complexity from O(r~+0pt) to O(r~). Note that the problem setting considered by Nishimoto and Tabei [12] allows haplotypes of varying lengths. We also show that our PBWT-based solution can be adapted to this more general case. While our query time is not as efficient as that of Nishimoto and Tabei [12], our approach has the advantage of not requiring a compact trie. As a second application, we design an O(r~)-word data structure to represent the haplotypes, supporting retrieval of any haplotype Si (1i0pt) in O(loglogw0pt+0pt) time (Theorem 17).

Before introducing our “move”-like O(r~)-word data structure, we complement our results with lower and upper bounds on the measure r~. We establish a connection between r~ and the number 0pt′′ of adjacent haplotype pairs (Si,Si+1) such that SiSi+1. Specifically, we show that r~0pt′′+1 and r~0pt(0pt′′+1).

Paper organization.

In Section 2, we introduce the notation and preliminary results used throughout the paper. In Section 3, we establish lower and upper bounds on the size r~. Section 4 defines the three-overlap constraint over two lists of intervals and presents an algorithm that divides intervals in one list into sub-intervals satisfying this constraint. Applying this algorithm, we describe in Section 5 how to divide PBWT runs into sub-runs for back and fore queries. In Section 6, we design data structures over these sub-runs and develop the corresponding algorithms for back and fore queries. Section 7 discusses two applications of back and fore queries: haplotype retrieval and prefix searches. Finally, Section 8 concludes the paper and outlines directions for future work.

2 Preliminaries

All results in this paper are presented under the word RAM (random-access machine) model. We evaluate the space cost of data structures in words. Each word is of w bits.

Notations.

We denote by [i,j] the interval of integers i,i+1,,j, and define [i,j]= if j<i. Given an interval 𝖨=[i,j], we denote its left and right endpoints by 𝖨.b and 𝖨.e, respectively, so that 𝖨.b=i and 𝖨.e=j. For any matrix A, we denote by colj(A) its j-th column and by colj(A)[i] the entry A[i][j]. Let M be the matrix that stores S1,S2,,S0pt in rows 1,2,,0pt. We note that the input haplotypes might not be pairwise distinct.

Consider an ordered alphabet {0,,σ1} with 0<1<<σ1. A string α over this alphabet is a finite sequence of symbols from {0,,σ1}, that is, α=α[1]α[2]α[|α|], where |α| denotes the length of α, and α[i]{0,,σ1} for all 1i|α|. The empty string is denoted by ε. For indices 1ij|α|, we denote by α[i..j] the substring of α spanning positions i through j (and define α[i..j]=ε if i>j). The string α[1..i] is referred to as the i-th prefix of α, and α[i..|α|] as the i-th suffix, for 1i|α|. A proper prefix (respectively, proper suffix) of α is a prefix (respectively, suffix) β such that βα.

Given two strings α and β over the alphabet set {0,,σ1}, we say that α is lexicographically smaller than β, denoted by αβ, if and only if one of the following holds: i) there exists an index k such that α[i]=β[i] for all i<k, and α[k]<β[k]; ii) or α is a proper prefix of β. We say that α is co-lexicographically smaller than β, denoted by αcolexβ, if and only if one of the following holds: i) There exists an index k such that α[|α|i+1]=β[|β|i+1] for all 1i<k, and α[|α|k+1]<β[|β|k+1]; ii) or α is a proper suffix of β.

Predecessor queries.

Given a sorted list S of integers, a predecessor query takes an integer x as input and returns max{ySyx} and its rightmost position in S.

Lemma 1 ([1, Theorem A.1]).

Given an increasingly sorted list of n integers, drawn from the universe {0,,σ1}, there is a data structure that occupies O(nlogσ) bits of space and answers a predecessor query in O(loglogwσ) time.

Rank and select queries.

Given a sequence A[1..n] over an alphabet {0,,σ1}, the operation rankc(A,j) returns the number of occurrences of c in A[1..j], for c{0,,σ1}. The operation selectc(A,j) returns the position of the j-th occurrence of c in A, for 1jrankc(A,n), and returns n+1 if j>rankc(A,n).

Lemma 2 ([1]).

There exists a data structure of O(n) words built on A[1..n] that supports rank queries in O(loglogwσ) time and select queries in O(1) time.

Positional Burrows–Wheeler Transform (PBWT).

Closely related to the PBWT is the Prefix Array (PA), a matrix that records, for each column, the permutation of haplotype indices induced by the PBWT. Formally, the Prefix Array PA built for the matrix M is an 0pt×0pt matrix, in which col1(PA) is simply the list 1,2,,0pt, and colj(PA), for j>1, stores the permutation of the set {1,,0pt} induced by the co-lexicographic ordering of prefixes of {S1,,S0pt} up to column j1, that is, colj(PA)[i]=k if and only if Sk[1..j1] is ranked i in the co-lexicographic order of S1[1..j1],,S0pt[1..j1].

Let PBWT be the matrix representing the positional BWT of M. Then PBWT is also an 0pt×0pt matrix in which colj(PBWT)[i]=colj(M)[colj(PA)[i]] for all i[1..0pt] and j[1..0pt]. We refer to a maximal substring of identical characters in colj(PBWT) as a run. Throughout the paper, let rj denote the number of runs for colj(PBWT). We define r~ as 1j0ptrj.

Forward and backward stepping on PBWT.

We define fore[i][j], for i[1..0pt] and j[1..0pt), as the (row) index of colj(PA)[i] in colj+1(PA), and back[i][j], for i[1..0pt] and j(1..0pt], as the (row) index of colj(PA)[i] in colj1(PA).

Previously, the operation fore[i][j] could be implemented as follows. Let Cc denote the number of occurrences of symbols c<c in column j of the PBWT, that is, in colj(PBWT). Then, fore[i][j]=Cc+rankc(colj(PBWT),i), where c=colj(PBWT)[i]. The backward stepping operation can be implemented in a symmetric manner.

Proposition 3 states the key properties of fore.

Proposition 3.

(a) If colj(PBWT)[i]=colj(PBWT)[i′′] and i<i′′, then fore[i][j]<fore[i′′][j], and (b) if colj(PBWT)[i]=colj(PBWT)[i+1], then fore[i][j]+1=fore[i+1][j].

Proof.

When constructing the j-th column of PBWT, note that the prefixes of the haplotypes up to column j1 are stably sorted. Therefore, statements (a) and (b) follow directly from this stable ordering.

3 A Lower Bound and an Upper Bound on 𝒓~

In this section, we establish lower and upper bounds on r~ in terms of 0pt′′, where 0pt′′ denotes the number of pairs (Si,Si+1) such that 1i<0pt and SiSi+1.

Lemma 4.

It holds that r~0pt′′+1.

Proof.

Consider any pair (Si,Si+1) such that SiSi+1. Let j′′ denote the length of the longest common prefix between Si and Si+1. Observe that the indices i and i+1 remain consecutive in colj(PA) for all 1jj′′+1. Let τ be the row index such that colj′′+1(PA)[τ]=i. By the observation above, we have colj′′+1(PA)[τ+1]=i+1. Since colj′′+1(PBWT)[τ]colj′′+1(PBWT)[τ+1] by the definition of j′′, there must be a run boundary between rows τ and τ+1 in the (j′′+1)-st column of PBWT. Therefore, each pair (Si,Si+1) with SiSi+1 corresponds to a run boundary in PBWT. The mapping from such a pair to a run boundary at (τ,j′′+1) is injective, since each haplotype index i appears at a unique row τ in PA of any column. This establishes that r~0pt′′+1.

Corollary 5.

r~ is at least the number of distinct haplotypes in {S1,S2,,S0pt}.

Proof.

The statement holds because the number of distinct haplotypes in {S1,S2,,S0pt} is at most 0pt′′+1.

We call an interval [b,e] canonical with respect to column j of the PBWT, for 1j0pt, if [b,e] is the maximal interval such that Scolj(PA)[b]=Scolj(PA)[b+1]==Scolj(PA)[e]. Let j denote the number of canonical intervals with respect to column j for 1j0pt. Lemma 6 describes the relationship between j and rj.

Lemma 6.

It holds that rjj.

Proof.

Consider column j for any 1j0pt. Let [b,e] denote any canonical interval with respect to this column. Observe that colj(PBWT)[b]=colj(PBWT)[b+1]==colj(PBWT)[e]. Hence, [b,e] corresponds to a contiguous block of identical symbols in colj(PBWT), although the block might not be maximal. This implies that rjj.

Lemma 7.

It holds that j0pt′′+1.

Proof.

The proof proceeds by induction on j. Let H be the array consisting of {0pt}{iSiSi+1 and 1i<0pt} in increasing order. It follows that |H|=1+0pt′′.

For the base case j=1, observe that each interval [H[t1]+1,H[t]] for 1t|H| (under the convention H[0]=0) forms a distinct canonical interval with respect to the first column. Since t[H[t1]+1,H[t]]=[1,0pt], we have 1=|H|.

Assume inductively that j10pt′′+1. Let [bj1,ej1] denote any canonical interval with respect to column j1, so we have colj1(PBWT)[bj1]==colj1(PBWT)[ej1]. By Proposition 3(b), the integers fore[bj1][j1],fore[bj1+1][j1],,fore[ej1][j1] are consecutive, forming an interval [fore[bj1][j1],fore[ej1][j1]]. Furthermore, by the definitions of fore and [bj1,ej1], the haplotypes Scolj(PA)[t] for all t[fore[bj1][j1],fore[ej1][j1]] are identical. Thus, this interval is contained within some canonical interval with respect to column j. This containment may be strict whenever multiple canonical intervals with respect to column j1, corresponding to identical haplotype sequences, are mapped to adjacent positions in column j, thereby merging into a single canonical interval with respect to column j. Therefore, each canonical interval with respect to column j1 is mapped by fore to a subinterval of a canonical interval with respect to column j. Since the union of these mapped intervals covers all rows [1,0pt], the number of canonical intervals in column j must be less than or equal to the number in column j1 (jj1). By the induction hypothesis, jj10pt′′+1, completing the proof.

Theorem 8.

It holds that r~0pt(0pt′′+1).

Proof.

By Lemmas 6 and 7, we have rj0pt′′+1 for all j. Therefore, r~=1j0ptrj1j0pt(0pt′′+1)=0pt(0pt′′+1).

4 The Three-Overlap Constraint and a Normalization Algorithm

In this section, we define the three-overlap constraint and present a new algorithm for partitioning runs based on it.

Definition 9 (The Three-Overlap Constraint).

Let Ip={[p1,p1],[p2,p2],,[px,px]} be a collection of x pairwise disjoint intervals that partition the range [1,n], where p1=1, px=n, and pi+1=pi+1 for 1i<x. Similarly, let Iq={[q1,q1],[q2,q2],,[qy,qy]} be a collection of y pairwise disjoint intervals that also partition [1,n], where q1=1, qy=n, and qj+1=qj+1 for 1j<y. We say that Ip satisfies the three-overlap constraint with respect to Iq if every interval in Ip overlaps with at most three intervals in Iq.

Note that the three-overlap constraint differs from the balancing property introduced in the move data structure [12] in two key aspects. Under the balancing property,

  • Ip and Iq are in bijective correspondence – that is, there exists a bijection f() (with inverse f1()) such that for each interval 𝖨Ip (resp., 𝖨Iq), the interval [f(𝖨.b),f(𝖨.e)] belongs to Iq (resp., [f1(𝖨.b),f1(𝖨.e)]Ip), and

  • each interval in Ip contains at most three left endpoints of intervals in Iq; consequently, a single interval in Ip may overlap with up to four distinct intervals from Iq.

Lemma 10.

Let Ip and Iq denote two lists of intervals into which [1,n] is partitioned. There exists an O(|Ip|+|Iq|)-time algorithm that partitions all intervals in Ip into at most (|Ip|+|Iq|2) sub-intervals, satisfying the three-overlap constraint, with respect to Iq.

Proof.

Let x=|Ip| and Ip=[p1,p1],[p2,p2],,[px,px] be x pairwise-disjoint intervals into which [1,n] is partitioned, where p1=1,px=n, and pi+1=pi+1 for 1i<x. Let y=|Iq|. Without loss of generality, assume that y4; otherwise, Ip immediately satisfies the three-overlap constraint. Let Iq=[q1,q1],[q2,q2],,[qy,qy] be y pairwise-disjoint intervals into which [1,n] is partitioned, where q1=1,qy=n, and qj+1=qj+1 for 1j<y.

The algorithm normalization(Ip,Iq) is described as follows. Create a variable k and initiate k to 1. Iterate and process each interval [pi,pi] in Ip from left to right as follows: If [pi,pi] overlaps with at most three intervals of Iq, then skip [pi,pi] and move on to the next interval; otherwise, divide [pi,pi] into two sub-intervals, [pi,dk] and [dk+1,pi], where 1dkn is the largest integer such that [pi,dk] overlaps three intervals of Iq. Then, substitute [pi,pi] for [pi,dk] and [dk+1,pi], increment k by one, and move on to the next interval, that is, [dk+1,pi].

Let I^p denote the list of intervals outputted by the above algorithm. Figure 2 illustrates an example of the algorithm. Clearly, we have |I^p|=x+k and it follows that every interval in I^p overlaps at most three intervals in Iq. It remains to prove that ky2. To this end, we define Λ(I^p[i]) for any 1ix+k to be the set of intervals in Iq, overlapping I^p[i].

Claim 11.

For any 1t1<t2<k, let 𝖨1 (resp. 𝖨2) denote the interval in I^p, of which the right endpoint is dt1 (resp. dt2). We have Λ(𝖨1)Λ(𝖨2)=.

Proof.

Observe that we have dτ{q1,,qy} for any 1τ<k, and thus the integers dτ and dτ+1 are always in different intervals in Iq. Moreover, dt1+1𝖨~ for any 𝖨~Λ(𝖨1), in view of the algorithm.

Assume that there exists an interval 𝖨Λ(𝖨1)Λ(𝖨2). Let z denote the left endpoint of the interval 𝖨2. Then, we have dt1𝖨 and z𝖨. Since dt1<dt1+1z, we have dt1+1𝖨Λ(𝖨1) as well, a contradiction. Hence, the assumption is false.

In view of the algorithm, the interval in I^p ending at dτ for any 1τ<k overlaps exactly three intervals in Iq. In view of Claim 11, we have k1y3; therefore, x+kx+1+y3x+y2, for y4.

Clearly, the algorithm runs in O(|I^p|+|Ip|+|Iq|)O(|Ip|+|Iq|) time.

Figure 2: Example of the normalization algorithm. Given Ip={[1,1],[2,11],[12,16]} and Iq={[1,2],[3,3],[4,5],[6,7],[8,9],[10,10],[11,13],[14,14],[15,16]}, the output is I^p={[1,1],[2,5],[6,10],[11,11],[12,16]}, where each interval of I^p overlaps at most 3 intervals of Iq.

5 Constructing Sub-Runs and Bounding Their Number

In this section, we introduce sub-runs for forward and backward stepping (i.e., fore and back) in the PBWT.

While runs are maximal-length substrings consisting of the same character, we define sub-runs as substrings of the same character without the maximal-length restriction.

We define a run interval with respect to column j (1j0pt) as the maximal interval [b,e] such that all symbols in positions b,b+1,,e of colj(PBWT) are identical. Let intervalsj denote the list of the rj run intervals in column j, sorted in increasing order of their starting positions. Similarly, a sub-run interval is any contiguous subrange contained within a run interval. We abuse notation slightly and use the terms run intervals (resp. sub-run intervals) and runs (resp. sub-runs) interchangeably.

In the following, we define two bijection functions foreL and backL that will be used, respectively, in the construction of two lists SubIBj and SubIFj of sub-runs for each column j. The lists SubIBj and SubIFj are used later to implement back queries and fore queries, respectively. More precisely, foreLj(L) returns the list {[fore[bτ][j],fore[eτ][j]]1τ|L|}, sorted in increasing order by the left endpoint of each interval, for any set of intervals L={[bτ,eτ]1τ|L|,1bτeτ0pt} and any 1j<0pt.

By Proposition 3(b), it follows that fore[i+1][j]fore[i][j]=1 if colj(PBWT)[i]=colj(PBWT)[i+1]. Hence, foreLj(L) is well-defined (i.e., fore[eτ][j]fore[bτ][j] for every 1τ|L|) if each interval in L is a sub-interval of some interval in intervalsj.

Symmetrically, we define backLj(L) to return the list {[back[bτ][j],back[eτ][j]]1τ|L|}, sorted in increasing order by the left endpoint of each interval.

Constructing sub-runs for back queries.

The construction of SubIBj proceeds by induction. In the base case, we set SubIB1=intervals1. For each j from 2 to 0pt, we construct SubIBj as follows: we apply the algorithm normalization(Ip,Iq) (see Lemma 10) with Ip:=intervalsj and Iq:=foreLj1(SubIBj1). Recall that the function foreLj1 maps sub-intervals in column j1 to sub-intervals in column j. The list of sub-intervals output by this algorithm is assigned to SubIBj. See Figure 3 for an illustration of the algorithm and an example.

(a) The scheme of building SubIBj.
(b) An Example of building SubIBj.
Figure 3: Illustration of the algorithm scheme for building sub-runs in SubIBj and an example. In this example, SubIBj1={[1,2],[3,3],[4,5],[6,6],[7,8],[9,11],[12,13],[14,14],[15,16]} and intervalsj={[1,1],[2,11],[12,16]}. The bijective function foreLj1 maps the list SubIBj1 to the list {[1,2],[3,3],[4,5],[6,7],[8,9],[10,10],[11,13],[14,14],[15,16]}. Intervals highlighted in the same color contain the same haplotype indices and indicate corresponding pairs under this bijection. After applying the normalization algorithm to intervalsj and foreLj1(SubIBj1), the intervals in intervalsj are partitioned into SubIBj={[1,1],[2,5],[6,10],[11,11],[12,16]}. Each interval in SubIBj overlaps with at most three intervals in foreLj1(SubIBj1).

In view of the algorithm in Lemma 10, each interval in SubIBj for 1j0pt is a sub-interval of some interval in intervalsj and overlaps at most three intervals in the list foreLj1(SubIBj1). Recall that every interval in intervalsj corresponds to a run in colj(PBWT). Hence, every interval in SubIBj corresponds to a sub-run in colj(PBWT).

Constructing sub-runs for fore queries.

The construction of SubIFj is also performed by induction. In the base case, we set SubIF0pt=intervals0pt. Then, for j from 0pt1 down to 1, we construct SubIFj as follows: we apply the algorithm normalization(Ip,Iq) (see Lemma 10), where Ip=foreLj(intervalsj) and Iq=SubIFj+1. Let SubIFj+1 be the list of intervals output by the algorithm; we then assign SubIFj=backLj+1(SubIFj+1). Figure 6 (in Appendix A) illustrates the construction scheme along with an example.

By the normalization algorithm shown in Lemma 10, each interval in SubIFj+1 for 1j0pt is a sub-interval of some interval in foreLj(intervalsj) and overlaps at most three intervals in SubIFj+1. Recall that every interval in foreLj(intervalsj) corresponds to a run in colj(PBWT). Likewise, every interval in SubIFj+1 corresponds to a sub-run in colj(PBWT). Since SubIFj=backLj+1(SubIFj+1), every interval in SubIFj is a sub-run in colj(PBWT).

Lemma 12.

We have 1j0pt|SubIBj|<2r~ and 1j0pt|SubIFj|<2r~.

Proof.

Observe that |foreLj(SubIBj)|=|SubIBj|. Recall that |intervalsj|=rj is always true. In the base case, we have |SubIB1|=r1. For 1<j0pt, we have the recursion |SubIBj||intervalsj|+|SubIBj1|2rj+|SubIBj1|2, in view of Lemma 10 and the observation above. By solving the recursion, it follows that |SubIBj|=r12j1+r22j2++rj2jj=1τjrτ2jτ. Therefore, we have 1j0pt|SubIBj|1j0pt1τjrτ2jτ<2(r1+r2++r0pt)=2r~. The bound on the total number of |SubIFj| for all j can be computed similarly. This concludes the proof.

6 The Data Structure for Constant-Time fore/back Queries

In this section, we design the data structure constructed over these sub-runs to support fore/back queries and access to entries in the matrix PBWT.

Theorem 13.

There exists a data structure of O(r~) words, constructed over SubIBj and SubIFj for 1j0pt, that supports each of the following operations in constant time – without accessing the original matrix M, its PBWT, or its prefix arrays PA:

  • Given an index i[1..0pt] and the index of the interval in SubIBj that contains i, one can find back[i][j], determine the index of the interval in SubIBj1 containing back[i][j], and retrieve colj(PBWT)[i].

  • Given an index i[1..0pt] and the index of the interval in SubIFj that contains i, one can find fore[i][j], determine the index of the interval in SubIFj+1 containing fore[i][j], and retrieve colj(PBWT)[i].

Proof.

We first describe the data structure for back queries. For each column j of the PBWT, we construct the list SubIBj as described in Section 5 (see Constructing sub-runs for back queries). Observe that each interval in SubIBj overlaps at most three intervals in foreLj1(SubIBj1). Moreover, each interval 𝖨~foreLj1(SubIBj1) corresponds to the interval [back[𝖨~.b][j],back[𝖨~.e][j]] belonging to SubIBj1. For every 1<j0pt and each interval SubIBj[τ] with 1τ|SubIBj|, we store a list Bjτ of quadruples (s~,t~,s,λ), where:

  • [s~,t~] is a distinct interval in foreLj1(SubIBj1) that overlaps SubIBj[τ];

  • s=back[s~][j]; and

  • λ is the index of the interval in SubIBj1 whose left endpoint is s.

Since each SubIBj[τ] overlaps at most three intervals in foreLj1(SubIBj1), the list Bjτ contains at most three tuples. By Lemma 12, j|SubIBj|<2r~, so the total space usage is O(r~) words.

Let x, given in a query, denote the index of the sub-run in SubIBj containing i. To answer a query back[i][j], we search in the list Bjx for the quadruple (s~,t~,s,λ) satisfying i[s~,t~]. Then back[i][j]=is~+s, and λ is the index of the interval in SubIBj1 containing back[i][j]. We return (is~+s,λ) as the result. Since |Bjx|3, each query takes O(1) time. See Figure 4 for an illustration of the data structure and algorithm.

Figure 4: Example illustrating the data structure and algorithm for back queries. The third interval [6,10] in SubIBj overlaps three intervals in foreLj1(SubIBj1): [6,7], [8,9], and [10,10]. These correspond to the first [1,2], seventh [12,13], and eighth [14,14] intervals in SubIBj1, respectively. Thus, the data structureBj3 stores the quadruples {(6,7,1,1),(8,9,12,7),(10,10,14,8)} in the form (s~,t~,s,λ). For a query back[7][j] with index 3, the algorithm finds (s~:6,t~:7,s:1,λ:1) in Bj3 (since 7[6,7]) and returns 7s~+s=2 and λ=1.

Accessing col𝒋(PBWT)[𝒊] from SubIB lists.

We store, for each 1j0pt, an array ValBackj of length |SubIBj|, where each entry ValBackj[τ] is set to colj(PBWT)[SubIBj[τ].b]. This requires O(rj) words per column, and O(r~) words overall. Given the index x of the sub-run containing i in SubIBj, we have colj(PBWT)[i]=ValBackj[x], which can be retrieved in O(1) time.

Data structure for fore queries.

We construct the lists SubIFj for each column j as described in Section 5 (see Constructing sub-runs for fore queries). Each interval 𝖨SubIFj corresponds to [fore[𝖨.b][j],fore[𝖨.e][j]]foreLj(SubIFj), and each interval in foreLj(SubIFj) overlaps at most three intervals in SubIFj+1. For every 1j<0pt and each interval SubIFj[τ], we store a list Fjτ of quintuplets (s,s~,s,t,λ), where:

  • s=SubIFj[τ].b, s~=fore[s][j],

  • [s,t] is an interval in SubIFj+1 that overlaps [fore[SubIFj[τ].b][j],fore[SubIFj[τ].e][j]],

  • λ is the index of [s,t] in SubIFj+1.

Since each such interval, i.e., [fore[SubIFj[τ].b][j],fore[SubIFj[τ].e][j]], overlaps at most three intervals in SubIFj+1, each Fjτ has at most three tuples. By Lemma 12, the total space is again O(r~) words.

Let x denote the index of the sub-run containing i in SubIFj. To answer fore[i][j], we search Fjx for the quintuple (s,s~,s,t,λ) satisfying is+s~[s,t]. Then fore[i][j]=is+s~, and λ is the index of the interval in SubIFj+1 containing fore[i][j]. We return (is+s~,λ) as the result. Since |Fjx|3, each query takes O(1) time. An illustration of the data structure and the algorithm is depicted in Figure 7 (in Appendix B).

Accessing col𝒋(PBWT)[𝒊] from SubIF lists.

Analogously, for each 1j0pt, we store an array ValForej of length |SubIFj|, where ValForej[τ]=colj(PBWT)[SubIFj[τ].b]. This requires O(rj) words per column, and O(r~) words in total. Given the index x of the sub-run containing i in SubIFj, we have colj(PBWT)[i]=ValForej[x], retrievable in O(1) time.

7 Applications

In this section, we present applications that rely on the iterative use of fore/back queries. Section 7.1 introduces a PBWT-based solution to prefix searches, while our method to haplotype retrieval is given in Section 7.2.

Henceforth, set ρj:=|SubIFj| for every 1j0pt. According to Theorem 13, given i,j and x, where 1j0pt, 1xρj, and SubIFj[x].biSubIFj[x].e, we define forePairj(i,x) that returns (i,x) such that i=fore[i][j] and SubIFj+1[x].biSubIFj+1[x].e. In other words, forePairj(i,x) returns fore[i][j] and the index of the sub-interval in SubIFj+1 that contains fore[i][j].

7.1 A PBWT-Based Solution to Prefix Search

We first provide a solution under the assumption that all haplotypes {S1,,S0pt} are of the same length 0pt and then generalize it to the case where haplotypes are of arbitrary length.

Similarly as sa-interval in suffix arrays [9], given a query pattern P[1..m], we define pa-intervalj, with 2jm, as the maximal continuous range of indices in colj(PA) such that P[1..j1] is a prefix of Si for each ipa-intervalj. In particular, pa-interval1 is defined as [1..0pt], corresponding to the empty string P[1..0].

Theorem 14.

There exists an O(r~)-word data structure constructed over an arbitrarily ordered list {S1,,S0pt} of haplotypes of length 0pt over the alphabet {0,,σ1} such that, given a pattern P[1..m], one can compute in O(mloglogwσ) time:

  1. 1.

    the longest common prefix P[1..m] between P[1..m] and any haplotype,

  2. 2.

    the number occ of haplotypes prefixed by P[1..m], and

  3. 3.

    an index i such that Si is prefixed by P[1..m].

If {S1,,S0pt} are lexicographically sorted, then the data structure finds, in O(mloglogwσ) time, the interval [γ..γ] such that Si is prefixed by P[1..m] for every i[γ..γ] and γ=γ+occ1.

In the remainder of this section, we prove Theorem 14.

The data structures.

The construction of the data structure proceeds as follows. We first build the PBWT matrix PBWT and the prefix array matrix PA for the 0pt haplotypes, each consisting of 0pt columns and 0pt rows. Next, we compute the sub-runs SubIFj for all 1j0pt, as described in Section 5. Over these sub-runs, we then construct the O(r~)-space data structure from Theorem 13 to support fore queries efficiently.

We also build the following auxiliary arrays for 1j0pt. Recall that ρj=|SubIFj|.

  • sPAj[1..ρj]: each entry sPAj[τ] (τ[1..ρj]) stores colj(PA)[SubIFj[τ].b];

  • sValj[1..ρj]: each entry sValj[τ] stores colj(PBWT)[SubIFj[τ].b];

  • sCountj[1..ρj]: each entry sCountj[τ] stores the number of occurrences of sValj[τ] in colj(PBWT)[1..SubIFj[τ].b], that is, ranksValj[τ](colj(PBWT),SubIFj[τ].b).

We then build the data structures for rank and select queries over sValj as in Lemma 2. After building these arrays and supporting structures, we discard PBWT and PA.

The structure of Theorem 13 occupies O(r~) words of space. By Lemma 12, we have jρj=O(jrj)=O(r~). Hence, storing all the arrays and auxiliary rank/select structures requires O(jρj)=O(r~) words in total. Consequently, the overall space complexity of our data structure is O(r~) words.

The query algorithm.

The algorithm Partial Prefix Search(P[1..m]) iterates through columns from left to right. At each column j, it updates a state quintuple (b,e,x,x,index) defined as follows:

  • b,e{1,,0pt} represent the interval boundaries pa-intervalj.b and pa-intervalj.e, respectively,

  • x,x{1,,|SubIFj|} are indices such that bSubIFj[x] and eSubIFj[x], respectively, and

  • index{1,,0pt} stores the value colj(PA)[b].

Initially, we set the quintuple as [b,e]=[1,h]=pa-interval1, x=1, x=|SubIF1|, and index=sPA1[1]. In the j-th iteration (1jm), the following steps are performed:

  • We first determine the positions b~ and e~, where bb~e~e denote the indices of the first and last occurrences of P[j] in colj(PBWT) within the range [b,e]. Formally, b~=min{be,colj(PBWT)[]=P[j]} and e~=max{be,colj(PBWT)[]=P[j]}. If neither b~ nor e~ exists, the interval pa-intervalj+1 corresponding to the prefix P[1..j] is empty. Otherwise, we locate the indices x~ and x~ such that b~SubIFj[x~] and e~SubIFj[x~], respectively. In the pseudocode, we show that all of b~, e~, x~, and x~ can be obtained using rank and select queries over the array sValj. In addition, if b~b, we update the variable index:=sPAj[x~]. We will later prove that the variable index always stores colj(PA)[b].

  • Second, if j<m and pa-intervalj+1, we apply the queries forePairj(b~,x~) and forePairj(e~,x~) according to Theorem 13, and update (b,x):=forePairj(b~,x~) and (e,x):=forePairj(e~,x~), respectively. Consequently, for j<m, it follows that b=pa-intervalj+1.b and e=pa-intervalj+1.e. Thus, pa-intervalj+1, corresponding to the prefix P[1..j], is obtained and stored as [b,e], with the values x and x updated accordingly. If j=m, we instead set (b,x):=(b~,x~) and (e,x):=(e~,x~).

  • Third, we increment j by 1 and proceed to the next iteration.

We stop proceeding to the next iteration if pa-intervalj+1= or j=m+1. The following observation is crucial: in either case, the longest common prefix shared by P[1..m] and any haplotype is P[1..j1].

If pa-intervalj+1=, then [b,e] is pa-intervalj, corresponding to the prefix P[1..j1]. If j=1, then the longest common prefix shared by P[1..m] and any haplotype is an empty string. Otherwise, the longest common prefix is P[1..j1] by the observation mentioned earlier, and the number of haplotypes prefixed by P[1..j1] is eb+1 by the definition of pa-intervalj; therefore, we return P[1..j1],eb+1, and index as the answer.

If instead j=m+1, it follows that P[1..m] is the longest common prefix and that b and e store, respectively, the indices of the first and last occurrences of P[m] in colm(PBWT)[b^,e^], where [b^,e^]=pa-intervalm (note that pa-intervalm corresponds to the prefix P[1..m1]). In this case, we compute the numbers of occurrences of P[m] in colm(PBWT)[1..b] and colm(PBWT)[1..e], which are sCountm[x]+bSubIFm[x].b and sCountj[x]+eSubIFj[x].b, respectively, and store them in variables count1 and count2. The number of haplotypes prefixed by P[1..m] is count2count1+1. In the end, we return P[1..m],count2count1+1,index as the answer; recall that the variable index stores colm(PA)[b]. The pseudocode of the algorithm can be found in Appendix C.

We have shown that the procedure Partial Prefix Search(P[1..m]) identifies the longest prefix P[1..m] shared between P[1..m] and any haplotype, and counts the number of haplotypes prefixed by P[1..m]. It remains to show that the variable index returned by the procedure indeed stores the index of one of these haplotypes. To this end, it suffices to prove that the invariant index=colj(PA)[b] holds in each iteration j.

Lemma 15.

It follows that index=colj(PA)[b] in each iteration j with 1jm.

Proof.

We give a proof by induction. When j=1, the procedure sets b:=1 and index:=sPA1[1]. Since colj(PA)[b]=colj(PA)[1]=sPA1[1], we have index=colj(PA)[b]; the base case for j=1 holds trivially.

Assume by induction that at the beginning of the j-th iteration, we have index=colj(PA)[b]. Consider the j-th iteration. Note that in the beginning of this iteration, we have sValj[x]=colj(PBWT)[b], as bSubIFj[x].

If sValj[x]=P[j], then colj(PBWT)[b]=P[j]; in this case, the variable index remains in this iteration, and the variable b is set to fore[b][j]. Note that by the definition of fore queries, we have colj(PA)[b]=colj+1(PA)[fore[b][j]]. By the inductive assumption, we have index=colj(PA)[b], thereby index=colj+1(PA)[fore[b][j]]; therefore, at the beginning of the next iteration, the statement still holds.

Otherwise, we have colj(PBWT)[b]P[j]; in this case, the procedure finds the index b~ of the first occurrence of P[j] in colj(PBWT) within the range [b..e] and the index x~ that satisfies b~=SubIFj[x~].b, and sets index:=sPAj[x~]. Since colj(PA)[b~]=sPAj[x~], we have colj(PA)[b~]=index. If j=m, then the procedure sets b:=b~; therefore, we have colm(PA)[b]=colm(PA)[b~]=sPAm[x~]=index. When the while-loop terminates in the m-th iteration, we have colm(PA)[b]=index. If j<m, then b is set to fore[b~][j]. By the definition of fore queries, we have colj(PA)[b~]=colj+1(PA)[fore[b~][j]]. Recall that colj(PA)[b~]=index, so it follows that index=colj+1(PA)[fore[b~][j]]=colj+1(PA)[b]. Thus, at the beginning of the next iteration, the statement holds, completing the proof.

Moreover, by Proposition 3(a), it follows that the variable index returned by the algorithm stores the smallest index such that S is prefixed by P[1..m]; that is, index=min{10pt and P[1..m] is a prefix of S}.

The running time analysis.

The while-loop in the algorithm performs at most m iterations. Recall that m denotes the length of the longest common prefix to return. So, pa-intervalm+2 does not exist, and at most min(m+1,m) iterations are executed. In each iteration j, the queries rank and select over the array sValj, as well as the query forePair are called at most twice, respectively. By Lemma 2 and Theorem 13, a rank query takes O(loglogwσ) time, a query select or forePairj takes O(1) time. Hence, the overall running time of the algorithm is bounded by O(mloglogwσ).

When {𝑺𝟏,𝑺𝟐,,𝑺𝟎𝒑𝒕} are sorted lexicographically.

In this case, we first invoke the procedure Partial Prefix Search(P[1..m]) to obtain P[1..m], the count occ, and the index i of a haplotype that is prefixed by P[1..m]. We then compute the interval [γ..γ] as [i..i+occ1]. To verify correctness, observe that if S1,S2,,S0pt are presorted lexicographically, then the list {γ,γ+1,,γ1,γ} forms a sub-list of colj(PA) for every 1jmin(m+1,m). Recall that i=min{10pt and P[1..m] is a prefix of S}. Hence, it follows that i=γ and γ=i+occ1.

This completes the proof of Theorem 14. In Corollary 16, we extend this result to enumerate all haplotype indices prefixed by P[1..m].

Corollary 16.

There is an O(r~+0pt)-word data structure built over an arbitrary ordered list {S1,,S0pt} of haplotypes such that, given a pattern P[1..m], the indices of the haplotypes prefixed by P[1..m] can be enumerated in O(mloglogwσ+occ) time, where P[1..m] is the longest common prefix between P[1..m] and any haplotype and occ denotes the number of haplotypes prefixed by P[1..m].

Proof.

We first sort all haplotypes in lexicographic order, build the data structure of Theorem 14 over the sorted list, and store the permutation π1(i) for 1i0pt such that Sπ(1)Sπ(2)Sπ(0pt). The resulting data structure uses O(r~+0pt) words of space.

Given a query pattern P[1..m], Theorem 14 allows us to find the longest common prefix P[1..m] in O(mloglogwσ) time, as well as the interval [γ,γ] such that Sπ(i) for any π(i)[γ,γ] is prefixed by P[1..m]. The number occ of occurrences is then γγ+1, and the original indices, before sorting, of these haplotypes prefixed by P[1..m] are {π1(τ)τ[γ,γ]}. Using the permutation π1 together with the interval [γ,γ], the list of indices can be reported in O(occ) time.

Handling haplotypes of arbitrary lengths.

We consider a general setting where the haplotypes {S1,,S0pt} have arbitrary length. We append a special symbol #{0,,σ1} – assumed to be the smallest – to the end of each haplotype. Next, we construct the PBWT representation PBWT and the prefix arrays PA for the new haplotypes, which consist of 0pt+i[1..0pt]|Si| symbols in total.

The construction of PBWT proceeds column by column from left to right, as in the case of haplotypes of equal length. In this setting, however, both PBWT and the PA are no longer matrices; instead, each consists of 0pt columns of possibly different lengths, denoted by {PBWT1,PBWT2,,PBWT0pt} and {PA1,PA2,,PA0pt}, respectively. Here, 0pt denotes the maximum extended haplotype length among {S1,,S0pt}, that is, 0pt=max{|Si|+11i0pt}. When constructing the entries of PBWTj and PAj, we exclude any haplotype Si such that j>|Si|+1. Figure 5 shows an example of PBWT and PA built for haplotypes of arbitrary length.

(a) Extended haplotypes.
(b) PBWT.
(c) PA.
Figure 5: Example of PBWT and PA built for haplotypes of arbitrary length.

The construction procedure described above ensures that each column PBWTj stores a permutation of all entries Si[j] for every 1i0pt and j|Si|+1. Note that Si[|Si|+1]=#. As a result, the symbol # appears in PBWT exactly 0pt times across all columns. Let r~ denote the total number of runs in PBWT, and let r~ denote the number of runs excluding those composed entirely of #. Since # occurs 0pt times in PBWT, it follows that r~r~+0pt.

Upon the runs of PBWT for the new haplotypes trailing with #, we build the same data structures as we have seen before for constructing sub-runs SubIFj’s, for fore queries, and for prefix searches (Corollary 16). The space cost is bounded by O(r~+0pt) words, and a prefix search query can be answered in O(mloglogw(σ+1)+occ) time, since the new alphabet set is {0,,σ1}{#}. Note that a prefix search query never calls fore[i][j] for any i and j such that PBWTj[i]=#.

7.2 Haplotype Retrieval within 𝑶(𝒓~) Space

Theorem 17.

The list of haplotypes {S1,,S0pt}, each of length 0pt, can be represented in O(r~) words of space, allowing Si with any 1i0pt to be retrieved in O(0pt+loglogw0pt) time.

Proof.

We construct the data structure, denoted by DS, as described in Theorem 13 for supporting fore queries. Let pτ, for 1τ|SubIF1|, be the starting positions of the τ-th sub-run in col1(PBWT). Clearly, these positions p1,p2, are sorted in increasing order. The list consists of exactly r1 positions. We build the data structure from Lemma 1 over the list p1,p2, to support predecessor queries. Since these positions are drawn from the universe {1,,0pt}, each predecessor query can be answered in O(loglogw0pt) time. The data structure requires O(r1+r~)=O(r~) words of space.

Given a query position i, we apply Lemma 1 to find the index x1 of the sub-run that contains i; that is, x1 is the position of the predecessor of i in the list p1,p2,. Using x1, we can retrieve col1(PBWT)[i] and forePair1(i,x1) in constant time via DS. The former gives the entry Si[1], while the latter provides both the position i2 – where i is stored in col2(PA) – and the index x2 of the sub-run in col2(PBWT) that contains i2. With x2 and i2, we can obtain the entry Si[2] and continue in the same manner for the subsequent columns. The algorithm terminates after all 0pt entries of Si have been retrieved.

The predecessor query is invoked once, costing O(loglogw0pt) time by Lemma 1. The forePair query is invoked 0pt times, and exactly 0pt entries of the matrix PBWT are accessed. Thus, the total query time is bounded by O(loglogw0pt+0pt).

8 Conclusions

In this work, we presented new O(r~)-space data structures and algorithms that support efficient forward and backward stepping operations on the PBWT. Our data structure enables constant-time computation of both fore and back operations. We also established lower and upper bounds on r~. To demonstrate the utility of the optimal-time mapping, we revisited two applications: prefix search and haplotype retrieval. For the first application, we proposed an O(r~+0pt)–word data structure that answers each query in O(mloglogwσ) time. When the haplotypes are provided in lexicographic order, the space requirement reduces to O(r~) words. Moreover, our PBWT-based approach to prefix search naturally extends to haplotypes of arbitrary length. For the second application, we designed an O(r~)-word data structure that supports haplotype retrieval in O(0pt+loglogw0pt) time. While this work primarily focuses on the theoretical approach for achieving constant-time mapping in the run-length encoded PBWT, it also opens new directions for practical implementations and other applications, such as accelerating the computation of SMEMs [4] or MPSC in haplotype threading [13, 3]. We leave these aspects for future work.

References

  • [1] Djamal Belazzougui and Gonzalo Navarro. Optimal Lower and Upper Bounds for Representing Sequences. ACM Transactions on Algorithms, 11(4), 2015. doi:10.1145/2629339.
  • [2] Paola Bonizzoni, Christina Boucher, Davide Cozzi, Travis Gagie, Dominik Köppl, and Massimiliano Rossi. Data Structures for SMEM-Finding in the PBWT. In Franco Maria Nardini, Nadia Pisanti, and Rossano Venturini, editors, String Processing and Information Retrieval - 30th International Symposium, SPIRE 2023, Pisa, Italy, September 26-28, 2023, Proceedings, Lecture Notes in Computer Science, pages 89–101. Springer, 2023. doi:10.1007/978-3-031-43980-3_8.
  • [3] Paola Bonizzoni, Christina Boucher, Davide Cozzi, Travis Gagie, and Yuri Pirola. Solving the Minimal Positional Substring Cover Problem in Sublinear Space. In Shunsuke Inenaga and Simon J. Puglisi, editors, 35th Annual Symposium on Combinatorial Pattern Matching (CPM 2024), volume 296 of LIPIcs, pages 12:1–12:16, Dagstuhl, Germany, 2024. Schloss Dagstuhl – Leibniz-Zentrum für Informatik. doi:10.4230/LIPIcs.CPM.2024.12.
  • [4] Davide Cozzi, Massimiliano Rossi, Simone Rubinacci, Travis Gagie, Dominik Köppl, Christina Boucher, and Paola Bonizzoni. μ- PBWT: a lightweight r-indexing of the PBWT for storing and querying UK Biobank data. Bioinform., 39(9), 2023. doi:10.1093/BIOINFORMATICS/BTAD552.
  • [5] Richard Durbin. Efficient haplotype matching and storage using the positional Burrows-Wheeler transform (PBWT). Bioinform., 30(9):1266–1272, 2014. doi:10.1093/BIOINFORMATICS/BTU014.
  • [6] Travis Gagie, Giovanni Manzini, and Marinella Sciortino. Teaching the Burrows-Wheeler Transform via the Positional Burrows-Wheeler Transform. CoRR, abs/2208.09840, 2022. doi:10.48550/arXiv.2208.09840.
  • [7] Travis Gagie, Gonzalo Navarro, and Nicola Prezza. Fully Functional Suffix Trees and Optimal Text Searching in BWT-Runs Bounded Space. Journal of the ACM, 67(1):2:1–2:54, 2020. doi:10.1145/3375890.
  • [8] Bjarni V Halldorsson, Hannes P Eggertsson, Kristjan HS Moore, Hannes Hauswedell, Ogmundur Eiriksson, Magnus O Ulfarsson, Gunnar Palsson, Marteinn T Hardarson, Asmundur Oddsson, Brynjar O Jensson, et al. The sequences of 150,119 genomes in the UK Biobank. Nature, pages 1–9, 2022. doi:10.1038/s41586-022-04965-x.
  • [9] Udi Manber and Eugene W. Myers. Suffix Arrays: A New Method for On-Line String Searches. SIAM J. Comput., 22(5):935–948, 1993. doi:10.1137/0222058.
  • [10] Donald R. Morrison. PATRICIA - Practical Algorithm To Retrieve Information Coded in Alphanumeric. Journal of the ACM, 15(4):514–534, 1968. doi:10.1145/321479.321481.
  • [11] Ardalan Naseri, Degui Zhi, and Shaojie Zhang. Multi-allelic positional Burrows-Wheeler transform. BMC Bioinform., 20-S(11):279:1–279:8, 2019. doi:10.1186/S12859-019-2821-6.
  • [12] Takaaki Nishimoto and Yasuo Tabei. Optimal-Time Queries on BWT-Runs Compressed Indexes. In Nikhil Bansal, Emanuela Merelli, and James Worrell, editors, 48th International Colloquium on Automata, Languages, and Programming, ICALP 2021, Glasgow, Scotland (Virtual Conference), July 12-16, 2021, LIPIcs, pages 101:1–101:15. Schloss Dagstuhl – Leibniz-Zentrum für Informatik, 2021. doi:10.4230/LIPIcs.ICALP.2021.101.
  • [13] Ahsan Sanaullah, Degui Zhi, and Shaoije Zhang. Haplotype Threading Using the Positional Burrows-Wheeler Transform. In Christina Boucher and Sven Rahmann, editors, 22nd International Workshop on Algorithms in Bioinformatics, WABI 2022, Potsdam, Germany, September 5-7, 2022, LIPIcs, pages 4:1–4:14. Schloss Dagstuhl – Leibniz-Zentrum für Informatik, 2022. doi:10.4230/LIPIcs.WABI.2022.4.

Appendix A The Figure Omitted from Section 5

(a) The scheme of building SubIFj.
(b) An Example of building SubIFj.
Figure 6: Illustration of the algorithm scheme for building sub-runs in SubIFj and an example. In this example, SubIFj+1={[1,2],[3,3],[4,5],[6,7],[8,9],[10,10],[11,13],[14,14],[15,16]} and intervalsj={[1,5],[6,6],[7,16]}. The bijective function foreLj maps the list intervalsj to the list {[1,1],[2,11],[12,16]}. Intervals highlighted in the same color contain the same haplotype indices and indicate corresponding pairs under this bijection. After applying the normalization algorithm to foreLj(intervalsj) and SubIFj+1, the intervals in foreLj(intervalsj) are partitioned into SubIFj={[1,1],[2,5],[6,10],[11,11],[12,16]}. Each interval in SubIFj+1 overlaps with at most three intervals in SubIFj+1. Finally, by setting SubIFj=backLj+1(SubIFj+1), the intervals intervalsj are partitioned into SubIFj={[1,5],[6,6],[7,10],[11,15],[16,16]}.

Appendix B The Figure Omitted from Section 6

Figure 7: Example illustrating the data structure and algorithm for fore queries. The fourth interval [11,15] in SubIFj corresponds to the third interval [6,10] in foreLj(SubIFj), which overlaps three intervals in SubIFj+1: the fourth [6,7], the fifth [8,9], and the sixth [10,10]. Accordingly, the data structure Fj4 built for the interval [11,15] stores the quintuples {(11,6,6,7,4),(11,6,8,9,5),(11,6,10,10,6)} in the form (s,s~,s,t,λ). Given a query fore[14][j] with index 4, the algorithm finds the tuple (s=11,s~=6,s=8,t=9,λ=5) in Fj4 (since 14s+s~=1411+6=9[8,9]) and returns 14s+s~=9 and λ=5 as the answer.

Appendix C The Pseudocode for Prefix Searches

Partial Prefix Search(P[1..m])
01.     (b,e,x,x,index)(1,0pt,1,|SubIF1|,sPA1[1]);
02.     j1;
03.     while jm do
04.        cP[j];
05.        (b~,x~)(b,x);
06.        if sValj[x]c then
07.          countrankc(sValj,x);
08.          x~selectc(sValj,count+1);
09.          if x~=|SubIFj|+1 then
10.             break;
11.          b~SubIFj[x~].b;
12.          indexsPAj[x~];
13.        (e~,x~)(e,x);
14.        if sValj[x]c then
15.          countrankc(sValj,x);
16.          x~selectc(sValj,count);
17.          e~SubIFj[x].e;
18.        if j<m then
19.          (b,x)forePairj(b~,x~);
20.          (e,x)forePairj(e~,x~);
21.        else
22.          (b,x)(b~,x~);
23.          (e,x)(e~,x~);
24.        jj+1;
25.     if j=1 then
26.        return the longest common prefix is empty;
27.     else if 1<jm
28.        return P[1..j1],eb+1,index;
29.     else
30.        count1sCountm[x]+bSubIFm[x].b;
31.        count2sCountm[x]+eSubIFm[x].b;
32.        countcount2count1+1;
33.        return P[1..m],count,index;