Abstract 1 Introduction 2 Informal Description of the Algorithm 3 Preliminaries 4 Data Structure 5 Queries 6 Updates 7 Applications 8 Conclusion References Appendix A Proof of Lemma 11 Appendix B Proof of Corollary 15 Appendix C Overcoming the Size Limitation

Longest Common Extension of a Dynamic String in Parallel Constant Time

Daniel Alexander Albert ORCID TU Dortmund University, Germany
Abstract

A longest common extension (LCE) query on a string computes the length of the longest common suffix or prefix at two given positions. A dynamic LCE algorithm maintains a data structure that allows efficient LCE queries on a string that can change via character insertions and deletions.

A dynamic parallel constant-time algorithm is presented that can maintain LCE queries on a common CRCW PRAM with 𝒪(nϵ) work, for any ϵ>0. The algorithm maintains a string synchronizing sets hierarchy, which it uses to answer substring equality queries, which it in turn uses to answer LCE queries. To achieve constant runtime, the algorithm allows parts of its information to become outdated by up to lognlogn updates. It answers queries by combining this slightly outdated information with a list of the recent changes.

Two applications of this dynamic LCE algorithm are shown. Firstly, a dynamic parallel constant-time algorithm can maintain membership in a Dyck language Dk,k>0 with 𝒪(nϵ) work for any ϵ>0. Secondly, a dynamic parallel constant-time algorithm can maintain squares with 𝒪(nϵ) work for any ϵ>0.

Keywords and phrases:
Dynamic Strings, Work, Parallel Constant Time, Longest Common Extension, Longest Common Prefix
Copyright and License:
[Uncaptioned image] © Daniel Alexander Albert; licensed under Creative Commons License CC-BY 4.0
2012 ACM Subject Classification:
Theory of computation Parallel algorithms
; Theory of computation Pattern matching ; Theory of computation Complexity theory and logic
Related Version:
Full Version: https://arxiv.org/abs/2604.12696 [1]
Editors:
Philip Bille and Nicola Prezza

1 Introduction

Answering longest common extension (LCE) queries is a fundamental problem that appears as part of many string algorithms. An LCE query determines, for two given indices i,j of a string S, the length of the longest common prefix (LCP) of S[i,|S|] and S[j,|S|], or the length of the longest common suffix (LCS) of S[1,i] and S[1,j].

Background on LCE Queries.

LCE queries trace back to Landau and Vishkin [14, Section 2.3], who use the name MAX-LENGTH for what we call the length of the LCP. Optimal LCE algorithms build a data structure for a given string which answers LCE queries in constant time. The first construction algorithm runs in linear time for constant alphabets ([14, Section 4] and [20]). Later algorithms achieve the same runtime even for integer alphabets [5].

These algorithms are sequential and run on a single processor. With parallel machines, we can find algorithms with shorter runtime at the cost of adding more processors.

An early parallel LCE algorithm is the skew algorithm by Kärkkäinen and Sanders [10, Theorem 2], which runs in 𝒪(log2n) time on 𝒪(n/logn) processors. This algorithm runs on the very restrictive EREW PRAM model. Shun improved this algorithm to run on 𝒪(n/log2n) processors [19, Theorem 3.6]. This algorithm is work-efficient, meaning that simulating it with just one processor is as efficient as the best known sequential algorithm.

These algorithms operate in the static setting. In the dynamic setting, we are looking for a data structure which can keep up with changes to the string. We are interested in dynamic problems where we can insert or delete single characters anywhere in the string. There has been some research on dynamic LCE algorithms on sequential machines.

Early work on dynamic strings was done by Gu, Farach and Beigel [8]. They studied the related dynamic text indexing problem. This problem is about maintaining a data structure for a changing string which can report all occurrences of a given pattern in the string. Gawrychowski et al. show an optimal data structure for a different related problem where updates and LCE queries run in logarithmic time, with high probability [7].111Gawrychowski et al. study a different but related problem and their algorithm is more powerful. The dynamic LCE problem is reducible to the problem in Gawrychowski et al. This reduction increases the runtime of queries from constant to logarithmic.

Parallel Constant-Time Algorithms.

We study the problem of dynamic LCE queries in the context of parallel constant-time algorithms. We use the parallel computational model described by Shiloach and Vishkin [18], which since has become known as the common CRCW PRAM (see e.g. [6]). A common CRCW PRAM employs multiple parallel processors that access a shared memory. Multiple processors can access the same cell of memory concurrently, but concurrent writes are only allowed if all write the same value.

We study parallel algorithms where the maximum runtime over all processors is constant. Our measure for the complexity of such algorithms is the number of processors.

Our Contributions.

Our primary result is the following theorem.

Theorem 1.

For any ϵ>0, there is a dynamic algorithm on a common CRCW PRAM that maintains a data structure for a string S with fixed maximum size n, where

  • the size of the data structure is in 𝒪(nlognlogn),222The iterated logarithm logn counts the number of times the logarithm (with base 2) has to be applied until the result is at most 1. It grows extremely slowly, e.g. log265536=5.

  • the initialization for S=ϵ runs in parallel constant time on 𝒪(nlognlogn) processors,

  • updates to the data structure after the insertion or deletion of a character are processed in parallel constant time on 𝒪(nϵ) processors, and

  • the LCE of two given indices is computed in parallel constant time on 𝒪(nϵ) processors.

A maximum size n for the string is fixed at the initialization.

Our algorithm answers LCE queries using string synchronizing sets, which keep track of the occurrences of some substrings within the underlying string. Kempa and Kociumaka [12, Section 7] show a dynamic algorithm that maintains these sets. We modify this algorithm to run in parallel constant time, using techniques related to the so-called Muddling-Lemma [4].

As an application of Theorem 1, a common CRCW PRAM can maintain Dyck languages (Corollary 15) and squares (Corollary 16) in constant time on 𝒪(nϵ) processors.

Related Work.

We already discussed related work on LCE queries. Here we go over some related work on dynamic parallel constant-time algorithms.

The study of dynamic parallel constant-time algorithms originated in the field of database theory. It traces back to the introduction of the complexity class DynFO by Patnaik and Immerman [16, Section 3.1]. DynFO contains dynamic problems where the actions required for processing updates and answering queries can be expressed as first-order formulae.

Patnaik and Immerman show that many relevant problems are in DynFO [16], like reachability on undirected graphs. Their conjecture that reachability on directed graphs is also in DynFO was later proven by Datta et al. [3].

Schmidt et al. study DynFO-algorithms to maintain membership queries for various classes of formal languages [17] via common CRCW PRAMs. The complexity class DynFO coincides with dynamic parallel constant-time algorithms on common CRCW PRAMs [9, Corollary 5.10]. The advantage of using PRAMs instead of first-order formulae to specify dynamic algorithms, as argued by Schmidt et al. [17], is that PRAM algorithms are usually easier to understand and PRAMs have a very clear and natural notion of work.

Structure.

We first give an informal description of our algorithm in Section 2. The detailed description starts with preliminary definitions and auxiliary algorithms in Section 3. Section 4 describes how the algorithm stores its information. Section 5 explains how to answer queries with this information and Section 6 describes how to process updates. Section 7 shows two applications of Theorem 1, namely for maintaining Dyck languages and squares.

2 Informal Description of the Algorithm

We first give a rough informal description of the algorithm, split into three parts. As a foundation we begin with string synchronizing sets and how they appear in static algorithms. Then we move onto a dynamic algorithm for maintaining string synchronizing sets. Finally we describe how we modify this dynamic algorithm so that it runs in parallel constant time.

