Abstract 1 Introduction 2 Notation and preliminaries 3 Computational complexity of counting π’Œ-mers in graphs 4 Algorithms for π’Œ-mer counting in deterministic Wheeler graphs 5 π’Œ-mer preserving graph transformations to Wheeler graphs 6 The de Bruijn Graph of a Deterministic Wheeler Graph 7 Conclusion References Appendix A Proof of Lemmas 6 and 8 Appendix B Details of the 𝑢⁒(π’πŸ’β’π₯π¨π β‘π’Œ) algorithm Appendix C Computing intervals and left-extensions

Computing k-mers in Graphs

Jarno N. Alanko ORCID Department of Computer Science, University of Helsinki, Finland    MΓ‘ximo PΓ©rez-LΓ³pez ORCID Department of Computer Science, Technical University of Denmark, Lyngby, Denmark
Abstract

We initiate the study of computational problems on k-mers (strings of length k) in labeled graphs. As a starting point, we consider the problem of counting the number of distinct k-mers found on the walks of a graph. We establish that this is #P-hard, even on connected deterministic DAGs. However, in the class of deterministic Wheeler graphs (Gagie, Manzini, and Sirén, TCS 2017), we show that distinct k-mers of such a graph W=(V,E) can be counted using O⁒(|W|⁒k) or O⁒(n4⁒log⁑k) arithmetic operations, where n=|V|, m=|E| and |W|=n+m. The latter result uses a new generalization of the technique of prefix doubling to Wheeler graphs. To generalize our results beyond Wheeler graphs, we discuss ways to transform a graph into a Wheeler graph in a manner that preserves the k-mers.

As an application of our k-mer counting algorithms, we construct a representation of the de Bruijn graph of the k-mers that occupies O⁒(nk+|W|⁒k⁒log⁑(max1≀ℓ≀k⁑nβ„“)+σ⁒log⁑m) bits of space, where nβ„“ is the number of distinct β„“-mers in the Wheeler graph, and Οƒ is the size of the alphabet. We show how to construct it in the same time complexity. Given that the Wheeler graph can be exponentially smaller than the de Bruijn graph, for large k this provides a theoretical improvement over previous de Bruijn graph construction methods from graphs, which must spend Ω⁒(k) time per k-mer in the graph.

Keywords and phrases:
Wheeler graph, Wheeler language, de Bruijn graph, graph, k-mer, q-gram, DFA, #P-hard
Funding:
Jarno N. Alanko: Supported by the Academy of Finland grant 339070.
MΓ‘ximo PΓ©rez-LΓ³pez: Supported by Danish Research Council grant 10.46540/3105-00302B.
Copyright and License:
[Uncaptioned image] © Jarno N. Alanko and MΓ‘ximo PΓ©rez-LΓ³pez; licensed under Creative Commons License CC-BY 4.0
2012 ACM Subject Classification:
Theory of computation β†’ Graph algorithms analysis
; Theory of computation β†’ Pattern matching
Related Version:
Previous Version: https://arxiv.org/abs/2509.22885
Acknowledgements:
We thank Simon J. Puglisi for helpful discussions and feedback.
Editors:
Philip Bille and Nicola Prezza

1 Introduction

In recent years, a sizeable body of literature in the field of computational biology has emerged on storing and indexing sets of k-mers (strings of length k). Typically, these k-mers are all the overlapping windows of length k in some genome sequence. In strings, the problem of counting the number of distinct k-mers is easily solvable in linear time using a combination of suffix and LCP arrays [18, 16], which are computable in O⁒(n) time for polynomial alphabets [15]. There exist highly optimized practical tools for counting short k-mers on strings and encoding them efficiently by exploiting this overlap structure [19].

However, a significant effort is underway to move from linear reference genomes into a more rich graph-based reference genome that encodes all variation in a species. Very little attention has been paid to the problem of counting k-mers in more general structures such as trees, DAGs and general graphs, some of which can encode an exponential number of distinct k-mers. There is some practical work toward this direction in the field of pangenomics [20], but the theoretical limits and possibilities remain largely unexplored. In this paper, we take the first steps towards mapping this uncharted territory.

First, we show that it is #P-hard to compute the number of distinct k-mers in directed labeled graphs, even if we restrict ourselves to connected deterministic graphs without directed cycles. However, we find that in the special case of deterministic Wheeler graphs [10], we can compute the number of k-mers in O⁒(|W|⁒k) time, where |W| denotes the total number of vertices and edges of W, with a simple dynamic programming approach. Pushing further, we study what it takes to improve the time complexity with respect to k. Here, the problem turns out to be significantly more complicated than on strings, but we manage an O⁒(n4⁒log⁑k) algorithm by generalizing the technique of prefix doubling [18] to Wheeler graphs. We believe there is room to improve the O⁒(n4) factor. These results pave the way toward counting k-mers in arbitrary graphs without explicit enumeration, by reducing them to Wheeler graphs that preserve the k-mer set.

As an application of k-mer counting, we present an algorithm that builds the node-centric de Bruijn graph of the k-mers of a Wheeler graph W in O⁒(nk+|W|⁒k⁒log⁑(max1≀ℓ≀k⁑nβ„“)+σ⁒log⁑m) time, where nβ„“ is the number of β„“-mers in W. Crucially, the multiplicative factor of k is on the size of the Wheeler graph, rather than the size of the potentially exponential de Bruijn graph (which contains one node per k-mer). Previous algorithms to build de Bruijn graphs from graphs or sets of k-mers spend Ω⁒(k) time per k-mer inserted in the graph, which inevitably incurs a cost of O⁒(k⁒nk). In the bioinformatics literature, we find the GCSA2 construction algorithm [20], which builds the de Bruijn graph of a graph by building all distinct k-mers of the graph by prefix doubling. Other de Bruijn graph construction algorithms, such as dynamic versions of the data structure by Bowe et al. [5, 4], do not take a graph as input, and only allow the insertion of an explicit k-mer at a time, at a worst-case cost of Ω⁒(k) per insertion. This application showcases how our theoretical results translate into practical gains for graph algorithms.

The remainder of this paper is organized as follows. In Section 2, we lay down some basic notation and concepts. In Section 3, we discuss the computational complexity of the problem, and prove the problem to be #P-hard. In Section 4, we solve the problem on Wheeler graphs in time O⁒(|W|⁒k) or O⁒(n4⁒log⁑k). In Section 5, we discuss ways of turning an arbitrary graph into a Wheeler graph with the same k-mers in order to apply the algorithms in Section 4. Section 6 describes the de Bruijn graph construction algorithm. Section 7 concludes the paper with some closing remarks.

2 Notation and preliminaries

We consider directed graphs with single character labels on the edges. Formally, we consider graphs G formed by a vertex set V⁒(G) and an edge set E⁒(G)βŠ†VΓ—VΓ—Ξ£, where Ξ£ is an alphabet of symbols that is totally ordered by a relation β‰Ί. The indegree and outdegree of a node v are denoted with 𝗂𝗇𝖽𝖾𝗀⁒(v) and π—ˆπ—Žπ—π–½π–Ύπ—€β’(v), respectively. A k-mer Ξ± is a string of length k from Ξ£k, indexed from 1 to k. We compare strings by extending β‰Ί to Ξ£βˆ— co-lexicographically, which is the right-to-left lexicographical order (we abbreviate this by colex order). We say that a labeled graph G contains a k-mer Ξ± if there exists a walk v0,v1,…,vk in G such that (viβˆ’1,vi,α⁒[i])∈E⁒(G) for all 1≀i≀k. In this case, we say that Ξ± reaches vk, and write α↝vk. The minimum and maximum k-mer that reach a vertex v are denoted minvk and maxvk, respectively. A Wheeler graph is a labeled directed graph with the following properties [10]:

Definition 1.

A labeled directed graph G is a Wheeler graph if there is an ordering on the nodes such that nodes with no incoming edges precede those with positive indegree, and every pair of edges (u,v,a),(uβ€²,vβ€²,aβ€²) of the state graph satisfies the following two properties:

  • β– 

    W1: a≺a′⇒v<v′

  • β– 

    W2: (a=aβ€²βˆ§u<uβ€²)β‡’v≀vβ€²

We say that a graph is deterministic if no two outgoing edges from the same vertex have the same label. In deterministic Wheeler graphs, we have the following stronger property:

Lemma 2.

In deterministic Wheeler graphs, for any pair of edges, (u,v,a),(uβ€²,vβ€²,aβ€²) we have (a=aβ€²βˆ§v<vβ€²)β‡’u<uβ€².

There exists an algorithm to transform a non-deterministic Wheeler graph into a deterministic one with the same k-mers, that in the worst case is only a linear factor larger [2]. In contrast, in general graphs the deterministic version could be exponentially larger. However, the running time of the algorithm is O⁒(n3) [2], and improving this upper bound is an open problem. Thus, we assume that our input are deterministic graphs throughout the paper.

