Longest Common Extension of a Dynamic String in Parallel Constant Time
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 work, for any . 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 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 with work for any . Secondly, a dynamic parallel constant-time algorithm can maintain squares with work for any .
Keywords and phrases:
Dynamic Strings, Work, Parallel Constant Time, Longest Common Extension, Longest Common Prefix2012 ACM Subject Classification:
Theory of computation Parallel algorithms ; Theory of computation Pattern matching ; Theory of computation Complexity theory and logicEditors:
Philip Bille and Nicola PrezzaSeries and Publisher:
Leibniz International Proceedings in Informatics, Schloss Dagstuhl – Leibniz-Zentrum für Informatik
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 of a string , the length of the longest common prefix (LCP) of and , or the length of the longest common suffix (LCS) of and .
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 time on processors. This algorithm runs on the very restrictive EREW PRAM model. Shun improved this algorithm to run on 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 , there is a dynamic algorithm on a common CRCW PRAM that maintains a data structure for a string with fixed maximum size , where
-
the size of the data structure is in ,222The iterated logarithm counts the number of times the logarithm (with base ) has to be applied until the result is at most . It grows extremely slowly, e.g. .
-
the initialization for runs in parallel constant time on processors,
-
updates to the data structure after the insertion or deletion of a character are processed in parallel constant time on processors, and
-
the LCE of two given indices is computed in parallel constant time on processors.
A maximum size 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 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 is the string synchronizing set with substring-length 1, with substring-length 2 and with substring-length 4. In the string , every first position of an occurrence in is marked with the name assigned to that occurrence.
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 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 levels in sequence, taking time per level. The algorithm divides this processing into 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 -th update are fully processed with the -th update. Each update computes its first action as well as actions belonging to previous updates, all in parallel.
Due to this delayed processing, the lowermost decomposition is delayed by updates, the next level by updates, and so on, with the topmost decomposition delayed by 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 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 processors capable of performing the typical elementary operations, where 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 is a finite sequence of characters from some alphabet . We only consider integer alphabets . A decomposition of is a sequence of factors such that . We write to point to a specific occurrence of so that we can distinguish different occurrences of the same substring. A string has a period of length if for all . A string is periodic if it has a period with length at most . A periodic segment of is some substring 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 for .
Definition 2.
For a string , length and domain , a string synchronizing set is a set of indices and a function such that:
-
1.
Consistency: If for some , then if and only if .
-
2.
Density: for all , unless there is a periodic segment of size with a period of length at most that contains .
- 3.
-
4.
Names For all , if and only if .
Dynamic LCE Problem.
Our algorithm solves the dynamic problem DynamicLce.
-
Problem: DynamicLce
-
Initialization: String , alphabet , maximum size
-
Updates:
-
–
: Set to .
-
–
: Set to .
-
–
-
Queries:
-
–
: Return .
-
–
: Return .
-
–
A dynamic algorithm for DynamicLce is a data structure with sub-algorithms for the initialization, updates, and queries. The initialization, given the alphabet and maximum size , builds a data structure for . The algorithms for updates modify the data structure according to changes to . 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 , string , marked indices , maximum size
-
Updates:
-
–
-
–
-
–
(with ): Set to .
-
–
(with ): Set to .
-
–
-
Queries:
-
–
: Return .
-
–
: Return , or if none exists.
-
–
: Return , 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 .
Lemma 3.
For any , there is a dynamic algorithm for DynamicMarkedString on a common CRCW PRAM, where
-
the size of the data structure is in ,
-
the initialization runs in parallel constant time on processors,
-
Insert and Delete run in parallel constant time on processors,
-
Mark and Unmark run in parallel constant time on processors,
-
SubStr runs in parallel constant time on processors, and
-
Succ and Pred run in parallel constant time on processors.
Names.
An important task within the algorithm is assigning short names to bigger objects. These objects are substrings from that represent factors/occurrences. The names are from a domain . The primary purpose of this auxiliary algorithm is to maintain a function that maps objects to names , without naming-conflicts and with .
This auxiliary algorithm avoids naming-conflicts so long as there are never more than distinct objects that need names at the same time, called tracked objects. The number describes how many objects an update can modify at once. The tracked objects are stored in a set . The auxiliary algorithm maintains a function that maps objects to such that, if , it can forget , removing it from the tracked objects.
Updates receive a multi-set of objects. Let be the number of occurrences of in . Updates first expand the tracked objects and assign new names for previously untracked objects in . Then they increase for each unique by . Updates decrease for each unique by , then forget every with .
Queries retrieve the name of a given object , if it is a tracked object.
-
Problem: DynamicNames
-
Initialization: Alphabet , domain , set , function , injective function , maximum size of , substring size .
-
Updates:
-
–
-
–
-
–
-
Queries:
-
–
: Return , or if .
-
–
In our usage, the batches are very small with . The names are from the domain , which is dependent on the maximum batch size.
Lemma 4.
For any , there is a dynamic algorithm for DynamicNames on a common CRCW PRAM, where
-
the size of batches is and the domain is ,
-
the size of the data structure is in ,
-
the initialization in parallel constant time on processors,
-
updates run in parallel constant time on processors, and
-
queries run in parallel constant time on processors.
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.
| DynamicMarkedString | current string, marks unused | |
| compact sorted array | record of recent changes | |
| for : | ||
| DynamicMarkedString | delayed string, marks occurrences in | |
| DynamicNames | names used by | |
| for : | ||
| DynamicMarkedString | delayed string, marks factors in | |
| DynamicMarkedString | sequence of factors names in | |
| DynamicNames | names used by | |
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 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 , it stores a synchronizing set in an instance of DynamicMarkedString, with some delay. The underlying string in is the delayed string at that level. It marks every index and annotates them with the name . 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 of DynamicNames to maintains the names used by .
Decompositions.
The algorithm computes the synchronizing sets via a decompositions hierarchy of decompositions for each .
The algorithm maintains several properties for the decompositions 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 be a factor in the decomposition at level .
-
1.
If there are no string and with , then .
-
2.
If and are adjacent factors in , then .
The instance of DynamicMarkedString stores the delayed string. It marks every first index of a factor in 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 . 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 of DynamicNames to maintain consistent factor names for .
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 for each are available. For now, we assume that we also have, for each , successor- and predecessor-links which point, for each index of , to the closest occurrence in .
Lemma 6.
There is a parallel constant-time algorithm that, given a string of size and integers , decides if holds on a common CRCW PRAM with processors. For each , the algorithm has access to a string synchronizing set and successor- and predecessor-links for .
Sketch. The algorithm first covers 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 . This produces a covering of , unless there are periodic prefixes or suffixes, which require some special handling. Then the algorithm looks at and, if it can find the same covering there, concludes . 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 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 , there is a parallel constant-time algorithm that, given the information described in Section 4 and integers , decides if holds on a common CRCW PRAM with 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 , 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 , it creates a further sub-query that starts at the first unaffected index after that change and ends at the next change in either or . It similarly creates sub-queries for changes in .
This results in 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 processors per query for any (Lemma 3). For any given , we can choose such that the total number of processors overall is .
Finally, alongside the sub-queries for unchanged segments, the algorithm checks single indices which were recently inserted and lie within or and compares them naïvely. There are at most recently inserted indices.
LCE Queries.
The final step reduces LCE queries to substring equality queries.
Lemma 8.
For any , there is a parallel constant-time algorithm that, given the information described in Section 4, answers LCE queries on a common CRCW PRAM with processors.
Proof.
The algorithm finds the length of the LCE via several substring equality queries with a binary-search-like approach, with arity instead of two. Starting with the search range of all lengths , it splits the search range into 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 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 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 are arranged bottom-up along levels . Updates traverse these levels in ascending order. The processing of an update is split into actions , where counts the updates, the levels, and the actions on a level. The actions of the -th update are . Actions are ordered lexicographically, i.e. if or . All of these actions processed sequentially in ascending order compute the changes that result from the -th update.
The first action updates the current string and the record . The actions 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 immediately. Then, for each subsequent update, it advances the processing of this update by one further action. When update arrives, the algorithm thus processes the following actions in parallel (if they exist):
Affected and Relevant Segment.
For a decomposition and an update that affects index , the affected segment is the sequence of factors in that might be affected by that update. It is the part of the that has to be recalculate for an update at index . 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 . They are the factors the algorithms has to know to recalculate the affected segment.
Lemma 9.
Let be the decomposition at level , let be some index and let be the factor that contains the -th character. The affected segment for in is . The relevant segment is .
This lemma establishes the context that affects each factor of the decomposition. It informs us that changes to one factor affect at most factors before and factors after it. To recalculate these affected factors, the algorithm only needs 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 compute the changes to one level in the form of one parallel algorithm with runtime . The processing of this algorithm is then split across actions where the final action applies changes to .
The changes the final action applies to the decomposition affect later actions for both this update and later updates .
Preparation.
The algorithm modifies the affected segment of the decomposition to ensure two properties. The preparation enforces that factors shorter than are surrounded by factors longer than , 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 to identify runs of identical factors.
The result of the preparation is a string of the names of the factors in the relevant segment of . To achieve the upper bound of the size-constraints, it deactivates factors longer than . A deactivated factor will not be merged in the next step. It deactivates a factor by replacing the name of that factor with . The final string satisfies the following.
Lemma 10.
Let be the string of factor names produced by level preparation and let be the corresponding sequence of factors. The following hold for every :
-
1.
if and only if .
-
2.
If , then if and only if .
-
3.
If , then .
-
4.
If , then .
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 with . It maps these names to which, combined with for deactivated factors, gives a string over . The algorithm applies a function to this string that yields a bit-string where the beginning of each merged factor is .
There are several properties this bit string has to have. The bit string may not contain , 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 ’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 ’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 there is a function which satisfies the following for all strings and indices :
-
1.
If , then changing does not affect .
-
2.
If there is a with , , then changing does not affect .
-
3.
If , then .
-
4.
If and , then .
-
5.
does not contain .
-
6.
There is a parallel algorithm that calculates in time on a common CRCW PRAM with 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.
Finalization.
The finalization has two tasks. It updates the decomposition , then updates the synchronizing sets that are derived from .
For the first task, it updates and according to how the merges were chosen.
The instance 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 factor names in total.
Both the finalization of level and the preparation of level modify the decomposition and access , and . To avoid conflicts, the finalization of waits until the preparation of has finished before it accesses , and .
The second task is deriving the synchronizing sets from the decompositions. The set contains an element for each factor in decomposition . To ensure consistency the occurrence has to contains the entire context of . 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 , let and .
Let be the level- decompositions of strings respectively.
If is a factor in and there is a with , then is a factor in .
Each factor in 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 .
Lemma 13.
Let be the level- decomposition of a string , let be some integer and . If , then , alongside an appropriate name-function , is a string synchronizing set for .
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 is the language of well-balanced parentheses expressions with types of parentheses. We first note that we can improve the bound for the number of processors of a dynamic constant-time algorithm for from in Schmidt et al. [17, Theorem 6.5] to . 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 on a common CRCW PRAM with processors. Updates allow only character substitutions and void characters.
Schmidt et al. also consider Dyck languages for . 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 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 , there is a dynamic parallel constant-time algorithm that maintains membership in on a common CRCW PRAM with 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 where is not empty. A string is square-free if it contains no squares. Amir et al. show dynamic sequential algorithms that run in 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 , 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 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 fragments, thus reducing the depth of the recursion to constant.
8 Conclusion
We gave a dynamic parallel constant-time algorithm for LCE queries on processors, for any . 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 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 that, given a string over the alphabet , computes a bit-string of the same length such that
-
1.
the bit depends only on ,
-
2.
the character does not affect bit if there is a character in between,
-
3.
if is , then ,
-
4.
the bit-string does not contain , unless the previous property applies,
-
5.
the bit-string does not contain , and
-
6.
this function can be computed in time on processors.
Proof.
The algorithm treats as the -coloring of a path. In a nutshell, it reduces the number of colors first to over rounds, then to , and finally sets all indices to where the -coloring has a local minimum.
The algorithm also has some special handling for indices with . The intention is that acts as a barrier. The coloring to the left of is independent from the characters to the right of it and vice versa. The coloring of itself is irrelevant because the final result is fixed according to Lemma 11, Property 3.
To get from an -coloring to a -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 bits to bits. Observe that this results in a valid coloring.
For indices , it always keeps the value . When comparing binary representations, it treats the binary representation of as (i.e. every bit is different compared to a regular binary representation). This special handling of the color ensures Property 2.
After iterations every value is either in , which forms a -coloring over these indices, or it is . The algorithm then looks at each index with color and assigns for each index the smallest available color from that does not occur at a neighbor. It repeats this procedure for and finally for .
The algorithm sets if and only if at least one of the following holds:
-
1.
,
-
2.
-
3.
the final color at is , or
-
4.
the final color at is and no neighbor has color .
The first two conditions ensure that Property 3 holds. The last two conditions simply check for a local minimum, ignoring the color . 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 . Since there are only three colors, at least every fourth color has to be a local minima (if the coloring goes ), 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 . If the algorithm might produce (where was forced due to and had a local minimum). To fix this, if , it sets to . Otherwise, if , it sets to . The algorithm does the same mirrored for with .
The algorithm runs over 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 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 on a common CRCW PRAM with processors.
B.1 Maintaining Dyck Languages
The Dyck language is the language of well-balanced parentheses expressions with types of parentheses .
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 that deletes all occurrences of character from a string , which we use with to erase void characters.
Definition 17.
The function erases all occurrences of a symbol from a string with
We can now define the dynamic problem of maintaining membership in .
-
Problem: Member()
-
Initialization: String
-
Updates:
-
–
: If , set to .
-
–
: Set to .
-
–
-
Query:
-
–
: Is ?
-
–
Schmidt et al. prove a link between Member() and the problem StringEquality [17, Lemma 6.9], which maintains if two dynamic strings are equal.
-
Problem: StringEquality
-
Initialization: Strings ,
-
Updates:
-
–
: For , if , set to .
-
–
: For , set to .
-
–
-
Query:
-
–
: Is ?
-
–
Schmidt et al. prove that, given an algorithm for StringEquality, it is possible to solve Member(). 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 processors, then there is a dynamic parallel constant-time algorithm that maintains Member() on a common CRCW PRAM with processors, for each .
We use Lemma 18 to show that Member() can be solved on processors. To this end, we need to show that we can maintain StringEquality efficiently. Our solution for StringEquality uses the problem RangeEval(), which we address first.
B.2 Maintaining RangeEval
The problem RangeEval() uses a monoid , which consists of a set , a binary associative operator and a neutral element . The problem RangeEval() maintains a sequence of elements and can determine, for any range , the result of .
-
Problem: RangeEval()
-
Initialization: A sequence of monoid elements with for each .
-
Updates:
-
–
: Replace with .
-
–
-
Queries:
-
–
: Return .
-
–
Schmidt et al. show that RangeEval() can be maintained on processors for finite monoids [17, Proposition 5.2]. It is easy to see that their proof also works for monoids whose size depends on , so long as each can be stored in a constant number of memory cells (i.e. bits) and the operator can be evaluated in constant time by a single processor.
Lemma 19 ([17, Proposition 5.2]).
Let be a monoid where each can be stored in bits and the operator can be evaluated in constant time by a single processor. For any , there is a dynamic algorithm for RangeEval() on a common CRCW PRAM, where
-
the size of the data structure is in ,
-
the initialization runs in parallel constant time on processors,
-
updates run in parallel constant time on 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 , alphabet , maximum size
-
Updates:
-
–
: Set to .
-
–
: Set to .
-
–
-
Queries:
-
–
: Return .
-
–
: Return .
-
–
According to Theorem 1, we can solve DynamicLce on processors. It remains to show that we can solve StringEquality on processors as well.
Lemma 20.
For any , there is a dynamic algorithm for StringEquality on a common CRCW PRAM, where
-
the size of the data structure is in ,
-
the initialization for runs in parallel constant time on processors,
-
updates run in parallel constant time on processors, and
-
queries run in parallel constant time on 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 with void characters, the position in general does not correspond to . Instead corresponds to where is the number of non-void characters in .
We use an instance of RangeEval() with an appropriate monoid to maintain which position in corresponds to which position in .
Proof.
We show that we can use the algorithm for DynamicLce from Theorem 1 to solve StringEquality.
Let be the strings from StringEquality. The algorithm uses an instance of DynamicLce with the concatenated string . It furthermore maintains the lengths of and .
The algorithm answers queries by checking if holds.
The algorithm uses instances of RangeEval() to maintain which position of corresponds to which position of . We define a binary string that marks which positions in are not . Let be a binary string with and if and only if . Then, for any index of , it follows that is the corresponding index in .
Let be the natural numbers from 0 to and let be addition modulo . According to Lemma 19, RangeEval() can be maintained on processors. We use the binary string as the underlying sequence of monoid-elements for RangeEval(). A query then returns, for any index of , the corresponding index in .
The algorithm processes an update by first using the instance of
RangeEval() to determine which index of corresponds to the first non-void-character before .
It updates that instance RangeEval() with , increments by one, then updates DynamicLce with .
Updates are processed similarly.
For updates to (updates and ), the algorithm uses a second instance of RangeEval() to maintain which positions in correspond to which positions in . Updates to are processed similarly to updates to .
We have shown that we can use our algorithm for DynamicLce alongside an algorithm for RangeEval() 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 that is larger then the current string. The future instance has maximum size 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 , then swaps over when it reaches length . It therefore builds over the course of at least updates, with processors per update. It is possible to build with maximum size for any underlying string in time on 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.