String Synchronizing Sets in a Static Setting.

A good starting point for string synchronizing sets is the algorithm by Kociumaka et al. [13, Section 4]. We explain its ideas in the following.

Simply speaking, a string synchronizing set is a set of occurrences of substrings of a certain size with some useful properties. An occurrence of a substring is a sequence of positions so that the characters of the underlying string at these positions match the substring. Occurrences are typically represented by their first position and some identifier for the substring.

A string synchronizing set stores occurrences for some substrings. If any occurrence of a substring is stored, then all its occurrences need to be stored. This property is called consistency. Every position of the underlying string is covered by the first half of an occurrence and the total length of all occurrences is linear to the length of the underlying string. These properties are called density and sparseness respectively. Occurrences are assigned consistent names so that occurrences of the same substring have the same name.

Given a hierarchy of logarithmically many string synchronizing sets where the occurrence-length doubles with each level, an algorithm can decide efficiently if any two given segments are equal. To do so, it computes canonical coverings for both segments and checks if they match. A covering is a selection of occurrences from the synchronizing sets so that every position in the segment is covered by at least one occurrence. To compute a canonical covering, the algorithm selects, from each level in the synchronizing sets hierarchy, the first and last occurrences that lie entirely within the segment. See Table 1 for an example, where B1 is the string synchronizing set with substring-length 1, B2 with substring-length 2 and B4 with substring-length 4. In the string S, every first position of an occurrence in B1,B2,B3 is marked with the name assigned to that occurrence.

Table 1: Example for the first three string synchronizing sets B1,B2,B4 of string S=ababcaabbabcaabbabcb and canonical coverings for substrings S[2,12],S[9,19]. The substrings S[2,12] and S[9,19] are identical and their canonical coverings match.

It is not hard to see that, thanks to consistency, two substrings are equal if and only if their canonical coverings match. The algorithm can compute and compare canonical coverings efficiently because a canonical covering consists of at most a logarithmic number of occurrences. The LCE is then computed with several queries for substring-equality.

The construction algorithm computes the synchronizing sets hierarchy via a hierarchy of decompositions. Each decomposition divides the underlying string into a sequence of factors. Unlike the string synchronizing sets, the factors may have different lengths, but can not overlap one another. These decompositions are computed in a bottom-up fashion, starting with the decomposition of singleton factors. Then follows a series of stages where each stage takes the current decomposition and merges factors to produce the next decomposition.

A stage first looks for and merges runs of identical factors. After this preparation, a stage merges each factor with some of its neighbors consistently, i.e., if the context around two factors is identical, then it produces the same merged factors. The context around a factor consists of that factor and a certain number of characters before and after that factor. The exact number of characters depends on the rule used to choose these merges. We do not look at the concrete rule used by Kociumaka et al. [13, Section 4.2]. The rule has to be consistent, have a small context, and each merge has to involve up to a constant number of factors.

The algorithm runs over a logarithmic number of stages. The topmost decomposition consists of only one factor for the entire string. The algorithm derives the string synchronizing sets from the decompositions hierarchy. For each level of the synchronizing sets hierarchy, it selects an appropriate decomposition from the hierarchy. Every factor in the decomposition is lengthened and becomes an occurrence in the synchronizing set.

String Synchronizing Sets in a Dynamic Setting.

Kempa and Kociumaka [12, Section 7] describe a dynamic algorithm that maintains a string synchronizing sets hierarchy. The algorithm is sequential and queries and updates run in poly-log-time. The dynamic algorithm stores the decompositions hierarchy and synchronizing sets hierarchy. The idea is that, for each update, it suffices to recalculate only small parts of these hierarchies. To achieve this, Kempa and Kociumaka had to ensure that each update affects only small parts of the hierarchies. To this end, they substitute the global sparseness criteria outlined above with local sparseness. Local sparseness demands that the total length of all occurrences within any part of the string is linear in the length of that part, within a logn factor.

To achieve local sparseness, Kempa and Kociumaka modify the processing of the stages. They modify the rule for choosing merges so that the merging of each factor depends only on a few factors around it.333This is stricter than demanding only consistency. For example, the algorithm in [13] first inspects the entire string to build a rule for merging factors, then applies that rule consistently. Changing one character might result in a different rule and lead to many changes in the resulting decomposition. With their modified rule, changing one character of the string affects only a small part of the decompositions and synchronizing sets. The dynamic algorithm can afford to recalculate the affected parts for each update.

String Synchronizing Sets in Parallel Constant-Time.

We take the dynamic algorithm from Kempa and Kociumaka [12] and modify it so that updates and queries run in constant time. Our main challenge is that an update affects logarithmically many levels and it is unclear how the modifications could be computed in parallel constant time.

Our solution is a technique inspired by the so-called Muddling-Lemma [4]. The algorithm allows its data structure to become slightly outdated, i.e. the synchronizing sets do not match the current string, but the string as it was a certain number of updates ago. This technique gives the algorithm enough time to traverse the hierarchy sequentially when calculating the changes that result from an update, but makes queries slightly more complicated.

The processing of one update runs through all logn levels in sequence, taking 𝒪(logn) time per level. The algorithm divides this processing into lognlogn+1 actions, each of which runs in constant time. It spreads the actions across the following updates, so that each following update advances the processing by one action. The changes that result from the k-th update are fully processed with the (k+lognlogn)-th update. Each update computes its first action as well as lognlogn actions belonging to previous updates, all in parallel.

Due to this delayed processing, the lowermost decomposition is delayed by logn updates, the next level by 2logn updates, and so on, with the topmost decomposition delayed by lognlogn updates. These delays carry over to the synchronizing sets.

Queries have to account for the fact that the information does not reflect the current string. The solution to this problem lies in the observation that there are only up to lognlogn individual positions with outdated information. The algorithm cuts queries at these positions, splitting it into a poly-logarithmic number of sub-queries. It answers each sub-query with the slightly outdated information, then compares the cut-out positions naïvely.

3 Preliminaries

We first address the model of computation, followed by definitions for strings, string synchronizing sets, and the dynamic LCE problem. Finally, this section introduces two auxiliary problems used within our LCE algorithm.

3.1 Model of Computation

We use the Common CRCW PRAM model as originally described by Shiloach and Vishkin [18]. A PRAM consists of P(n) processors capable of performing the typical elementary operations, where n is the size of the input. The ticks of the processors are synchronized.

All processors have access to a common memory. In a CRCW PRAM multiple processors can read from and write to cells of this memory concurrently. In a common CRCW PRAM, if multiple processors write to the same cell concurrently, all must write the same value.

We use three measures for the complexity of our algorithms. These are the runtime, number of processors, and work. The runtime is the maximum runtime over all processors employed by the PRAM. The number of processors is determined at the start of the algorithm and the algorithm is not allowed to create new processors on-the-fly. The work is the product of the runtime and the number or processors. When dealing with constant-time algorithms, asymptotic bounds for the work and for the number of processors are interchangeable.

3.2 Definitions

Strings.

A string S is a finite sequence of characters from some alphabet Σ. We only consider integer alphabets Σ=[1,n]. A decomposition D=v1,,vm of S is a sequence of factors vi such that v1vm=S. We write vi=S[α,β] to point to a specific occurrence of vi so that we can distinguish different occurrences of the same substring. A string S has a period of length m if S[i]=S[i+m] for all i[1,|S|m]. A string S is periodic if it has a period with length at most |S|/2. A periodic segment of S is some substring S[α,β] that is periodic.