In a labeled graph we can identify the incoming infimum and supremum strings to every vertex, denoted infv and supv for all v∈V. We use the definition of [3], though note that they read the strings backwards, and use lexicographical order, while we read the strings forward and use colex order instead. Let Ξ³1,Ξ³2,…,Ξ³2⁒n be the colexicographically sorted infimum and supremum strings of the n vertices of a Wheeler graph. The longest common suffix array is defined as an array 𝖫𝖒𝖲⁒[2..2⁒n], where 𝖫𝖒𝖲⁒[i] is the longest common suffix of Ξ³iβˆ’1 and Ξ³i. It was first defined in [7], where it was also proven that in a deterministic Wheeler graph, infvβͺ―supv, and supuβͺ―infv for all u<v in Wheeler order. Observe that we can find the 𝖫𝖒𝖲 value between any infima and suprema in O⁒(1) time, by building a range minimum query data structure [9, 13] over the 𝖫𝖒𝖲 array, and performing the appropriate query.

We find it convenient to divide the 𝖫𝖒𝖲 array into two parts: one is the external 𝖫𝖒𝖲 array, written 𝖀𝖫𝖒𝖲, that holds the 𝖫𝖒𝖲 between the supremum and infimum string of viβˆ’1 and vi. The other one is the internal 𝖫𝖒𝖲 array, written 𝖨𝖫𝖒𝖲, that holds the 𝖫𝖒𝖲 value of the infimum and supremum of the same vertex. We compute them as 𝖀𝖫𝖒𝖲⁒(viβˆ’1,vi)=𝖫𝖒𝖲⁒[2⁒iβˆ’1], and 𝖨𝖫𝖒𝖲⁒(vi)=𝖫𝖒𝖲⁒[2⁒i]. In Section 4 we show how to use these arrays in the context of k-mers.

Model of computation.

Since the number of k-mers in a graph may be exponential, the time complexity of integer addition and multiplication of large integers can become relevant for the running time of our algorithms. We put this issue to the side by assuming a Word RAM model [12] with a word size large enough to hold the maximum numbers that we handle, which are proportional to the maximum number of β„“-mers in the graph, for any 1≀ℓ≀k.

3 Computational complexity of counting π’Œ-mers in graphs

Refer to caption
Figure 1: Reduction from the example DNF formula F=(x1∧x3)∨(Β¬x1∧x2)∨(Β¬x1∧¬x3), to counting 3-mers. Note how d1=1,d2=0,d3=1 and thus #⁒S⁒A⁒T⁒(F)=10βˆ’21βˆ’20βˆ’21=5.

In this section we show that the k-mer counting problem on graphs is #P-hard even when the graph is acyclic, connected (i.e., there exists a node from which every other node can be reached) and deterministic (i.e., no two edges with the same label have the same origin).

Let #⁒S⁒A⁒T⁒(F) denote the number of satisfying assignments to a boolean formula F over n variables x1,…,xn in conjunctive normal form. Computing #⁒S⁒A⁒T⁒(F) is the archetypical #⁒P-complete problem [21]. It is also well known that the problem is #⁒P-complete in disjunctive normal form since we can write the number of solutions to a CNF formula F as 2nβˆ’#⁒S⁒A⁒T⁒(Β¬F), where Β¬F can be written in disjunctive normal form of the same size as F by de Morgan’s laws.

Theorem 3.

Counting the number of distinct k-mers on walks on an acyclic deterministic connected graph G is #P-hard.

Proof.

We reduce from counting satisfying assignments of a DNF formula. Let n be the number of distinct variables in the formula. For each clause, we introduce a graph gadget. The gadget for clause Cj is as follows: add one node vi for each i=0,…,n, and edges (viβˆ’1,vi,c), for all variables xi that appear in Cj, such that the label c is 1 if xi appears as positive in Cj, otherwise 0. For variables xi that do not appear in Cj, we add both edges (viβˆ’1,vi,0) and (viβˆ’1,vi,1). Now each distinct n-mer in this gadget corresponds to a satisfying truth assignment to the clause, such that the i-th character of the n-mer is 1 iff variable xi is set to true. Let G be the union of all the gadgets for all clauses in the input. Now, the number of distinct n-mers in G is equal to the number of satisfying truth assignments. To make the graph connected, we add a new source node that has an edge to the sources of each of the gadgets, with a unique label #j for each gadget Cj. See Figure 1. Let us denote the modified graph with G#. The addition of the new source node adds 2dj distinct n-mers ending in the gadget for Cj, where dj is the number of nodes with two outgoing edges among the first (nβˆ’1) nodes of the gadget. Thus, if the number of n-mers in G# is N, and the number of clauses is m, then the number of satisfying assignments to the DNF formula is Nβˆ’βˆ‘j=1m2dj. β—€ It is #⁒P-hard even to count the number of k-mers arriving at a single node:

Corollary 4.

Counting the number of k-mers arriving at a single node v in a graph G is #P-hard.

Proof.

If there were an efficient algorithm to count the k-mers coming into a single node v, then we could add a new sink state to any graph, with edges labeled with a unique symbol # pointing to the sink: now the number of (k+1)-mers ending at the sink equals the number of k-mers in the original graph. β—€ Theorem 3 also implies that counting factors of length k in a regular language defined by a DFA is #P-hard:

Corollary 5.

Counting factors of length k in the language of a DFA is #P-hard.

Proof.

We can turn a connected deterministic graph G into a DFA by picking a node that can reach all states as the initial state, and making every state accepting. Now counting factors of length k in the language of the automaton counts k-mers in the graph. β—€

4 Algorithms for π’Œ-mer counting in deterministic Wheeler graphs

In this section, we develop two polynomial-time algorithms for counting k-mers on deterministic Wheeler graphs. We abbreviate those by DWGs. Let W=(V,E) be a DWG, with |V|=n, |E|=m and |W|=n+m. The first algorithm has time complexity O⁒(|W|⁒k). For the second algorithm, we reduce the dependency on k, but we end up with a time complexity of O⁒(n4⁒log⁑k).

These algorithms require, as an internal step, to obtain the LCS array up to a length of k, i.e. min⁑{𝖫𝖒𝖲⁒(Ξ³i,Ξ³i+1),k} for all values in the array. The current known LCS construction algorithms take O⁒(n⁒log⁑σ+min⁑{m⁒log⁑n,m+n2}) time on general deterministic graphs [3], and O⁒(n⁒log⁑σ+m) if the graph is a Wheeler semi-DFA, which requires to have exactly one source. We do not make the assumption of a single source, thus we can only use the former algorithm, which is within the time bound for our O⁒(n4⁒log⁑k) counting algorithm. For our O⁒(|W|⁒k) counting algorithm, we present a tailored LCS construction that is constructed during the k-mer counting algorithm at no extra cost, but with values capped to k, which is enough for our purposes.

4.1 Counting π’Œ-mers in 𝑢⁒(|𝑾|β’π’Œ) time

Let Svk be the set of distinct k-mers reaching a vertex v. The algorithm relies on two properties of deterministic Wheeler graphs. First, the incoming edges to a node all have the same label (a direct consequence of the first condition in Definition 1), a property called input-consistency. We denote with λ⁒(v) the label on the incoming edges to v, setting λ⁒(s)=Ρ for any source s. Second, we have the following well-known property on the colexicographic order of incoming k-mers, which we prove in appendix A:

Lemma 6.

For two nodes u,v in a DWG, if u<v, then for any two k-mers Ξ± and Ξ² such that α↝u and β↝v, we have Ξ±βͺ―Ξ².

Corollary 7.

If two different nodes u<v of the DWG share a k-mer, then they share maxuk=minvk.

If the DWG has sources, some vertices may not have incoming k-mers, but they always have an infimum and a supremum string, as defined in [3]. We also prove that, if two vertices u<v share a k-mer, then maxuk and minvk are suffixes of supu and infv, respectively. If they do not share a k-mer, that may not hold in general. This makes it possible to check for shared k-mers using the original LCS array.

Lemma 8.

Two different nodes u<v of a DWG share a k-mer if and only if𝖫𝖒𝖲⁒(supu,infv)β‰₯k. In that case, maxuk is a suffix of supu, and minvk is a suffix of infv.

We leave the proof in appendix A. Now, we show a recurrence to build the sets Svβ„“ for all β„“=1,…,k. Let pred⁒(v) be the set of nodes that have an outgoing edge to v. Then, for a non-source vertex, we have

Svβ„“=⋃u∈pred⁒(v){α⋅λ⁒(v)∣α∈Suβ„“βˆ’1}, (1)

with the base case Sv0={Ξ΅} for all v∈V, where Ξ΅ denotes the empty string. For sources, Svβ„“=βˆ… for β„“>0.

However, at this point, we are not interested in enumerating the distinct β„“-mers, only counting them. Let Cℓ⁒(v)=|Svβ„“|. Let u1,…,ud be the in-neighbours of v sorted in the Wheeler order. For β„“=0, we have Cℓ⁒(v)=1 for all v. Then, for β„“>0, sources have Cℓ⁒(s)=0; and for non-source vertices, the size of the union in Equation 1 can be written as:

Cℓ⁒(v)=βˆ‘i=1dCβ„“βˆ’1⁒(ui)βˆ’βˆ‘i=2d|Suiβˆ’1β„“βˆ’1∩Suiβ„“βˆ’1|=βˆ‘i=1dCβ„“βˆ’1⁒(ui)βˆ’βˆ‘i=2d[max⁑Suiβˆ’1β„“βˆ’1=min⁑Suiβ„“βˆ’1],

where [P] is the Iverson bracket that evaluates to 1 if the predicate P is true, otherwise to 0. The last equality holds thanks to Corollary 7. Now the only difficult part in computing the recurrence is determining whether max⁑Suiβˆ’1β„“βˆ’1=min⁑Suiβ„“βˆ’1. As discussed before, if we have the LCS array available, by Lemma 8, we can directly check it in the array. Otherwise, there exists a quickly computable recurrence for that as well. Let β„“β‰₯1. For non-source nodes u,v, let π—Œπ—π–Ίπ—‹π–Ύβ„“β’(u,v)=[max⁑Suβ„“=min⁑Svβ„“], and let π—Œπ—π–Ίπ—‹π–Ύβ„“β’(u,v)=0 if u or v are sources. Furthermore, for non-source v define

𝖨𝖫𝖒𝖲β‰₯ℓ⁒(v)=[|infv|β‰₯β„“]β‹…[|supv|β‰₯β„“]β‹…[min⁑Svβ„“=max⁑Svβ„“],

and 𝖨𝖫𝖒𝖲β‰₯ℓ⁒(s)=0 for a source s. We have that π—Œπ—π–Ίπ—‹π–Ύβ„“β’(u,v)=1 iff λ⁒(u)=λ⁒(v) and π—Œπ—π–Ίπ—‹π–Ύβ„“βˆ’1⁒(max⁑pred⁒(u),min⁑pred⁒(v))=1, with the base case π—Œπ—π–Ίπ—‹π–Ύ0⁒(u,v)=1 for all u,v. Similarly, we also have that 𝖨𝖫𝖒𝖲β‰₯ℓ⁒(v)=1 iff 𝖨𝖫𝖒𝖲β‰₯β„“βˆ’1⁒(min⁑pred⁒(v))=1, 𝖨𝖫𝖒𝖲β‰₯β„“βˆ’1⁒(max⁑pred⁒(v))=1 and π—Œπ—π–Ίπ—‹π–Ύβ„“βˆ’1⁒(min⁑pred⁒(v),max⁑pred⁒(v))=1, with the base case 𝖨𝖫𝖒𝖲β‰₯0⁒(v)=1 for all v. To compute these without tabulating all O⁒(|V|2) input pairs u,v to π—Œπ—π–Ίπ—‹π–Ύβ„“, we exploit the formula

π—Œπ—π–Ίπ—‹π–Ύβ„“β’(u,v)=min⁑{minu<w≀vβ‘π—Œπ—π–Ίπ—‹π–Ύβ„“β’(wβˆ’1,w),minu<w<v⁑𝖨𝖫𝖒𝖲β‰₯ℓ⁒(w)}. (2)

With this, it suffices to compute π—Œπ—π–Ίπ—‹π–Ύβ„“ only for adjacent inputs (viβˆ’1,v), and build a range minimum data structure [9, 13] over both the 𝖨𝖫𝖒𝖲β‰₯ℓ⁒(v) and π—Œπ—π–Ίπ—‹π–Ύβ„“β’(viβˆ’1,vi) arrays, to be able to resolve π—Œπ—π–Ίπ—‹π–Ύβ„“β’(u,v) in constant time for any input pair. Proceeding level by level β„“=1,2,…,k, we obtain:

Theorem 9.

We can compute the number of distinct k-mers in the state graph (V,E) of a DWG in total time O⁒((|V|+|E|)⁒k)=O⁒(|W|⁒k).

Note that during the procedure to compute π—Œπ—π–Ίπ—‹π–Ύβ„“ and 𝖨𝖫𝖒𝖲β‰₯β„“ for all β„“, we can also infer the values of the 𝖨𝖫𝖒𝖲 and 𝖀𝖫𝖒𝖲 array up to k, and keep all needed information in O⁒(n) space.

4.2 Counting π’Œ-mers in 𝑢⁒(π’πŸ’β’π₯π¨π β‘π’Œ) time in DWGs

Now, we present a new algorithm for k-mer counting that has a logarithmic dependency on k, based on the technique of prefix-doubling [18]. We obtain a running time of O⁒(n4⁒log⁑k), which is better than our previous algorithm for k=ω⁒(n2⁒log⁑n). We suspect that the upper bound could be improved, but we were not able to. We give now an intuition for the difficulty of this problem.

Our starting point is the algorithm by Kim, Olivares and Prezza [17], that computes the total order of the infima of every vertex by prefix doubling. Let s⁒u⁒fℓ⁒(infv) denote the suffix of length β„“ of infv. For every vertex v and β„“=2i with i=1,…,log⁑k, their algorithm maintains a set Pℓ⁒(v) of the vertices u such that s⁒u⁒fℓ⁒(infv) starts at u and ends at v. Then, it computes P2⁒ℓ⁒(v) as the union of the Pℓ⁒(u) such that u∈Pℓ⁒(v), and u has the smallest s⁒u⁒fℓ⁒(infu) among all u∈Pℓ⁒(v). It observes that the mentioned union is disjoint because of determinism, and thus computing P2⁒ℓ⁒(v) from Pℓ⁒(v) takes O⁒(n) time. Across all vertices and lengths up to k, the running time is O⁒(n2⁒log⁑k), given that a sorting step is done by radix sort in linear time.

Our problem is significantly more complicated since we are interested not only in the infima, but all the strings reaching a node. We assume that we already have a total order on the nodes, but the problem remains challenging. First, we decompose the problem into computing C⁒(v) for each v∈V. From these, it is easy to obtain the k-mer count of the whole graph because adjacent nodes in the Wheeler order share are most one k-mer, which we can detect using the 𝖨𝖫𝖒𝖲 array like in the previous section. Further, we decompose computing Ck⁒(v) into counts Ck⁒(u,v) for all u∈V, where Ck⁒(u,v) denotes the number of k-mers starting from u and ending at v. The counts Ck⁒(u,v) also turn out easy to compute by squaring the adjacency matrix repeatedly, but for Ck⁒(v) we must be very careful to avoid double counting between the Ck⁒(u,v) of different starting nodes u. Let Sk⁒(u,v) denote the k-mers starting from u and ending at v. We have Ck⁒(v)=|⋃u∈VSk⁒(u,v)|. This reduces the problem into computing sizes of unions of the sets Sk⁒(u,v), or computing their intersections to subtract double counting. This is where the core difficulty lies because despite sharing the end point v, the shape of the intersection Sk⁒(u,v)∩Sk⁒(w,v) can be complicated and arbitrarily large.

Therefore, we devise a novel recursive method to compute unions of Sℓ⁒(u,v) for ranges of u. Define Tℓ⁒([ui,uj],v) as |⋃w∈[ui,uj]Sℓ⁒(w,v)| for any interval of vertices [ui,uj] and any v. If all the (β„“/2)-mers reaching two vertices wa,wa+1 are distinct, the number of β„“-mers reaching v and passing through wa,wa+1 is Cβ„“/2⁒(v,wa)β‹…Tβ„“/2⁒([u1,un],wa)+Cβ„“/2⁒(v,wa+1)β‹…Tβ„“/2⁒([u1,un],wa+1), because the first halves are distinct. However, if it happens that wa,wa+1 share one (β„“/2)-mer Ξ², the number of β„“-mers reaching v with prefix Ξ² depends on the size of the union between Sβ„“/2⁒(wa,v) and Sβ„“/2⁒(wa+1,v), and thus we recurse to length β„“/2.

Refer to caption
w T2W⁒([1,6],w) T2⁒([1,6],w)
1 0 0
2 0 0
3 1 0
4 1 1
5 1 1
6 1 1
B2={[1,2]},R⁒([1,6],a⁒a)=[1,2]
Figure 2: Example of a Wheeler graph, with an illustration of how we compute the 4-mer counts of vertex 6. The 2-mers encapsulated with a box are black, and the rest are white. With the information on the table, we can calculate T4⁒([1,6],6)=T2W⁒([1,6],3)β‹…C2⁒(3,6)+T2⁒([1,2],6)=2.
Recursive algorithm

Because of input consistency, C1⁒(v)=[degi⁒n⁑(v)>0]. For β„“>1, we have Cℓ⁒(v)=Tℓ⁒([u1,un],v), and we give a recursive formulation for Tℓ⁒([ui,uj],v). First, we introduce some notation. Given β„“β‰₯1, we call an β„“-mer white if all its occurrences arrive at the same vertex. Otherwise, we call the β„“-mer black. Let Tβ„“W⁒([ui,uj],v) be the number of white β„“-mers starting from any vertex in [ui,uj] and reaching v, and let Bβ„“ be the set of all black β„“-mers of length β„“. Finally, let R⁒([ui,uj],Ξ²) denote the maximal interval of vertices that we can reach starting from [ui,uj] and following an β„“-mer Ξ². Note that for two distinct black β„“-mers Ξ²1β‰ΊΞ²2 and any IβŠ†[u1,un], |R⁒(I,Ξ²1)∩R⁒(I,Ξ²2)|≀1.

We compute Tℓ⁒([ui,uj],v) by dividing the number of β„“-mers reaching v from [ui,uj] into those whose first half is white, and those whose first half is black:

Tℓ⁒([ui,uj],v)=βˆ‘w∈VTβ„“/2W⁒([ui,uj],w)β‹…Cβ„“/2⁒(w,v)+βˆ‘Ξ²βˆˆBβ„“/2Tβ„“/2⁒(R⁒([ui,uj],Ξ²),v) (3)