String Synchronizing Sets.

Our algorithm compares substrings via string synchronizing sets, which were introduced in [11, Definition 3.1]. We expand the standard definition of string synchronizing sets by a function that assigns consistent names from some domain Δ to all occurrences in the set. Our algorithm uses sets of integers {1,2,,m} for Δ.

Definition 2.

For a string S, length τ|S| and domain Δ, a string synchronizing set (Bτ,fτ) is a set Bτ{1,,|S|τ} of indices and a function fτ:BτΔ such that:

  1. 1.

    Consistency: If S[i,i+τ)=S[j,j+τ) for some i,j, then iBτ if and only if jBτ.

  2. 2.

    Density: Bτ[i,i+12τ) for all i{1,,|S|12τ}, unless there is a periodic segment of size 32τ with a period of length at most 12τ that contains i.

  3. 3.

    Sparseness444We deviate from [11, Definition 3.1] in this property and instead use local sparseness from [12]. : |Bτ[i,i+m)|=𝒪(mτlogmτ) for all m>1 and 1inmτ.

  4. 4.

    Names For all i,jBτ, fτ(i)=fτ(j) if and only if S[i,i+τ)=S[j,j+τ).

Dynamic LCE Problem.

Our algorithm solves the dynamic problem DynamicLce.

  • Problem: DynamicLce

  • Initialization: String S=ϵ, alphabet Σ=[1,n], maximum size n

  • Updates:

    • Insert(i,σ): Set S to S[1,i1]σS[i,|S|].

    • Delete(i): Set S to S[1,i1]S[i+1,|S|].

  • Queries:

    • Lcp(i,j): Return max{mS[i,i+m)=S[j,j+m)}.

    • Lcs(i,j): Return max{mS(im,i]=S(jm,j]}.

A dynamic algorithm for DynamicLce is a data structure with sub-algorithms for the initialization, updates, and queries. The initialization, given the alphabet Σ=[1,n] and maximum size n, builds a data structure for S=ϵ. The algorithms for updates modify the data structure according to changes to S. The algorithms for queries use the data structure to compute the length of the LCE for two given indices. We measure the complexity of a dynamic algorithm by the complexity of each sub-algorithm and the size of the data structure.

3.3 Auxiliary Problems

The algorithm relies on two auxiliary dynamic problems. The first problem DynamicMarkedString maintains a dynamic string where some indices are marked. We use instances of DynamicMarkedString to store string synchronizing sets and decompositions by marking each first index of an occurrence/factor. The second problem DynamicNames assigns consistent names to occurrences and factors in our synchronizing sets and decompositions. We only define the dynamic problems and state the properties of the auxiliary algorithms, but leave descriptions of how they work for the full version of this paper [1, Appendix A].

Marked String.