The first term of the sum avoids double counting because all the first white halves are different. The second term counts the number of β„“-mers that reach v with each black (β„“/2)-mer as a prefix, starting from [ui,uj].

To fulfill the recursion, we run into the issue that for two (β„“/2)-mers Ξ² and Ξ³ and any interval IβŠ†[u1,un], R⁒(I,γ⁒β)βŠ†R⁒(I,Ξ²), and we cannot easily infer the value of Tℓ⁒(R⁒(I,γ⁒β),v) from Tℓ⁒(R⁒(I,Ξ²),v) if R⁒(I,γ⁒β)⊊R⁒(I,Ξ²). We settle for computing Tℓ⁒([ui,uj],v) for all O⁒(n2) intervals [ui,uj]βŠ†[u1,un] at every level of the recursion, and for every v∈V. This requires a table of size O⁒(n3) at every level of the recursion, where each value takes O⁒(n) time to compute with formula 3 once the terms inside the sum have been computed.

Once we have found all Tβ„“/2⁒([ui,uj],w), the terms Tβ„“/2W⁒([ui,uj],w) for the next recursion can be computed by subtracting the black k-mers reaching the vertices, which we can check from the sets Pβ„“/2⁒(v) as shown in appendix B. There, we also show how to compute the intervals of β„“-mers in Bβ„“ and R⁒([ui,uj],Ξ²) from the LCS array and the sets Pβ„“/2⁒(v). Note that knowing the endpoints of the intervals of vertices reached by the β„“-mers in Bβ„“ is enough to fulfil the recursion. We achieve this by building a data structure of size O⁒(n2) that allows us to compute each Tβ„“W⁒([ui,uj],v) from Tℓ⁒([ui,uj],v) in O⁒(1) time, to find the intervals of β„“-mers in Bβ„“ in O⁒(n) time, and all R⁒([ui,uj],Ξ²) in a total of O⁒(n3) time.

With log⁑k recursion steps, we arrive at an algorithm with O⁒(n4⁒log⁑k) running time, and O⁒(n3) space. The space complexity can be achieved by only keeping in memory the table from the last iteration. All together, we have shown the following theorem:

Theorem 10.

We can compute the number of distinct k-mers of a DWG W=(V,E) in time O⁒(n4⁒log⁑k), where n=|V|.

5 π’Œ-mer preserving graph transformations to Wheeler graphs

The algorithms in Section 4 are of limited usability since they apply only to deterministic Wheeler graphs. In this Section we discuss how to transform some more general graphs into deterministic Wheeler graphs.

An layered DAG with k layers is a directed acyclic graph that can be partitioned into k disjoint subsets of vertices V0,…⁒Vkβˆ’1 such that edges exists only from vertices in Vi into Vi+1 for i=0,…,kβˆ’2. For any graph, we can build the k times unfolded DAG, which preserves the k-mers in the graph:

Definition 11.

The k times unfolded DAG of a graph G is a layered DAG Gk with k+1 layers such that the vertices on each layer Vi are a copy of the vertices of G, and the edge set is defined so that for every edge (u,v,c) in G there are edges from the copy of u in layer i to the copy of v in layer i+1 for all i=0,…⁒kβˆ’1.

We can turn this into a DFA by introducing a new initial state with epsilon-transitions into the first layer, and determinizing with the classic subset construction. Now, since every k-mer corresponds to a distinct path from the initial state to the final layer, we can count k-mers by counting the distinct paths to each node on the final layer of the DAG, which is easily done with a dynamic programming algorithm that processes the nodes in topological order.

However, this does not exploit overlaps between k-mers. For deterministic acyclic graphs that have a source node that can reach all nodes, we may use the Wheelerization algorithm of Alanko et al. [2] that computes the smallest equivalent Wheeler DFA in O⁒(n⁒log⁑n) time in the size of the output. More generally, if the input is the state graph G of any DFA recognizing a Wheeler language, the minimum equivalent Wheeler DFA can be constructed in O⁒(|G|3⁒n⁒log⁑n) time, where n is the size of the output [8].

Another option is to build the de Bruijn graph of the k-mers, which is always Wheeler [10]. Unfortunately, this does not help much with counting the k-mers because building the de Bruijn graph takes time proportional to the number of k-mers, since there is one node per k-mer. That is, building the de Bruijn graph amounts to a brute force enumeration of all k-mers. However, the de Bruijn graph is not necessarily the smallest graph for a given set of k-mers: For example, the Wheeler DFA minimization algorithm of Alanko et al. [1], run on the de Bruijn graph, can reduce the size of the graph while maintaining Wheelerness. Building this compressed graph directly without first building the de Bruijn graph would be useful, but seems to be nontrivial. We leave this open for future work.

6 The de Bruijn Graph of a Deterministic Wheeler Graph

In this section, we define a representation of the node-centric de Bruijn graph of the k-mers of a DWG W, building on the definitions of black and white k-mers and the counting algorithms introduced in the previous section. We denote the de Bruijn graph by d⁒B⁒g. First, we describe the data structure contents, then we describe the algorithms to navigate the de Bruijn graph given this data structure, and then we analyse their time and space in bits. Finally we show how to build it in time and space O⁒(nk+|W|⁒k⁒log⁑(max1≀ℓ≀k⁑nβ„“)+σ⁒log⁑m). The main technical difficulty of this section is that each vertex v∈V⁒(W) may have exponentially many white k-mers that reach only v. Thus, to support de Bruijn graph navigation we need to keep track of the rank of the k-mer among all the k-mers reaching v, and update it to the rank in another vertex as we traverse an edge.

6.1 Data structure

Before presenting the data structure components, we define some new concepts.

  • β– 

    A left-extension of an β„“-mer Ξ±βˆˆβ„’β’(W) is an (β„“+1)-mer cβ’Ξ±βˆˆβ„’β’(W), that has Ξ± as a suffix. Note that all left-extensions of a white k-mer are also white.

  • β– 

    The left-contraction of an β„“-mer Ξ± is the maximal interval of vertices that Ξ±[2..β„“] reaches. The left-contraction of a white β„“-mer may be black.

  • β– 

    For a vertex v, Eℓ⁒(v) is the array containing the number of distinct left-extensions of each β„“-mer reaching v, sorted by their colex order.

  • β– 

    For a vertex v∈V⁒(W), the intervals 𝗅𝖾𝖿𝗍⁒_⁒𝗂𝗇𝗍𝖾𝗋𝗏𝖺𝗅ℓ⁒(v) and 𝗋𝗂𝗀𝗁𝗍⁒_⁒𝗂𝗇𝗍𝖾𝗋𝗏𝖺𝗅ℓ⁒(v) are defined as:

    • –

      𝗅𝖾𝖿𝗍⁒_⁒𝗂𝗇𝗍𝖾𝗋𝗏𝖺𝗅ℓ⁒(v)={maximal ⁒[va,vb]βŠ†V⁒(W):(βˆ€w∈[va,vb])⁒(minvℓ↝w)}.

    • –

      𝗋𝗂𝗀𝗁𝗍⁒_⁒𝗂𝗇𝗍𝖾𝗋𝗏𝖺𝗅ℓ⁒(v)={maximal ⁒[va,vb]βŠ†V⁒(W):(βˆ€w∈[va,vb])⁒(maxvℓ↝w)}

We give a few more details on the intervals. If any of minvβ„“ or maxvβ„“ does not exist, we define the respective left or right interval to be empty. Furthermore, for an interval of vertices [va,vb] where va<vb, we note that maxvaβ„“=minvbβ„“ by Corollary 7, and this β„“-mer is black. We represent the intervals by the two endpoints va,vb. In the appendix we show how to compute the intervals for all v and all 1≀ℓ≀k in O⁒(n⁒k) time, by scanning the vertices left-to-right and using the π—Œπ—π–Ίπ—‹π–Ύβ„“ function in each level.

Components.

The data structure is comprised of the following parts:

  • β– 

    The standard Wheeler index for W [10].

  • β– 

    For all v∈V⁒(W), the (kβˆ’1)-mer counts Ckβˆ’1⁒(v).

  • β– 

    For all v∈V⁒(W) and all 1≀ℓ≀k, with p⁒r⁒e⁒d⁒(v)=(u1,…,ud), a cumulative array Cℓ⁒(v)Β―[1..d] where Cℓ⁒(v)¯⁒[j] is the total number of (β„“βˆ’1)-mers reaching u1⁒…⁒ujβˆ’1 that are smaller than minujβ„“βˆ’1.

  • β– 

    For all non-sink vertices v, a predecessor data structure over the array of cumulative sums of Ekβˆ’1⁒(v), named Ekβˆ’1⁒(v)Β―[1..Ckβˆ’1(v)]. Given a number j of distinct left-extensions, the query returns the smallest index t such that Ekβˆ’1⁒(v)⁒[1]+…+Ekβˆ’1⁒(v)⁒[t]β‰₯j. We implement this data structure using constant-time rank and select operations [14, 6].

  • β– 

    For all v∈V⁒(W), the intervals 𝗅𝖾𝖿𝗍⁒_⁒𝗂𝗇𝗍𝖾𝗋𝗏𝖺𝗅kβˆ’1⁒(v) and 𝗋𝗂𝗀𝗁𝗍⁒_⁒𝗂𝗇𝗍𝖾𝗋𝗏𝖺𝗅kβˆ’1⁒(v), stored as described above.

Now, we describe how to implement the navigation queries with these data structures, and afterwards we analyse their space and time complexity.

6.2 de Bruijn Graph Navigation

The operations we implement return the handle of a k-mer, listing outgoing labels from a k-mer, and performing forward traversal with an outgoing label.

Handle of a π’Œ-mer.

The handle of a k-mer Ξ± is a triple (u,v,j), where [u,v] is the maximal interval of V⁒(W) that Ξ± reaches, and j is the rank of Ξ± in the colex order of k-mers reaching the left endpoint u. We obtain u and v via the standard forward-search on the Wheeler index, but we must keep track of the rank j. For 0≀ℓ≀k, let [uβ„“,vβ„“] be the interval of vertices that we obtain after matching Ξ±[1..β„“], starting from [u0,v0]=[v1,vn]. At any step where uβ„“<vβ„“, j=Cℓ⁒(uβ„“) because Ξ±[1..β„“]=maxuβ„“β„“. If uβ„“=vβ„“ for some β„“, we update j as follows. We find the rank t of uβ„“βˆ’1 among the in-neighbours of uβ„“ with the Wheeler index, and we set j←Cℓ⁒(uβ„“)¯⁒[t]+j.

Listing outgoing labels.

Given a handle (u,v,j), with the standard Wheeler graph index we can output the distinct outgoing labels in O⁒(log⁑σ) time per label, using rank and select operations [10].

Forward traversal.

Given the handle (u,v,j) of a k-mer b⁒α, |Ξ±|=kβˆ’1, and a label c, we can return the handle of α⁒c by first performing a left contraction on b⁒α, which returns an interval [u′⁒vβ€²], and then matching c from that interval with the Wheeler index and updating the rank (this is done in the same way as when we return the handle of a full k-mer).

To perform a left contraction we distinguish two cases. If u<v, then the left contraction is equal to 𝗋𝗂𝗀𝗁𝗍⁒_⁒𝗂𝗇𝗍𝖾𝗋𝗏𝖺𝗅kβˆ’1⁒(u), and the rank is Ckβˆ’1⁒(u). If u=v, then the rank of Ξ± is equal to s⁒e⁒l⁒e⁒c⁒t⁒(Ekβˆ’1⁒(u),j). If the new rank is 1 or Ckβˆ’1⁒(u), then the interval is 𝗅𝖾𝖿𝗍⁒_⁒𝗂𝗇𝗍𝖾𝗋𝗏𝖺𝗅kβˆ’1⁒(u) or 𝗋𝗂𝗀𝗁𝗍⁒_⁒𝗂𝗇𝗍𝖾𝗋𝗏𝖺𝗅kβˆ’1⁒(u), respectively. Otherwise, Ξ± is a white k-mer, and the interval is [u,u].

6.3 Analysis

We store the β„“-mer counts Cℓ⁒(v) and the arrays Cℓ⁒(v)Β― as arrays of integers. The required integer size is given by the maximum number of β„“-mers, across all β„“=1..k. We denote by nβ„“ the number of β„“-mers of W, and with this notation, we obtain that we require n⁒k⁒log⁑(max1≀ℓ<k⁑nβ„“) bits to store the counts Cℓ⁒(v). The integers in Cℓ⁒(v)Β― grow up to Cβ„“+1⁒(v), thus we require 2⁒m⁒k⁒log⁑(max2≀ℓ≀k⁑nβ„“) bits to represent the arrays. The intervals take up 2⁒n⁒k⁒(log⁑n+2) bits. The Wheeler graph index is representable in O⁒(|W|+m⁒log⁑σ+σ⁒log⁑m) bits [10].

Finally, to build the predecessor data structure on Ekβˆ’1⁒(v)Β―, we encode Ekβˆ’1⁒(v) in unary, for example by ⨀1≀j≀|Ekβˆ’1⁒(v)|10Ekβˆ’1⁒(v)⁒[j], where ⨀ is the operator for concatenation of bit sequences. We build the classic constant rank and select data structures on it [14, 6]. To analyse the space, observe that all left extensions counted by all arrays Ekβˆ’1⁒(v) for all v represent distinct k-mers, except for at most 2⁒n shared k-mers between the vertices. Therefore, the sum of all zeros in all Ekβˆ’1⁒(v) is bounded by nk+2⁒n=|V⁒(d⁒B⁒g)|+2⁒n. The number of ones in Ekβˆ’1⁒(v) corresponds to the number of (β„“βˆ’1)-mers arriving at v. Notice, however, that we only compute Ekβˆ’1 for non-sink vertices, thus for each distinct (kβˆ’1)-mer represented by a 1-bit we have a distinct k-mer in V⁒(d⁒B⁒g) by right-extension. Thus, we get at most |V⁒(d⁒B⁒g)|+2⁒n ones. The space becomes O⁒(nk+|W|⁒k⁒log⁑(max1≀ℓ≀k⁑nβ„“)+σ⁒log⁑m) bits111Here we used σ≀n [11]..

The time needed for the operations to obtain the handle of a k-mer are bounded by O⁒(k) Wheeler graph operations, which take O⁒(log⁑σ) each. Listing outgoing labels can be done in O⁒(log⁑σ) time per label. The forward traversal requires one Wheeler graph matching, and a predecessor on Ekβˆ’1⁒(v)Β―, which can be implemented now with constant time rank and select on Ekβˆ’1⁒(v). Therefore, we arrive at the following theorem:

Theorem 12.

There exists a data structure for simulating navigation of the de Bruijn graph d⁒B⁒g of the k-mers of a Wheeler graph W, which uses O⁒(nk+|W|⁒k⁒log⁑(max1≀ℓ≀k⁑nβ„“)+σ⁒log⁑m) bits of space. It implements retrieving the handle of a k-mer in O⁒(k⁒log⁑σ) time, listing of outgoing labels in O⁒(log⁑σ) time per label, and forward traversal in O⁒(log⁑σ) time.

6.4 Computation of the data structure

We have discussed how to obtain the k-mer counts of W in section 4, from which we obtain Cℓ⁒(v) and Cℓ⁒(v)Β―, and we obtain the left and right intervals as shown in appendix C. The Wheeler graph index is as in [10]. Computing the arrays Ekβˆ’1⁒(v) is more challenging though, because its size is proportional to the number of (kβˆ’1)-mers of W, which can be exponential. We develop a recursive formula for Eβ„“ in terms of Eβ„“βˆ’1, which if it were implemented directly, it would lead to a O⁒((|W|+|d⁒B⁒g|)⁒k) solution. Then, we show a smart dynamic program that implements it and computes Ekβˆ’1⁒(v) in O⁒(|W|⁒k+nk) time and space.

6.4.1 Computation of π‘¬π’Œβˆ’πŸβ’(𝒗)

Let Ξ± be an β„“-mer, and denote by L⁒E⁒(Ξ±,v) the number of left-extensions of Ξ± that reach v. First, we observe that all the β„“-mers reaching v can be found by appending λ⁒(v) to the set of (β„“βˆ’1)-mers reaching the vertices of p⁒r⁒e⁒d⁒(v) (formula 1). The same can be said about left extensions. We observe two facts:

  1. 1.

    Let Ξ± be an (β„“βˆ’1)-mer reaching only one vertex u∈p⁒r⁒e⁒d⁒(v), and assume it is the jth (β„“βˆ’1)-mer of u. Then, L⁒E⁒(α⁒λ⁒(v),v)=L⁒E⁒(Ξ±,u)=Eβ„“βˆ’1⁒(u)⁒[j].

  2. 2.

    Assume Ξ± reaches a maximal range of in-neighbours [ua,ua+1⁒…,ub]βŠ†p⁒r⁒e⁒d⁒(v), with a<b. Then,

    L⁒E⁒(α⁒λ⁒(v),v)=L⁒E⁒(Ξ±,ua)+βˆ‘a<j≀b(L⁒E⁒(Ξ±,uj)βˆ’π—Œπ—π–Ίπ—‹π–Ύβ„“β’(ujβˆ’1,uj)), (4)

    where L⁒E⁒(Ξ±,ua)=Eβ„“βˆ’1⁒(ua)⁒[Cβ„“βˆ’1⁒(ua)] and L⁒E⁒(Ξ±,uj)=Eβ„“βˆ’1⁒(uj)⁒[1]. Note how we must avoid double-counting left-extensions of size β„“ that might reach several in-neighbours.

The second case can only happen for (β„“βˆ’1)-mers that are the minimum or the maximum ones of an in-neighbour uj, by Corollary 7. Similarly, a β€œmiddle” (β„“βˆ’1)-mer Ξ± that is not minujβ„“βˆ’1 or maxujβ„“βˆ’1 will always fall into case 1, where L⁒E⁒(α⁒λ⁒(v),v)=L⁒E⁒(Ξ±,uj), that can be computed recursively. With these observations, we design an algorithm that computes Ekβˆ’1⁒(v) for all v∈V⁒(W) in two steps. First, we compute all Eℓ⁒(v)⁒[1] and Eℓ⁒[Cℓ⁒(v)] for all v∈V⁒(W) and 1≀ℓ≀k, which can be done in O⁒(|W|⁒k) time, and can be used to compute the number of left extensions of (kβˆ’1)-mers in case 2. Then, we use a recursive algorithm to report the middle values of Ekβˆ’1⁒(v). To implement these algorithms, we will need all β„“-mer counts Cℓ⁒(v) for all v∈V⁒(W) and 1≀ℓ≀k, as well as the data structure to support π—Œπ—π–Ίπ—‹π–Ύβ„“β’(u,v) queries and 𝖨𝖫𝖒𝖲⁒(v) queries.