The first algorithm maintains a string with marked indices. We use it not only to store the current and delayed strings, but also to store synchronizing sets and decompositions by marking their first positions. Updates can insert and delete marks and modify the string. Marks apply to characters so that, if an update shifts a character, a mark on that character shifts with it. There are queries for retrieving substrings and for determining the nearest marked neighbor of a given index.

  • Problem: DynamicMarkedString

  • Initialization: Alphabet Σ=[1,n], string S=ϵ, marked indices Z=, maximum size n

  • Updates:

    • Insert(i,σ):{Set S to S[1,i1]σS[i,|S|].Set Z to {jjZ,j<i}{j+1jZ,ji}.

    • Delete(i):{Set S to S[1,i1]S[i+1,|S|].Set Z to {jjZ,j<i}{j1jZ,j>i}.

    • Mark(X) (with X[1,n]): Set Z to ZX.

    • Unmark(X) (with X[1,n]): Set Z to ZX.

  • Queries:

    • SubStr(i,m): Return S[i,i+m).

    • Succ(i): Return min{jZj>i}, or if none exists.

    • Pred(i): Return max{jZj<i}, or if none exists.

The problem DynamicMarkedString has batch-updates, which mark or unmark several indices at the same time. The size of the batches in our use-cases is |X|=𝒪(logn).

Lemma 3.

For any ϵ>0, there is a dynamic algorithm for DynamicMarkedString on a common CRCW PRAM, where

  • the size of the data structure is in 𝒪(n),

  • the initialization runs in parallel constant time on 𝒪(nϵ) processors,

  • Insert and Delete run in parallel constant time on 𝒪(nϵ) processors,

  • Mark and Unmark run in parallel constant time on 𝒪(nϵ|X|2+ϵ) processors,

  • SubStr runs in parallel constant time on 𝒪(mnϵ) processors, and

  • Succ and Pred run in parallel constant time on 𝒪(nϵ) processors.

Names.

An important task within the algorithm is assigning short names to bigger objects. These objects are substrings from Σm that represent factors/occurrences. The names are from a domain Δ. The primary purpose of this auxiliary algorithm is to maintain a function g that maps objects x to names g(x)Δ, without naming-conflicts and with |Δ|<|Σ|m.

This auxiliary algorithm avoids naming-conflicts so long as there are never more than |Δ|/k distinct objects that need names at the same time, called tracked objects. The number k>1 describes how many objects an update can modify at once. The tracked objects are stored in a set Z. The auxiliary algorithm maintains a function f that maps objects x to f(x)[1,n] such that, if f(x)0, it can forget x, removing it from the tracked objects.

Updates receive a multi-set X of objects. Let |X|x be the number of occurrences of x in X. Updates Add(X) first expand the tracked objects and assign new names for previously untracked objects in X. Then they increase f(x) for each unique xX by |X|x. Updates Sub(X) decrease f(x) for each unique xX by |X|x, then forget every x with f(x)0.

Queries retrieve the name g(x) of a given object x, if it is a tracked object.

  • Problem: DynamicNames

  • Initialization: Alphabet Σ, domain Δ, set Z=, function f:Z[1,n], injective function g:ZΔ, maximum size n of Z, substring size m.

  • Updates:

    • Add(X):{For each unique xX, if xZ, set f(x) to f(x)+|X|x.If xZ add x to Z with f(x)=|X|x,g(x)Δ so that g is injective.

    • Sub(X):{For each unique xX, if xZ, set f(x) to f(x)|X|x.Then, for each xX, if f(x)0, remove x from Z.

  • Queries:

    • Name(x): Return g(x), or if xZ.

In our usage, the batches are very small with |X|k=𝒪(logn). The names are from the domain Δ=[1,nk], which is dependent on the maximum batch size.

Lemma 4.

For any ϵ>0, there is a dynamic algorithm for DynamicNames on a common CRCW PRAM, where

  • the size of batches is |X|k and the domain is Δ=[1,nk],

  • the size of the data structure is in 𝒪(n),

  • the initialization in parallel constant time on 𝒪(nk) processors,

  • updates run in parallel constant time on 𝒪(2kmnϵ) processors, and

  • queries run in parallel constant time on 𝒪(mnϵ) processors.

This concludes the preliminary definitions. Next we describe our LCE algorithm. We first define the data structure in Section 4. Then we describe how to query it in Section 5. Finally we explain how to update the data structure in Section 6.

4 Data Structure

We describe how the algorithm stores its information. It uses several instances of the auxiliary problems described in Section 3.3. Table 2 gives a brief overview of the data structures we will define in this section for easy reference.

Table 2: Data Structures used by the algorithm. Only 𝒮 and are kept fully up-to-date.
𝒮 DynamicMarkedString current string, marks unused
compact sorted array record of recent changes
for τ=2z,z,τ[1,n]:
τ DynamicMarkedString delayed string, marks occurrences in (Bτ,fτ)
𝒩Bτ DynamicNames names used by (Bτ,fτ)
for {1,logn}:
𝒮 DynamicMarkedString delayed string, marks factors in D
𝒟 DynamicMarkedString sequence of factors names in D
𝒩D DynamicNames names used by D

Up-to-date Information.

The first data structure stores the current string without delay in an instance 𝒮 of DynamicMarkedString. It does not use the marks. Most of the other data structures represent the string as it was some number of updates ago.

The algorithm uses a record of the most recent updates to resolve outdated information. The record is a compact sorted array that stores the most recent lognlogn updates. The entries in store either that a character was inserted at some index or that at least one character was deleted between two indices. The entries are sorted by index. Each entry also stores the age of that change.

String Synchronizing Sets.

The algorithms uses a synchronizing sets hierarchy where the length of the substrings doubles with each level.

For each τ=2z,z,τ[1,n], it stores a synchronizing set (Bτ,fτ) in an instance τ of DynamicMarkedString, with some delay. The underlying string in τ is the delayed string at that level. It marks every index iBτ and annotates them with the name fτ(i). It maintains forward- and backward-links for every index in τ to the corresponding index in the current string 𝒮. It supplements the synchronizing sets with an instance 𝒩Bτ of DynamicNames to maintains the names used by Bτ.

Decompositions.

The algorithm computes the synchronizing sets via a decompositions hierarchy of decompositions D for each {1,,logn}.

The algorithm maintains several properties for the decompositions D that mirror the properties of string synchronizing sets. The decompositions are consistent in the sense that, if a big enough substring around a factor also occurs somewhere else, there is a copy of that factor at that second occurrence as well. It furthermore maintains upper and lower bounds for the size of the factors. We prove these properties at a later point.

Lemma 5.

Let u be a factor in the decomposition D at level .

  1. 1.

    If there are no string w and z2 with u=wz, then |u|2+1.

  2. 2.

    If u and v are adjacent factors in D, then |u|+|v|2+1.

The instance 𝒮 of DynamicMarkedString stores the delayed string. It marks every first index of a factor in D and annotates them with the name of the factor. It maintains links between each index in 𝒮 and the corresponding index in the current string 𝒮.

The instance 𝒟 of DynamicMarkedString also stores the decomposition. Unlike 𝒮, the underlying string is not the string for DynamicLce but the sequence of factor names in the decomposition D. It marks every factor that has a different name than the factor before it. It maintains links between each factor name in 𝒟 and its starting index in 𝒮.

It uses the instance 𝒩D of DynamicNames to maintain consistent factor names for D.

5 Queries

We first show how to answer substring equality queries using a logarithmic synchronizing sets hierarchy. Then we explain how to handle delayed synchronizing sets. We conclude by showing that LCE queries can be answered with substring equality queries.

Substring Equality.

We first show that we can answer substring equality queries if fully up-to-date string synchronizing sets (Bτ,fτ) for each τ=2z,z,τ[1,n] are available. For now, we assume that we also have, for each (Bτ,fτ), successor- and predecessor-links which point, for each index of S, to the closest occurrence in Bτ.

Lemma 6.

There is a parallel constant-time algorithm that, given a string S of size n and integers i,j,m, decides if S[i,i+m)=S[j,j+m) holds on a common CRCW PRAM with 𝒪(logn) processors. For each τ=2z,z,τ[1,n], the algorithm has access to a string synchronizing set (Bτ,fτ) and successor- and predecessor-links for Bτ.

Sketch. The algorithm first covers S[i,i+m) with logarithmically many occurrences from the synchronizing sets hierarchy. It uses the successor- and predecessor-links to find, for each level τ, the first and last occurrence at that level that lies entirely in S[i,i+m). This produces a covering of S[i,i+m), unless there are periodic prefixes or suffixes, which require some special handling. Then the algorithm looks at S[j,j+m) and, if it can find the same covering there, concludes S[i,i+m)=S[j,j+m). See the full version of this paper for a proof [1, Appendix B].

Accounting for Delay.

As mentioned above, the algorithm has to deal with the complication that it does not maintain fully up-to-date string synchronizing sets. Indeed there may be lognlogn positions where characters were recently inserted or deleted for which its information is outdated. Our solution is to cut the query at these positions into sub-queries which can be answered with the available information.

Lemma 7.

For any ϵ>0, there is a parallel constant-time algorithm that, given the information described in Section 4 and integers i,j,m, decides if S[i,i+m)=S[j,j+m) holds on a common CRCW PRAM with 𝒪(nϵ) processors.

Proof.

The algorithm first splits the query into sub-queries so that no sub-query contains recently changed indices. It creates a sub-query for the prefixes of S[i,i+m), S[j,j+m) up to but not including the first recorded change in either segment. Then, for every entry in the record , if the recorded change lies within S[i,i+m), it creates a further sub-query that starts at the first unaffected index after that change and ends at the next change in either S[i,i+m) or S[j,j+m). It similarly creates sub-queries for changes in S[j,j+m).

This results in 𝒪()=𝒪(lognlogn) sub-queries, which are answered in parallel using Lemma 6. Since the structures τ are delayed, it is possible that the same character occupies different indices in 𝒮 and τ, even if this position itself was not changed recently. The algorithm uses the links between each position in the current string 𝒮 and their corresponding positions in the delayed structures τ to match shifted indices.

The complexity of each sub-query is given in Lemma 6, but there is one caveat. In Lemma 6, we assumed that successor- and predecessor-links are precomputed and accessible with constant work, which is not true here. Instead the algorithm retrieves them from τ, which requires 𝒪(nθ) processors per query for any θ>0 (Lemma 3). For any given ϵ>0, we can choose θ such that the total number of processors overall is 𝒪(nϵ).

Finally, alongside the sub-queries for unchanged segments, the algorithm checks single indices which were recently inserted and lie within S[i,i+m) or S[j,j+m) and compares them naïvely. There are at most lognlogn recently inserted indices.

LCE Queries.

The final step reduces LCE queries to substring equality queries.

Lemma 8.

For any ϵ>0, there is a parallel constant-time algorithm that, given the information described in Section 4, answers LCE queries on a common CRCW PRAM with 𝒪(nϵ) processors.

Proof.

The algorithm finds the length of the LCE via several substring equality queries with a binary-search-like approach, with arity nϵ instead of two. Starting with the search range of all lengths [1,n], it splits the search range into nϵ same-sized segments at each step. It formulates one substring equality query per segment to determine which segment contains the LCE and becomes the next search range. This procedure terminates after 1ϵ rounds. The information described in Section 4 suffices to answer LCE-queries. It remains to show that the algorithm can maintain that information in parallel constant time on 𝒪(nϵ) processors.

6 Updates

We first explain how the algorithm spreads the processing of one change across the following updates. Then we take a look at the actions necessary to process an update.

Delayed Processing.

The decompositions D are arranged bottom-up along levels {1,,logn}. Updates traverse these levels in ascending order. The processing of an update is split into lognlogn+1 actions A(k,,i), where k counts the updates, logn the levels, and ilogn the actions on a level. The actions of the k-th update are {A(k,0,0)}{A(k,,i)[1,logn],i[i,logn]}. Actions are ordered lexicographically, i.e. A(k,,i)<A(k,,i) if < or (=)(i<i). All of these actions processed sequentially in ascending order compute the changes that result from the k-th update.

The first action A(k,0,0) updates the current string 𝒮 and the record . The actions A(k,,1),,A(k,,logn) together calculate the changes to level of the decompositions hierarchy. They also update the synchronizing sets that belong to that level.

The algorithm only processes the very first action A(k,0,0) immediately. Then, for each subsequent update, it advances the processing of this update by one further action. When update k arrives, the algorithm thus processes the following actions in parallel (if they exist):

A(k,0,0),A(k1,1,1),A(klogn,1,logn),A(klognlogn,logn,logn).

Affected and Relevant Segment.

For a decomposition D and an update that affects index i, the affected segment is the sequence of factors vj,,vj+k in D that might be affected by that update. It is the part of the D that has to be recalculate for an update at index i. An important prerequisite of our algorithm is that this affected segment is small.

The relevant segment is the union of all factors that influence a factor in vj,,vj+k. They are the factors the algorithms has to know to recalculate the affected segment.

Lemma 9.

Let D=v1,,vm be the decomposition at level , let i be some index and let vj be the factor that contains the i-th character. The affected segment for i in D is vjlogn9,,vj+5. The relevant segment is vjlogn14,,vj+logn+14.

This lemma establishes the context that affects each factor of the decomposition. It informs us that changes to one factor affect at most logn+9 factors before and 5 factors after it. To recalculate these affected factors, the algorithm only needs logn+14 factors on both sides. We do not prove Lemma 9 yet because we have to present the algorithm first.

Processing a Level

We describe how the actions A(k,,1),,A(k,,logn) compute the changes to one level in the form of one parallel algorithm with runtime 𝒪(logn). The processing of this algorithm is then split across logn actions where the final action A(k,,logn) applies changes to D.

The changes the final action A(k,,logn) applies to the decomposition D affect later actions for both this update A(k,+1,1) and later updates A(k,+1,1),k>k.

Preparation.

The algorithm modifies the affected segment of the decomposition D1 to ensure two properties. The preparation enforces that factors shorter than 21 are surrounded by factors longer than 2, which is required for the lower bound of the size-constraints. It also enforces that neighboring factors are distinct, which is required by the next step. It does this by merging factors, using the marks in 𝒟1 to identify runs of identical factors.

The result of the preparation is a string d1d2 of the names of the factors in the relevant segment of D1. To achieve the upper bound of the size-constraints, it deactivates factors longer than 2. A deactivated factor will not be merged in the next step. It deactivates a factor by replacing the name of that factor with 1. The final string satisfies the following.

Lemma 10.

Let d1d2 be the string of factor names produced by level preparation and let v1,v2, be the corresponding sequence of factors. The following hold for every i,j:

  1. 1.

    di=1 if and only if |vi|>2.

  2. 2.

    If di1, then vi=vj if and only if di=dj.

  3. 3.

    If |vi|<21, then di1=di+1=1.

  4. 4.

    If di1, then didi+1.

See the full version of this paper for a proof of Lemma 10 [1, Appendix C].

Choosing Merges.

This step starts with the string of factor names from the preparation. Recall that the algorithm maintains names according to Lemma 4, which uses integers in [1,N] with N=𝒪(nlogn). It maps these names to [0,N1] which, combined with 1 for deactivated factors, gives a string over [1,N1]. The algorithm applies a function to this string that yields a bit-string where the beginning of each merged factor is 1.

There are several properties this bit string has to have. The bit string may not contain 0000, because this would result in the merging of five or more factors, which could violate the upper bound for the size of merged factors. Likewise the bit string may not contain consecutive 1’s, because this would result in a factor that is not merged, which could violate the lower bound. The only exception to this rule is that deactivated factors should not be merged, meaning that the bit string must have consecutive 1’s there. To achieve a small context, each bit may depend on only a small sub-sequence of factor names. And finally, it must be possible to compute the function that produces this bit string efficiently.

We use deterministic coin flipping from [15, Lemma 1], with some modifications, to construct this function. This approach was taken from Kempa and Kociumaka, but with different modifications and therefore different properties compared to [12, Theorem 7.3].

Lemma 11 ([12, Theorem 7.3], [15, Lemma 1]).

For every N,n there is a function f:[1,N1]n[0,1]n which satisfies the following for all strings S[1,N1]n and indices i,j[1,n]:

  1. 1.

    If j[i4,i+logN+5], then changing S[j] does not affect f(S)[i].

  2. 2.

    If there is a k with S[k]=1, min{i,j}kmax{i,j}, then changing S[j] does not affect f(S)[i].

  3. 3.

    If S[i]=1, then f(S)[i,i+1]=11.

  4. 4.

    If f(S)[i]=1 and S[i]1, then f(S)[i+1]=0.

  5. 5.

    f(S) does not contain 0000.

  6. 6.

    There is a parallel algorithm that calculates f(S) in 𝒪(logN) time on a common CRCW PRAM with n processors.

We give the proof of Lemma 11 in the Appendix, Appendix A. It follows from Lemma 11 that all factors are merged into groups of two or four unless they are deactivated or surrounded by deactivated factors. Lemma 5 follows by induction using this fact and the preparation.

Lemma 9 follows from the combination of property 1 of Lemma 11 and the preparation. For a proof, see the full version of this paper [1, Appendix E].

Finalization.

The finalization has two tasks. It updates the decomposition D, then updates the synchronizing sets that are derived from D.

For the first task, it updates 𝒮 and 𝒩D according to how the merges were chosen.

The instance 𝒩D uses as its keys the covering of a factor with the synchronizing sets hierarchy, as would be done to answer a query (see Lemma 6). This might produce a faulty covering because the queries in Lemma 6 do not account for delayed information. We are safe to ignore this situation because it only occurs if there is a younger update with overlapping affected segment. When that younger update reaches this level, it will recalculate the factor with the faulty covering, thus cleaning up any potential problems.

After updating the decomposition in 𝒮 and assigning names as needed, the algorithm updates 𝒟. It can insert the new merged factor names into 𝒟 in a compact manner since this involves only 𝒪(logn) factor names in total.

Both the finalization of level and the preparation of level +1 modify the decomposition D and access 𝒮, 𝒟 and 𝒩D. To avoid conflicts, the finalization of waits until the preparation of +1 has finished before it accesses 𝒮, 𝒟 and 𝒩D.

The second task is deriving the synchronizing sets from the decompositions. The set Bτ contains an element i for each factor v in decomposition D. To ensure consistency the occurrence S[i,i+τ) has to contains the entire context of v. We first show how to match synchronizing sets to decompositions to guarantee that this is the case. We combine Lemma 5 and Lemma 9 to derive an upper bound for the context. It states that, if a large enough context around two factors is identical, then the factors are identical too.

Corollary 12.

For >0, let α=5(2+11) and β=(logN+9)(2+11).
Let D,D be the level- decompositions of strings S,S respectively. If x=S[i,i+m) is a factor in D and there is a j with S[iα,i+β)=S[jα,j+β], then x=S[j,j+m) is a factor in D.

Each factor in D becomes an occurrence by shifting the first index α positions to the left. It follows from Corollary 12 that this produces a consistent string synchronizing set if τ is at least as big as the context α+1+β.

Lemma 13.

Let D be the level- decomposition of a string S, let z be some integer and τ=2z. If α+1+βτ<α+1+1+β+1, then Bτ={iαj.S[i,j) is a factor in D}, alongside an appropriate name-function fτ, is a string synchronizing set for S.

Level updates synchronizing sets according to Lemma 13. Consistency follows from the fact that the occurrence contains the context. Density follows from the upper bound of Lemma 5 and sparseness follows from the lower bound.

7 Applications

We show two applications of our algorithm, one from the area of formal languages and another from string algorithms.

We note that these algorithms support only character substitutions, so inserting or deleting characters is not possible. The first algorithms also allow void characters, which can be substituted like any other character, but are ignored for the purpose of the problem.

7.1 Dyck Languages

The Dyck language Dk is the language of well-balanced parentheses expressions with k types of parentheses. We first note that we can improve the bound for the number of processors of a dynamic constant-time algorithm for D1 from 𝒪((logn)3) in Schmidt et al. [17, Theorem 6.5] to 𝒪(lognloglogn). We prove this in the full version of this paper [1, Appendix F].

Theorem 14.

There is a dynamic parallel constant-time algorithm that maintains membership in D1 on a common CRCW PRAM with 𝒪(lognloglogn) processors. Updates allow only character substitutions and void characters.

Schmidt et al. also consider Dyck languages Dk for k>1. They prove a link between the complexity for Dyck languages and the problem StringEquality [17, Lemma 6.9]. The problem StringEquality, which maintains if two dynamic strings are equal, is reducible to DynamicLce. They show that, given an efficient algorithm for StringEquality, it is possible to maintain membership in Dk while increasing the work by only a logarithmic factor. Applying Theorem 1 to [17, Lemma 6.9] yields the following bound.

Corollary 15.

For any ϵ>0,k, there is a dynamic parallel constant-time algorithm that maintains membership in Dk on a common CRCW PRAM with 𝒪(nϵ) processors. Updates allow only character substitutions and void characters.

See the Appendix, Appendix B, for a proof.

7.2 Squares

A square is a substring S[α,β]=vv where v is not empty. A string is square-free if it contains no squares. Amir et al. show dynamic sequential algorithms that run in no(1) time for square-freeness [2, Theorem 21] and maintaining all squares [2, Theorem 26]. With some modifications and using our LCE algorithm, we can construct similar efficient algorithms that run in parallel constant time.

Corollary 16.

For any ϵ>0, there is a dynamic parallel constant-time algorithm that answers if a dynamic string is square-free and maintains all squares on a common CRCW PRAM with 𝒪(nϵ) processors. Updates to the string allow only character substitutions.

We describe the algorithm in the full version of this paper [1, Appendix H]. Roughly speaking, we start with the algorithm by Amir et al., then carefully go through it to identify processes that are independent of each other and can run in parallel. This leaves only two parts that require additional insight. The first straightforward part is that the algorithm uses DynamicLce to compare long substrings, which we solve with Theorem 1. The second part is that the algorithm uses a problem called Dynamic Prefix-Suffix, which it solves recursively with logarithmic depth. We modify the recursion so that, instead of splitting the current string into a constant number of fragments at each step, it splits it into nϵ fragments, thus reducing the depth of the recursion to constant.

8 Conclusion

We gave a dynamic parallel constant-time algorithm for LCE queries on 𝒪(nϵ) processors, for any ϵ>0. It combines string synchronizing sets, a technique from string algorithms, with a technique related to the Muddling-Lemma, from dynamic constant-time algorithms. We also looked at applications of our algorithm. Using our algorithm, we can maintain Dyck languages and squares in parallel constant time on 𝒪(nϵ) processors.

We list some possible avenues of further research.

LCE queries have many applications and we expect there to be other applications of our algorithm. String synchronizing sets likewise have been used for many different purposes, like internal pattern matching or suffix arrays. This raises the question if it is possible to modify such algorithms to run in parallel constant-time, even with delayed information.

Our algorithm has two limitations. A maximum string size has to be set during the initialization and the algorithm supports only integer alphabets. While it is possible to overcome the size limitation, as we show in the Appendix, Appendix C, finding algorithms for other alphabets remains an open question.

And finally, we would ideally like to have a provably work-optimal constant-time algorithm for dynamic LCE queries. This requires an algorithm with matching lower bound. Unfortunately non-trivial lower bounds that apply specifically to dynamic parallel constant-time algorithms have so far been elusive, even for other problems.

References

  • [1] Daniel Albert. Longest common extension of a dynamic string in parallel constant time, 2026. arXiv:2604.12696.
  • [2] Amihood Amir, Itai Boneh, Panagiotis Charalampopoulos, and Eitan Kondratovsky. Repetition Detection in a Dynamic String. ESA 2019, 144:5:1–5:18, 2019. doi:10.4230/LIPIcs.ESA.2019.5.
  • [3] Samir Datta, Raghav Kulkarni, Anish Mukherjee, Thomas Schwentick, and Thomas Zeume. Reachability Is in DynFO. J. ACM, 65(5):33:1–33:24, August 2018. doi:10.1145/3212685.
  • [4] Samir Datta, Anish Mukherjee, Thomas Schwentick, Nils Vortmeier, and Thomas Zeume. A Strategy for Dynamic Programs: Start over and Muddle through. Logical Methods in Computer Science, Volume 15, Issue 2, May 2019. doi:10.23638/LMCS-15(2:12)2019.
  • [5] Martin Farach-Colton, Paolo Ferragina, and S. Muthukrishnan. On the sorting-complexity of suffix tree construction. J. ACM, 47(6):987–1011, November 2000. doi:10.1145/355541.355547.
  • [6] Faith E. Fich, Prabhakar L. Ragde, and Avi Wigderson. Relations between concurrent-write models of parallel computation. In Proceedings of the Third Annual ACM Symposium on Principles of Distributed Computing, PODC ’84, pages 179–189. Association for Computing Machinery, 1984. doi:10.1145/800222.806745.
  • [7] Paweł Gawrychowski, Adam Karczmarz, Tomasz Kociumaka, Jakub Łącki, and Piotr Sankowski. Optimal Dynamic Strings. In Proceedings of the 2018 Annual ACM-SIAM Symposium on Discrete Algorithms (SODA), Proceedings, pages 1509–1528. Society for Industrial and Applied Mathematics, January 2018. doi:10.1137/1.9781611975031.99.
  • [8] Ming Gu, Martin Farach, and Richard Beigel. An efficient algorithm for dynamic text indexing. In Proceedings of the Fifth Annual ACM-SIAM Symposium on Discrete Algorithms, SODA ’94, pages 697–704, USA, January 1994. Society for Industrial and Applied Mathematics. URL: http://dl.acm.org/citation.cfm?id=314464.314675.
  • [9] Neil Immerman. Descriptive complexity. Springer, New York u.a., 1999.
  • [10] Juha Kärkkäinen and Peter Sanders. Simple Linear Work Suffix Array Construction. In Jos C. M. Baeten, Jan Karel Lenstra, Joachim Parrow, and Gerhard J. Woeginger, editors, Automata, Languages and Programming, pages 943–955, Berlin, Heidelberg, 2003. Springer. doi:10.1007/3-540-45061-0_73.
  • [11] Dominik Kempa and Tomasz Kociumaka. String synchronizing sets: Sublinear-time BWT construction and optimal LCE data structure. In Proceedings of the 51st Annual ACM SIGACT Symposium on Theory of Computing, STOC 2019, pages 756–767. Association for Computing Machinery, 2019. doi:10.1145/3313276.3316368.
  • [12] Dominik Kempa and Tomasz Kociumaka. Dynamic Suffix Array with Polylogarithmic Queries and Updates. In Proceedings of the 54th Annual ACM SIGACT Symposium on Theory of Computing, pages 1657–1670, June 2022. doi:10.1145/3519935.3520061.
  • [13] Tomasz Kociumaka, Jakub Radoszewski, Wojciech Rytter, and Tomasz Waleń. Internal Pattern Matching Queries in a Text and Applications. SIAM Journal on Computing, 53(5):1524–1577, October 2024. doi:10.1137/23M1567618.
  • [14] Gad M. Landau and Uzi Vishkin. Fast string matching with k differences. Journal of Computer and System Sciences, 37(1):63–78, August 1988. doi:10.1016/0022-0000(88)90045-1.
  • [15] K. Mehlhorn, R. Sundar, and C. Uhrig. Maintaining dynamic sequences under equality tests in polylogarithmic time. Algorithmica, 17(2):183–198, 1997. doi:10.1007/BF02522825.
  • [16] Sushant Patnaik and Neil Immerman. Dyn-FO: A Parallel, Dynamic Complexity Class. Journal of Computer and System Sciences, 55(2):199–209, 1997. doi:10.1006/jcss.1997.1520.
  • [17] Jonas Schmidt, Thomas Schwentick, Till Tantau, Nils Vortmeier, and Thomas Zeume. Work-sensitive Dynamic Complexity of Formal Languages. In Stefan Kiefer and Christine Tasson, editors, Foundations of Software Science and Computation Structures, pages 490–509. Springer International Publishing, 2021. doi:10.1007/978-3-030-71995-1_25.
  • [18] Yossi Shiloach and Uzi Vishkin. Finding the maximum, merging and sorting in a parallel computation model. In W. Brauer, P. Brinch Hansen, D. Gries, C. Moler, G. Seegmüller, J. Stoer, N. Wirth, and Wolfgang Händler, editors, Conpar 81, pages 314–327, Berlin, Heidelberg, 1981. Springer. doi:10.1007/BFb0105127.
  • [19] Julian Shun. Fast Parallel Computation of Longest Common Prefixes. In SC ’14: Proceedings of the International Conference for High Performance Computing, Networking, Storage and Analysis, pages 387–398, November 2014. doi:10.1109/SC.2014.37.
  • [20] Peter Weiner. Linear pattern matching algorithms. In 14th Annual Symposium on Switching and Automata Theory (Swat 1973), pages 1–11, October 1973. doi:10.1109/SWAT.1973.13.

Appendix A Proof of Lemma 11

Lemma 11 states that there is a function f that, given a string S over the alphabet [1,N1], computes a bit-string of the same length such that

  1. 1.

    the bit f(S)[i] depends only on S[i4,i+logN+5],

  2. 2.

    the character S[j] does not affect bit f(S)[i] if there is a character 1 in between,

  3. 3.

    if S[i] is 1, then f(S)[i,i+1]=11,

  4. 4.

    the bit-string does not contain 11, unless the previous property applies,

  5. 5.

    the bit-string does not contain 0000, and

  6. 6.

    this function can be computed in 𝒪(logn) time on n processors.

Proof.

The algorithm treats S as the N-coloring of a path. In a nutshell, it reduces the number of colors first to 6 over logN rounds, then to 3, and finally sets all indices to 1 where the 3-coloring has a local minimum.

The algorithm also has some special handling for indices i with S[i]=1. The intention is that S[i]=1 acts as a barrier. The coloring to the left of S[i]=1 is independent from the characters to the right of it and vice versa. The coloring of S[i]=1 itself is irrelevant because the final result f(S)[i] is fixed according to Lemma 11, Property 3.

To get from an N-coloring to a 6-coloring, the algorithm repeatedly compares, for each index, the binary representation of its color with the binary representation of the next color. It determines the first index where the binary representations differ and sets the new color to the bit at that index followed by the index itself. This reduces the size of the binary representation from b bits to 1+logb bits. Observe that this results in a valid coloring.

For indices S[i]=1, it always keeps the value 1. When comparing binary representations, it treats the binary representation of 1 as 2b (i.e. every bit is different compared to a regular binary representation). This special handling of the color 1 ensures Property 2.

After logN iterations every value is either in [0,5], which forms a 6-coloring over these indices, or it is 1. The algorithm then looks at each index with color 3 and assigns for each index the smallest available color from {0,1,2} that does not occur at a neighbor. It repeats this procedure for 4 and finally for 5.

The algorithm sets f(S)[i]=1 if and only if at least one of the following holds:

  1. 1.

    S[i]=1,

  2. 2.

    S[i1]=1

  3. 3.

    the final color at i is 0, or

  4. 4.

    the final color at i is 1 and no neighbor has color 0.

The first two conditions ensure that Property 3 holds. The last two conditions simply check for a local minimum, ignoring the color 1. Since the colors form a valid 3-coloring, local minima can not neighbor each other, so Property 4 holds if we assume there are is no 1. Since there are only three colors, at least every fourth color has to be a local minima (if the coloring goes 0,1,2,1,0), so Property 5 holds as well.

The algorithm concludes with a clean-up step to address the problem that Property 4 might break next to indices with 1. If S[i]=1,S[i+1]1 the algorithm might produce f(S)[i+1,i+2]=11 (where i+1 was forced due to S[i])1 and i+2 had a local minimum). To fix this, if f(S)[i+2,i+4]=100, it sets f(S)[i+2,i+4] to 010. Otherwise, if f(S)[i+2,i+4]=101, it sets f(S)[i+2,i+4] to 001. The algorithm does the same mirrored for S[j]=1,S[j1]1 with f(S)[j1,j]=11.

The algorithm runs over logN rounds where, for each round, it only compares each color with its neighbors. Property 6 follows from this observation.

Adding up all indices that affect one bit f(S)[i] yields the bounds in Property 1.

Appendix B Proof of Corollary 15

We prove that a dynamic parallel constant-time algorithm can maintain membership in Dk on a common CRCW PRAM with 𝒪(nϵ) processors.

B.1 Maintaining Dyck Languages

The Dyck language Dk is the language of well-balanced parentheses expressions with k types of parentheses 1,1,,k,k.

The problem discussed in this section does not allow character insertion or deletion and instead uses a void character , which marks positions that should be ignored. To deal with the void character more easily, we define an erasing-function ea(S) that deletes all occurrences of character a from a string S, which we use with a= to erase void characters.

Definition 17.

The function ea:Σ(Σ{a}) erases all occurrences of a symbol a from a string with

ea(S)={ϵS{ϵ,a}σSΣ{a}ea(u)ea(v)S=uv,u,vΣ+

We can now define the dynamic problem of maintaining membership in Dk.

  • Problem: Member(Dk)

  • Initialization: String S=n

  • Updates:

    • Set(i,σ): If S[i]=, set S[i] to σ{j,jj[1,k]}.

    • Reset(i): Set S[i] to .

  • Query:

    • Member(): Is e(S)Dk?

Schmidt et al. prove a link between Member(Dk) and the problem StringEquality [17, Lemma 6.9], which maintains if two dynamic strings are equal.

  • Problem: StringEquality

  • Initialization: Strings S1=n, S2=n

  • Updates:

    • Setj(i,σ): For j{1,2}, if Sj[i]=, set Sj[i] to σ.

    • Resetj(i): For j{1,2}, set Sj[i] to .

  • Query:

    • Equal(): Is e(S1)=e(S2)?

Schmidt et al. prove that, given an algorithm for StringEquality, it is possible to solve Member(Dk). This increases the number of processors by a logarithmic factor.

Lemma 18 ([17, Lemma 6.9]).

If there is a dynamic parallel constant-time algorithm that maintains StringEquality on a common CRCW PRAM with W(n) processors, then there is a dynamic parallel constant-time algorithm that maintains Member(Dk) on a common CRCW PRAM with 𝒪(W(n)logn+(logn)3) processors, for each k1.

We use Lemma 18 to show that Member(Dk) can be solved on 𝒪(nϵ) processors. To this end, we need to show that we can maintain StringEquality efficiently. Our solution for StringEquality uses the problem RangeEval(M,), which we address first.

B.2 Maintaining RangeEval

The problem RangeEval(M,) uses a monoid (M,), which consists of a set M, a binary associative operator :M×MM and a neutral element 0M. The problem RangeEval(M,) maintains a sequence of elements m1mn and can determine, for any range 1lrn, the result of mlmr.

  • Problem: RangeEval(M,)

  • Initialization: A sequence m1mn of monoid elements with mi=0 for each i[1,n].

  • Updates:

    • Set(i,m): Replace mi with m.

  • Queries:

    • Range(l,r): Return mlmr.

Schmidt et al. show that RangeEval(M,) can be maintained on 𝒪(nϵ) processors for finite monoids (M,) [17, Proposition 5.2]. It is easy to see that their proof also works for monoids (M,) whose size depends on n, so long as each miM can be stored in a constant number of memory cells (i.e. 𝒪(logn) bits) and the operator can be evaluated in constant time by a single processor.

Lemma 19 ([17, Proposition 5.2]).

Let (M,) be a monoid where each miM can be stored in 𝒪(logn) bits and the operator can be evaluated in constant time by a single processor. For any ϵ>0, there is a dynamic algorithm for RangeEval(M,) on a common CRCW PRAM, where

  • the size of the data structure is in 𝒪(n),

  • the initialization runs in parallel constant time on 𝒪(n) processors,

  • updates run in parallel constant time on 𝒪(nϵ) processors, and

  • queries run in parallel constant time on one processor.

We do not repeat the proof here because it is identical to the original proof in [17, Proposition 5.2]. We can now reduce StringEquality to DynamicLce.

B.3 Maintaining String Equality

To solve StringEquality, we reduce DynamicLce to it. Recall that DynamicLce is defined as follows.

  • Problem: DynamicLce

  • Initialization: String S=ϵ, alphabet Σ=[1,n], maximum size n

  • Updates:

    • Insert(i,σ): Set S to S[1,i1]σS[i,|S|].

    • Delete(i): Set S to S[1,i1]S[i+1,|S|].

  • Queries:

    • Lcp(i,j): Return max{mS[i,i+m)=S[j,j+m)}.

    • Lcs(i,j): Return max{mS(im,i]=S(jm,j]}.

According to Theorem 1, we can solve DynamicLce on 𝒪(nϵ) processors. It remains to show that we can solve StringEquality on 𝒪(nϵ) processors as well.

Lemma 20.

For any ϵ>0, there is a dynamic algorithm for StringEquality on a common CRCW PRAM, where

  • the size of the data structure is in 𝒪(nlognlogn),

  • the initialization for S=n runs in parallel constant time on 𝒪(nlognlogn) processors,

  • updates run in parallel constant time on 𝒪(nϵ) processors, and

  • queries run in parallel constant time on 𝒪(nϵ) processors.

We want to reduce StringEquality to DynamicLce. It is not difficult to see that, if we let the string for DynamicLce be the concatenation of the two strings from StringEquality, answering queries becomes easy. The challenge lies in the different updates.

StringEquality uses void characters , whereas DynamicLce has insertion and deletion. While insertion and deletion is intuitively more powerful than void characters, it is not obvious how to get from one to the other. The difficulty lies in the fact that, for a string S with void characters, the position S[i] in general does not correspond to e(S)[i]. Instead S[i] corresponds to e(S)[j] where j is the number of non-void characters in S[1,i].

We use an instance of RangeEval(M,) with an appropriate monoid (M,) to maintain which position in S corresponds to which position in e(S).

Proof.

We show that we can use the algorithm for DynamicLce from Theorem 1 to solve StringEquality.

Let S1,S2 be the strings from StringEquality. The algorithm uses an instance of DynamicLce with the concatenated string e(S1S2). It furthermore maintains the lengths |e(S1)|,|e(S2)| of e(S1) and e(S2).

The algorithm answers queries Equal() by checking if Lcp(1,|e(S1)|+1)=|e(S1)|=|e(S2)| holds.

The algorithm uses instances of RangeEval(M,) to maintain which position of S1 corresponds to which position of e(S1). We define a binary string B1 that marks which positions in S1 are not . Let B1 be a binary string with |B1|=|S1|=n and B1[i]=1 if and only if S1[i]. Then, for any index i of S1, it follows that j=h=1iB[h] is the corresponding index in e(S1).

Let M=[0,n] be the natural numbers from 0 to n and let =+n+1 be addition modulo n+1. According to Lemma 19, RangeEval([0,n],+n+1) can be maintained on 𝒪(nϵ) processors. We use the binary string B1 as the underlying sequence of monoid-elements for RangeEval([0,n],+n+1). A query Range(1,i)=h=1iB[i]=j then returns, for any index i of S, the corresponding index j in e(S).

The algorithm processes an update Set1(i,σ) by first using the instance of
RangeEval([0,n],+n+1) to determine which index j of e(S) corresponds to the first non-void-character before S[i]. It updates that instance RangeEval([0,n],+n+1) with Set(i,1), increments |e(S1)| by one, then updates DynamicLce with Insert(j+1,σ).

Updates Reset1(i) are processed similarly.

For updates to S2 (updates Set2(i,σ) and Reset2(i)), the algorithm uses a second instance of RangeEval([0,n],+n+1) to maintain which positions in S2 correspond to which positions in e(S2). Updates to S2 are processed similarly to updates to S1.

We have shown that we can use our algorithm for DynamicLce alongside an algorithm for RangeEval(M,) to solve StringEquality efficiently. Corollary 15 follows from combining Lemma 20 with Lemma 18.

Appendix C Overcoming the Size Limitation

Our algorithm has the limitation that a maximum size for the string is fixed during the initialization. We give a rough description of a modified algorithm without this limitation using ideas from the Muddling Lemma [4].

The modified algorithm uses two instances of the original algorithm. It uses the current instance with some maximum size m that is larger then the current string. The future instance has maximum size 2m and is constructed as the string grows larger.

Simply speaking, the algorithm uses the current instance to answer queries, while in the background building the future instance . Both instances represent the same string, but the future instance is (in general) not yet fully built. It is fully built by the time the current string grows to large for the current instance , at which point the algorithm exchanges for , then starts building a new future instance with twice the maximum size.

Building the future instance is split across the updates. The algorithm starts building the future instance when the current string has length m2, then swaps over when it reaches length m. It therefore builds over the course of at least m2 updates, with 𝒪(mϵ) processors per update. It is possible to build with maximum size m for any underlying string in 𝒪(m) time on 𝒪(mϵ) processors.

One complication with this approach is that the underlying string for the future instance changes as it is built. To overcome this, each update is also applied to the future instance , even though it may not be fully built yet. Effects of the update to parts of that have not been built yet are simply ignored, while other effects are applied as usual.