Computing 𝑬ℓ⁒(𝒗)⁒[𝟏] and 𝑬ℓ⁒(𝒗)⁒[π‘ͺℓ⁒(𝒗)].

First, we observe that |E1⁒(v)|=1, and E1⁒(v)⁒[1]=E1⁒(v)⁒[C1⁒(v)]=[C2⁒(v)] by input-consistency. Then, for β„“=2,3,…,kβˆ’1, we compute Eℓ⁒(v)⁒[1] as follows. First, we scan the in-neighbours left-to-right until finding the first one with a non-zero count of (β„“βˆ’1)-mers. Let us be this vertex. We add the count of left-extensions of the first (β„“βˆ’1)-mer of us, and in case that (β„“βˆ’1)-mer is shared by more in-neighbours (which can be checked with π—Œπ—π–Ίπ—‹π–Ύβ„“βˆ’1⁒(us,us+1)), updating the count as in equation (4) above for every in-neighbour that shares the (β„“βˆ’1)-mer. The computation of Eℓ⁒(v)⁒[Cℓ⁒(v)] is similar, but going right-to-left, starting from the rightmost in-neighbour ue that has Cβ„“βˆ’1⁒(ue)>0. Clearly, we spend O⁒(1+degi⁒n⁑(v)) time per vertex per value of β„“, thus in total we spend O⁒((n+m)⁒k)=O⁒(|W|⁒k) time, and obtain a data structure of size O⁒(n⁒k).

Computing the rest of π‘¬π’Œβˆ’πŸβ’(𝒗) recursively.

We sketch a recursive procedure called 𝗅𝖾𝖿𝗍⁒_β’π–Ύπ—‘π—π–Ύπ—‡π—Œπ—‚π—ˆπ—‡π—Œβ’(w,β„“,Ekβˆ’1⁒(v)), that appends to one array Ekβˆ’1⁒(v) the counts of left-extensions that we find for β„“-mers of w. This procedure uses too many recursive calls, which we fix in the next section.

We start by calling 𝗅𝖾𝖿𝗍⁒_β’π–Ύπ—‘π—π–Ύπ—‡π—Œπ—‚π—ˆπ—‡π—Œ with w=v and β„“=kβˆ’1. Let p⁒r⁒e⁒d⁒(w)={u1,…,ud}. We scan the in-neighbours of w left-to-right, and we find the first one us with non-zero count of (β„“βˆ’1)-mers, Cβ„“βˆ’1⁒(us)>0. We repeat the following steps for all in-neighbours starting from uj=us:

  1. 1.

    Process the first (β„“βˆ’1)-mer Ξ± of uj. If we have counted its number of left-extensions already, ignore it. Otherwise, obtain the count of its left-extensions from the previously computed Eβ„“βˆ’1⁒(uj)⁒[1]. If Ξ± is shared with other in-neighbours, we have to apply formula (4) to count them. Append this count to Ekβˆ’1⁒(v). If we applied formula (4), we start again at step 1 with the last in-neighbour that has Ξ± incoming. Otherwise, move to step 2.

  2. 2.

    If Cβ„“βˆ’1⁒(uj)>2, recurse on uj with a call to 𝗅𝖾𝖿𝗍⁒_β’π–Ύπ—‘π—π–Ύπ—‡π—Œπ—‚π—ˆπ—‡π—Œβ’(uj,β„“βˆ’1,Ekβˆ’1⁒(v)).

  3. 3.

    Process the last (β„“βˆ’1)-mer Ξ² of uj. If β⁒λ⁒(w) is the last β„“-mer of w, stop. Otherwise, check π—Œπ—π–Ίπ—‹π–Ύβ„“βˆ’1⁒(uj,uj+1). If it is false, we append Eβ„“βˆ’1⁒(uj)⁒[Cβ„“βˆ’1⁒(uj)] to Ekβˆ’1⁒(v). If it is true, we compute the number of left-extensions of Ξ² with formula (4), and we move to the last in-neighbour that has Ξ² incoming.

It is possible to compute these steps for all in-neighbours of w in time O⁒(degi⁒n⁑(w)) plus the time to make the recursive calls, by using the left and right intervals and the π—Œπ—π–Ίπ—‹π–Ύ function. We leave the details in appendix C. Still, this procedure uses too many recursive calls, since for some w and β„“, 𝗅𝖾𝖿𝗍⁒_β’π–Ύπ—‘π—π–Ύπ—‡π—Œπ—‚π—ˆπ—‡π—Œβ’(w,β„“,Ekβˆ’1⁒(v)) may be called by many out-neighbours of w. However, we observe that every such call outputs the exact same numbers to Ekβˆ’1⁒(v). Therefore, using dynamic programming with memoization we can avoid computing repeated sub-problems.

Memoization.

We build the (kβˆ’1)-times unfolded graph Wkβˆ’1, and we add to all the vertices of Wβ„“βˆ’1 a placeholder for two pointers p and q. At the start of the algorithm, these pointers are empty. Crucially, we keep and reuse the pointers between computations of Ekβˆ’1⁒(vi) for different vi. We consider a call to 𝗅𝖾𝖿𝗍⁒_β’π–Ύπ—‘π—π–Ύπ—‡π—Œπ—‚π—ˆπ—‡π—Œβ’(w,β„“,Ekβˆ’1⁒(vi)) as a call on the vertex wβ„“ at layer β„“. Whenever we recurse on a vertex wβ„“ for the first time, we set p to the next position in the current list Ekβˆ’1⁒(vi), where the next value will be appended. When the recursion returns, q is set to point to the last filled position in Ekβˆ’1⁒(vi). The next time we recurse on wβ„“, whether in the computation of Ekβˆ’1⁒(vi) or another Ekβˆ’1⁒(vj), instead of running the algorithm, we output all values between p and q on Ekβˆ’1⁒(vi).

Complexity.

Clearly, now there are at most O⁒(n⁒k) recursions during the computation of all Ekβˆ’1⁒(v). These take time O⁒(1+degi⁒n⁑(v)) once per vertex, when the pointers p and q have not been computed yet. This amounts to O⁒(|W|⁒k) time in total. All other time is spent reporting values of Ekβˆ’1⁒(v), which as we argued before, there are O⁒(|V⁒(d⁒B⁒g)|)=O⁒(nk) of them. We have finally showed the following theorem:

Theorem 13.

We can build the data structure for de Bruijn graph navigation on the k-mers of a Wheeler graph W, in time and space O⁒(nk+|W|⁒k⁒log⁑(max1≀ℓ≀k⁑nβ„“)+σ⁒log⁑m).

7 Conclusion

This work, to the best of our knowledge, is the first to study the problem of k-mer counting on graphs. We have introduced the problem and established both hardness results and tractable cases. While the problem turns out to be #P-hard, our results show that the problem is in P in the class of Wheeler graphs, and by extension on any class of graphs that can be transformed into a Wheeler graph of polynomial size, without changing the k-mers. As the first application for our k-mer counting algorithm, we have shown how to simulate the de Bruijn graph of the k-mers of a Wheeler graph, without having to construct k-mers explicitly, improving on the state-of-the-art in this respect [20].

The tractability of the problem on Wheeler graphs raises several natural open questions. First, can we find the smallest Wheeler graph that preserves the k-mers of a given input graph? Second, which kinds of graphs admit polynomial-size Wheelerizations with the same k-mer set? Third, what is the best achievable polynomial degree of n for algorithms running in O⁒(poly⁒(n)⁒log⁑k) time on Wheeler graphs? This work thus marks a first step toward a broader theory of k-mer counting in graphs.

References

  • [1] Jarno Alanko, Nicola Cotumaccio, and Nicola Prezza. Linear-time minimization of wheeler dfas. In 2022 Data Compression Conference (DCC), pages 53–62. IEEE, 2022. doi:10.1109/DCC52660.2022.00013.
  • [2] Jarno Alanko, Giovanna D’Agostino, Alberto Policriti, and Nicola Prezza. Regular languages meet prefix sorting. In Proceedings of the Fourteenth Annual ACM-SIAM Symposium on Discrete Algorithms, pages 911–930. SIAM, 2020. doi:10.1137/1.9781611975994.55.
  • [3] Jarno N. Alanko, Davide Cenzato, Nicola Cotumaccio, Sung-Hwan Kim, Giovanni Manzini, and Nicola Prezza. Computing the LCP array of a labeled graph. In Shunsuke Inenaga and Simon J. Puglisi, editors, 35th Annual Symposium on Combinatorial Pattern Matching, CPM 2024, June 25-27, 2024, Fukuoka, Japan, volume 296 of LIPIcs, pages 1:1–1:15. Schloss Dagstuhl – Leibniz-Zentrum fΓΌr Informatik, 2024. doi:10.4230/LIPIcs.CPM.2024.1.
  • [4] Bahar Alipanahi, Alan Kuhnle, Simon J Puglisi, Leena Salmela, and Christina Boucher. Succinct dynamic de bruijn graphs. Bioinformatics, 37(14):1946–1952, July 2021. doi:10.1093/bioinformatics/btaa546.
  • [5] Alexander Bowe, Taku Onodera, Kunihiko Sadakane, and Tetsuo Shibuya. Succinct de bruijn graphs. In Ben Raphael and Jijun Tang, editors, Algorithms in Bioinformatics, pages 225–235, Berlin, Heidelberg, 2012. Springer Berlin Heidelberg. doi:10.1007/978-3-642-33122-0_18.
  • [6] David Richard Clark. Compact PAT trees. PhD thesis, University of Waterloo, Canada, 1996.
  • [7] Alessio Conte, Nicola Cotumaccio, Travis Gagie, Giovanni Manzini, Nicola Prezza, and Marinella Sciortino. Computing matching statistics on wheeler dfas. In Proc. Data Compression Conference (DCC), pages 150–159. IEEE, 2023. doi:10.1109/DCC55655.2023.00023.
  • [8] Giovanna D’Agostino, Davide Martincigh, and Alberto Policriti. Ordering regular languages and automata: Complexity. Theoretical Computer Science, 949:113709, 2023. doi:10.1016/J.TCS.2023.113709.
  • [9] Johannes Fischer. Optimal succinctness for range minimum queries. In Alejandro LΓ³pez-Ortiz, editor, LATIN 2010: Theoretical Informatics, pages 158–169, Berlin, Heidelberg, 2010. Springer Berlin Heidelberg. doi:10.1007/978-3-642-12200-2_16.
  • [10] Travis Gagie, Giovanni Manzini, and Jouni SirΓ©n. Wheeler graphs: A framework for bwt-based data structures. Theoretical computer science, 698:67–78, 2017. doi:10.1016/J.TCS.2017.06.016.
  • [11] Daniel Gibney and Sharma V. Thankachan. On the Complexity of Recognizing Wheeler Graphs. Algorithmica, 84(3):784–814, 2022. doi:10.1007/s00453-021-00917-5.
  • [12] Torben Hagerup. Sorting and searching on the word ram. In Proc. 15th STACS, pages 366–398, 1998. doi:10.1007/BFB0028575.
  • [13] Dov Harel and Robert Endre Tarjan. Fast algorithms for finding nearest common ancestors. SIAM Journal on Computing, 13(2):338–355, 1984. doi:10.1137/0213024.
  • [14] Guy Joseph Jacobson. Succinct static data structures. PhD thesis, Carnegie Mellon University, USA, 1988.
  • [15] Juha KΓ€rkkΓ€inen, Peter Sanders, and Stefan Burkhardt. Linear work suffix array construction. J. ACM, 53(6):918–936, 2006. doi:10.1145/1217856.1217858.
  • [16] Toru Kasai, Gunho Lee, Hiroki Arimura, Setsuo Arikawa, and Kunsoo Park. Linear-time longest-common-prefix computation in suffix arrays and its applications. In Amihood Amir, editor, Combinatorial Pattern Matching, pages 181–192, Berlin, Heidelberg, 2001. Springer Berlin Heidelberg. doi:10.1007/3-540-48194-X_17.
  • [17] Sung-Hwan Kim, Francisco Olivares, and Nicola Prezza. Faster Prefix-Sorting Algorithms for Deterministic Finite Automata. In Laurent Bulteau and Zsuzsanna LiptΓ‘k, editors, 34th Annual Symposium on Combinatorial Pattern Matching (CPM 2023), volume 259 of Leibniz International Proceedings in Informatics (LIPIcs), pages 16:1–16:16, Dagstuhl, Germany, 2023. Schloss Dagstuhl – Leibniz-Zentrum fΓΌr Informatik. doi:10.4230/LIPIcs.CPM.2023.16.
  • [18] Udi Manber and Gene Myers. Suffix arrays: a new method for on-line string searches. siam Journal on Computing, 22(5):935–948, 1993. doi:10.1137/0222058.
  • [19] Camille Marchet, Christina Boucher, Simon J Puglisi, Paul Medvedev, MikaΓ«l Salson, and Rayan Chikhi. Data structures based on k-mers for querying large collections of sequencing data sets. Genome research, 31(1):1–12, 2021.
  • [20] Jouni SirΓ©n. Indexing variation graphs. In 2017 Proceedings of the ninteenth workshop on algorithm engineering and experiments (ALENEX), pages 13–27. SIAM, 2017. doi:10.1137/1.9781611974768.2.
  • [21] Leslie G Valiant. The complexity of enumeration and reliability problems. siam Journal on Computing, 8(3):410–421, 1979. doi:10.1137/0208032.

Appendix A Proof of Lemmas 6 and 8

Lemma 6. [Restated, see original statement.]

For two nodes u,v in a DWG, if u<v, then for any two k-mers Ξ± and Ξ² such that α↝u and β↝v, we have Ξ±βͺ―Ξ².

Proof.

If Ξ±=Ξ², the claim is trivially true. Otherwise, let i be the largest index such that α⁒[i]≠β⁒[i]. Let Ξ³=Ξ±[i+1..k]=Ξ²[i+1..k]. There exists a path u1,…⁒uβ„“ labeled with Ξ³ such that uβ„“=u, and a path v1,…⁒vβ„“ labeled with Ξ³ such that vβ„“=v. We also have ujβ‰ vj for all j=1,…,β„“, or otherwise the graph is not deterministic, so we can iterate Lemma 2 for pairs of edges (uj,uj+1,c), (vj,vj+1,c), starting from uβ„“<vβ„“β‡’uβ„“βˆ’1<vβ„“βˆ’1 to obtain u1<v1. Since λ⁒(u1)=α⁒[i]≠β⁒[i]=λ⁒(v1), if α⁒[i]≻β⁒[i] then W1) implies u1>v1, a contradiction. Thus, it must hold that α⁒[i]≺β⁒[i], which implies Ξ±β‰ΊΞ². β—€

Lemma 8. [Restated, see original statement.]

Two different nodes u<v of a DWG share a k-mer if and only if𝖫𝖒𝖲⁒(supu,infv)β‰₯k. In that case, maxuk is a suffix of supu, and minvk is a suffix of infv.

Proof.

The lemma follows from two facts:

  1. 1.

    u and v can only share a k-mer if |supu|β‰₯k and |infv|β‰₯k,

  2. 2.

    |supu|β‰₯k implies that maxuk is a suffix of supu, and |infu|β‰₯k implies that minuk is a suffix of infu.

Thus, if 𝖫𝖒𝖲⁒(supu,infv)β‰₯k, then |supu|β‰₯k,|infv|β‰₯k, and 2) implies maxuk=minvk. Otherwise, if 𝖫𝖒𝖲⁒(supu,infv)<k, either a) |supu|<k∨|infv|<k, and 1) does not hold, so the k-mers cannot be shared; or |supu|β‰₯k∧|infv|β‰₯k, but then by 2) maxuk and minvk are suffixes of supu and infv, and then their LCS is less than k.

For the proof, let Iu be the set of left-infinite strings reaching u, union with the set of finite strings starting at a source, and ending at u. It is easy to check that the definitions of infu and supu in [3] are equivalent to infu=min⁑Iu and supu=max⁑Iu. Observe that if maxuk exists, there exists a maximum string in Iu suffixed by maxuk: Let M be the walk, possibly left-infinite, that is created right-to-left by following i) first the edges that form maxuk, and then ii) the maximum incoming edge to the last found vertex on the walk. This walk ends at u and is either a left-infinite string, or starts in a source; thus it spells a string in Iu, that is suffixed by maxuk. The same argument holds for a minimum string in Iu suffixed by minuk, following the smallest incoming edge.

We prove 2) first. Assuming that |supu|β‰₯k, let Ξ± be the suffix of length k of supu. We have that maxukβͺ°Ξ±, because maxuk can always be chosen as Ξ±. By contradiction, assume that maxuk≻α. Now, consider the maximum string γ∈Iu that is suffixed by maxuk: Since maxuk≻α, then γ≻supu, but this contradicts supu=max⁑Iu. Similarly, if |infu|β‰₯k and Ξ± is the suffix of length k of infu, we have minukβͺ―Ξ± because we can choose minuk=Ξ±. But if minukβ‰ΊΞ±, then the minimum string γ∈Iu suffixed by minuk is strictly smaller than infu, a contradiction.

To prove 1), we show two intermediate claims:

  1. A)

    If minuk exists, |infu|<k implies infuβ‰Ίminuk. To see why, let Ξ³ be the minimum string in Iu suffixed by minuk. We have Ξ³β‰ infu because they are of different lengths, but infu=min⁑Iu, therefore infuβ‰ΊΞ³. Since minuk is a suffix of Ξ³ of length k, but |infu|<k and infuβ‰ΊΞ³, then we have infuβ‰Ίminuk.

  2. B)

    maxukβͺ―supu regardless of the length of supu. Let Ξ³ be the maximum string in Iu suffixed by maxuk: Since maxuk is a suffix of Ξ³, maxukβͺ―Ξ³, and since supu=max⁑Iu, we have Ξ³βͺ―supu, which implies B).

Now, we have all the ingredients to prove 1): if |infv|<k, we have by A) and B) that maxukβͺ―supuβͺ―infvβ‰Ίminvk, so the k-mers cannot be shared. So we can assume |infv|β‰₯k, and by 2) minvk is a suffix of infv. If |supu|<k, because of the length of infv, we have supuβ‰Ίinfv, and since minvk is a suffix of infv, we have supuβ‰Ίminvk, that by B) implies maxukβ‰Ίminvk. So, the only time when u and v can share a k-mer is when |supu|β‰₯k and |infv|β‰₯k. β—€

Appendix B Details of the 𝑢⁒(π’πŸ’β’π₯π¨π β‘π’Œ) algorithm

We show here how to compute Tβ„“W and R⁒([ui,uj],Ξ²). We use the π—Œπ—π–Ίπ—‹π–Ύβ„“ and 𝖨𝖫𝖒𝖲β‰₯β„“ functions, and the algorithm by Kim et al [17]. Given that we can compute the 𝖫𝖒𝖲 array in time O⁒(m+n2) [3], the π—Œπ—π–Ίπ—‹π–Ύβ„“ and 𝖨𝖫𝖒𝖲β‰₯β„“ functions can be obtained directly from it and an RMQ data structure, as shown before (formula 2). The algorithm of Kim et al. constructs the sets Pℓ⁒(v) at each iteration, that contain the vertices u such that there exists a path spelling s⁒u⁒fℓ⁒(infv) from u to v. We make a matrix Dβ„“inf of size nΓ—n, where Dβ„“inf⁒(u,v)=1 if u∈Pℓ⁒(v). Furthermore, we index the columns of Dβ„“inf for range maximum queries [9]. With this data structure, we can answer the following query: For an interval [ui,uj], define Dβ„“inf⁒([ui,uj],v)=1 if there exists any w∈[ui,uj] such that s⁒u⁒fℓ⁒(infv) starts at w and ends at v, otherwise 0. We can build the corresponding data structures for the suprema, to answer the following queries: Dβ„“max⁒([ui,uj],v)=1 if and only if s⁒u⁒fℓ⁒(supv) starts at some w∈[ui,uj] and ends at v. Now, we can compute Tβ„“W⁒([ui,uj],v) with the following formula:

Tβ„“W⁒([ui,uj],v) =Tℓ⁒([ui,uj],v)βˆ’π—Œπ—π–Ίπ—‹π–Ύβ„“β’(v,vβˆ’1)β‹…Dβ„“inf⁒([ui,uj],v)
βˆ’π—Œπ—π–Ίπ—‹π–Ύβ„“(v,v+1)β‹…Dβ„“sup([ui,uj],v])β‹…[𝖨𝖫𝖒𝖲(v)<β„“].

It takes time O⁒(n2) to compute Pℓ⁒(v) for all v and for both infima and suprema in each iteration. Then, we spend O⁒(n2) time to build the matrices Dβ„“inf and Dβ„“sup and their correspondent range maximum data structures. The queries take O⁒(1) time. Thus, after O⁒(n2) time, we can compute Tβ„“W⁒([ui,uj],v) in constant time from Tℓ⁒([ui,uj],v).

To compute R⁒([ui,uj],Ξ²) for β∈Bβ„“/2, we first compute all intervals R⁒([u1,un],Ξ²) by scanning the vertices left-to-right and looking for the maximal intervals of vertices that share an β„“-mer, aided by the functions π—Œπ—π–Ίπ—‹π–Ύβ„“ and 𝖨𝖫𝖒𝖲 (see a more detailed version in appendix C). Once we have them, we restrict all found intervals [wa,wb]=R⁒([u1,un],Ξ²) to the vertices reachable from [ui,uj] as follows. Scanning [wa,wb] left to right, we change the left endpoint of [wa,wb] to the first vertex wp∈[wa,wb] such that Dβ„“sup⁒([ui,uj],wp)=1. Similarly, we change the last endpoint to the last vertex wq such that Dβ„“inf⁒([ui,uj],wq)=1. Since there are O⁒(n) such intervals, and their intersections are of size 1, this procedure can be done in O⁒(n) time for a given interval [ui,uj]. Across all O⁒(n2) intervals, we have a total of O⁒(n3) work.

Appendix C Computing intervals and left-extensions

First, we show how to compute all 𝗅𝖾𝖿𝗍⁒_⁒𝗂𝗇𝗍𝖾𝗋𝗏𝖺𝗅ℓ⁒(v) and 𝗋𝗂𝗀𝗁𝗍⁒_⁒𝗂𝗇𝗍𝖾𝗋𝗏𝖺𝗅ℓ⁒(v) for all vertices v and all 1≀ℓ≀k in O⁒(n⁒k) time once we have the β„“-mer counts. Then, we give the missing details for the left-extension counting algorithm of subsection 6.4.1.

Computing intervals.

For any β„“, the sources s have 𝗅𝖾𝖿𝗍⁒_⁒𝗂𝗇𝗍𝖾𝗋𝗏𝖺𝗅ℓ⁒(s)=𝗋𝗂𝗀𝗁𝗍⁒_⁒𝗂𝗇𝗍𝖾𝗋𝗏𝖺𝗅ℓ⁒(s)=βˆ…. For β„“=1, the left and right intervals of any vertex are the same, and they correspond to the intervals of vertices with the same incoming label. For β„“>1, first we find for every non-source v if 𝗅𝖾𝖿𝗍⁒_⁒𝗂𝗇𝗍𝖾𝗋𝗏𝖺𝗅ℓ⁒(v)=𝗋𝗂𝗀𝗁𝗍⁒_⁒𝗂𝗇𝗍𝖾𝗋𝗏𝖺𝗅ℓ⁒(v), by checking if minvβ„“=maxvβ„“. This is easy: minvβ„“=maxvβ„“ if and only if Cℓ⁒(v)=1.

Once we have this information, it is easy to run a loop through the non-source vertices, from smallest to largest, to find the maximal runs of vertices vi..vj such that for all i≀p<j we have π—Œπ—π–Ίπ—‹π–Ύβ„“βˆ’1⁒(vp,vp+1)=1, and for all i<p<j it holds that 𝗅𝖾𝖿𝗍⁒_⁒𝗂𝗇𝗍𝖾𝗋𝗏𝖺𝗅ℓ⁒(vp)=𝗋𝗂𝗀𝗁𝗍⁒_⁒𝗂𝗇𝗍𝖾𝗋𝗏𝖺𝗅ℓ⁒(vp). With this information, we can find all maximal intervals of all the vertices and assign them correctly. The algorithm takes O⁒(1) time for each vertex in each level, thus it takes O⁒(n⁒k) time in total.

Computing left-extensions.

We left out some details on the recursive algorithm to compute left-extensions. For a vertex wβ„“ and an in-neighbour uj of w, let Ξ± and Ξ² be the first and last (β„“βˆ’1)-mers of uj, respectively. We clarify the following points:

  • β– 

    How to compute formula 4 in time proportional to the number of in-neighbours that the (β„“βˆ’1)-mer reaches. Note that this may be smaller than the size of the interval of that (β„“βˆ’1)-mer.

  • β– 

    How to keep track of whether we have counted the number of left-extensions of Ξ±.

  • β– 

    How to know if β⁒λ⁒(w) is the last β„“-mer of v.

For the first point, when reporting the number of left-extensions of the last (β„“βˆ’1)-mer of uj, it may happen that 𝗋𝗂𝗀𝗁𝗍⁒_β’π—‚π—‡π—π–Ύπ—‹π—π–Ίπ—…β„“βˆ’1⁒(uj) is large, but it contains many vertices that are not in-neighbours of w. To compute formula 4 efficiently, we get the right endpoint wr of 𝗋𝗂𝗀𝗁𝗍⁒_β’π—‚π—‡π—π–Ύπ—‹π—π–Ίπ—…β„“βˆ’1⁒(uj), and we iterate the in-neighbours of w starting from uj as long as they are smaller than wr. For each of them, we add the appropriate term to the sum, and we report the value at the end.

For the second point, we keep a variable π—‹π–Ύπ—‰π—ˆπ—‹π—β’_⁒𝗆𝗂𝗇 throughout the algorithm, that indicates whether we should report the number of left-extensions of minujβ„“βˆ’1 or not. At the start of the algorithm it is false, since the number of left-extensions of minwβ„“ has been counted already (in Eℓ⁒(w)⁒[1]). When processing the last (β„“βˆ’1)-mer Ξ² of an in-neighbour uj, it may or may not be shared with more in-neighbours. If it is not shared, then π—‹π–Ύπ—‰π—ˆπ—‹π—β’_⁒𝗆𝗂𝗇 is set to t⁒r⁒u⁒e. Otherwise, if it is shared, and the last in-neighbour ub of w that Ξ² reaches has Cβ„“βˆ’1⁒(ub)>1, then we set π—‹π–Ύπ—‰π—ˆπ—‹π—β’_⁒𝗆𝗂𝗇 to f⁒a⁒l⁒s⁒e, otherwise to t⁒r⁒u⁒e.

For the last point, to avoid reporting the number of left-extensions maxwβ„“, we have two cases. If we arrive at the last in-neighbour of w, we just avoid running the last step of the algorithm. The other case is if, for some j<d, it happens that 𝗋𝗂𝗀𝗁𝗍⁒_β’π—‚π—‡π—π–Ύπ—‹π—π–Ίπ—…β„“βˆ’1⁒(uj) contains ud, and Cβ„“βˆ’1⁒(ud)=1. Thus, we must check every time we compute formula 4 if this is the case, and stop if so.