1 Introduction
Text correction systems typically rely on a core step where good correction suggestions are generated for garbled input words. The basis is a background lexicon which is assumed to contain – by and large – all correct words or phrases. Approximate search in the lexicon is then used for finding the correct words which are most similar to the garbled input words. In most applications the background lexicon is very large, which means that efficiency of the proposed methods is a central issue. Today, most competitive methods take advantage of finite state methods to represent the lexicon (Bunke Reference Bunke1993; Oflazer Reference Oflazer1996). Recent approaches also use automata to efficiently determine word similarity (Mihov and Schulz Reference Mihov and Schulz2004).
The background for the work presented in this paper are text correction methods that try to improve optical character recognition (OCR) on historical document collections, preserving the original spelling found in the document. The design of such methods is motivated by recent programs in the field of digital libraries that include historical document collections in their focus such as Google Books (books.google.com), IMPACT (www.impact-project.eu) and Europeana (www.europeana.eu). In this new context it can no longer be assumed that a complete lexicon of all correct words is available. Due to historical language change and missing normalization, the vocabulary found in old printed documents is full of distinct spelling variants. This effect becomes more and more central and eye-catching when moving to documents of older periods. Special lexica for historical language can only offer restricted coverage since language variation differs from century to century, from region to region, and even from one document to another.
As an alternative, special matching approaches have been suggested where possible historical spelling variants are derived from modern words in a rule-based way. These approaches make use of rewrite rules or patterns that locally explain the difference between modern and old spelling of a word. Patterns are applied to modern words to produce distinct historical spellings. The complete historical vocabulary is then described in terms of a modern lexicon of the given language and a characteristic set of patterns to be applied.
In this paper we suggest an algorithm for generating correction suggestions for misrecognized words of historical documents based on such a rule-based model for historical language. The lexicon of modern words and the set of patterns for a historical language are used as background resources. Given an garbled token as input and a small bound k, the algorithm efficiently generates all historical spelling variants of modern words where the Levenshtein distance between the input token and the variant does not exceed k. The algorithm is used as a core component of a system for postcorrection of OCR results on historical document collections to be built by our group in the EU project IMPACT.
The paper is structured as follows. After some formal preliminaries in Section 2 we introduce the exact algorithmic problem considered in the paper in Section 3. We show how our background scenario can be described in terms of a model with two channels. The first channel accounts for the distinction between modern and historical spellings of words. The second channel introduces errors via optical character recognition. Receiving the result of the second channel as input, we want to predict the underlying output of the first channel.
Section 4 shows how to efficiently enumerate all spelling variants of modern words that can be derived using patterns. The procedure, which is based on finite-state techniques, uses the lexicon of modern words and the set of patterns as input. It is flexible in the sense that distinct lexica and sets of patterns can be used at low computational costs. This is interesting in application scenarios where documents from distinct historical periods/regions are processed, each coming with specific characteristic sets of patterns.
In Section 5 we show how universal Levenshtein automata (Mihov and Schulz Reference Mihov and Schulz2004) can be used to control, given an garbled token w as input, the generation of spelling variants in a way that only good correction suggestions for w are produced. At the same time, this form of control drastically improves efficiency since the generation of useless variants is avoided.
The evaluation results presented in Section 6 show that our algorithm is highly efficient. We used a lexicon for modern German language with 2,336,165 entries and a pattern set for German historical language including 140 patterns. The search time depends on the bound for the maximal Levenhtein distance k between the input word and the correction suggestions. For k = 0, 1, 2 the generation of all suggestions approximately takes 0.2, 0.9, and 17 ms, respectively.
We finish with a description of related work in Section 7 and a brief conclusion.
2 Formal preliminaries and terminology
We consider words composed over a finite alphabet Σ called the text alphabet. Σ+ contains all nonempty words over Σ, Σ* additionally contains the empty word ε. The length of a word w ∈ Σ* is written |w|. Concatenation of words v, w ∈ Σ* is written v ⋅ w or vw. For sets of words V, W ⊆ Σ* let V ⋅ W = {vw | v ∈ V, w ∈ W}. Finite state automata (FSA) and deterministic FSA over the text alphabet Σ are defined as usual (see, e.g. Roche and Schabes Reference Roche and Schabes1997). Deterministic FSA are formally presented as quintuples A = (Σ, Q, δ, s, F) where Q (F) denotes the set of (final) states, s is the initial state and δ: Q × Σ → Q is the partial transition function. By δ*: Q × Σ* → Q we denote the generalized transition function. For convenience we repeat the notion of a path, which is needed later.
Definition 2.1
Let A = (Σ, Q, δ, s, F) be a deterministic FSA. A path of A of length l from q 0 ∈ Q to ql ∈ Q is a sequence
where qi ∈ Q (0 ≤ i ≤ l), Σi ∈ Σ and δ(qi, Σi) = q i+1 (0 ≤ i ≤ l − 1). The path π has the label label(π) := Σ0 ⋅ Σl−1. Two paths π1 and π2 of A can be concatenated (in the obvious way) if the target state of π1 is equal to the initial state of π2. We write π1 ⋅ π2. Obviously label(π1 ⋅ π2) = label(π1) ⋅ label(π2).
In what follows we assume that a finite set D ⊆ Σ* is given. In our application scenarios, D represents the set of words in a lexicon for a given modern language.
Definition 2.2
A pattern is a simple rewrite rule composed of two strings α, β ∈ Σ+ written in the form α ↦ β.
Using a pattern α ↦ β a string w of the form xαy can be rewritten to v = xβy.
Definition 2.3
Let P denote a set of patterns, let u ∈ D, let v ∈ Σ*. If for some n ≥ 0 the word u can be written in the form u 0α1u 1α2 . . . αn u n (ui ∈ Σ*) for patterns (αi ↦ βi) ∈ P, then v = u 0β1u 1β2 . . . βnun is called a spelling variant of u. The hypothetical lexicon determined by D and P is the set of all spelling variants of words in D.
Note that for the derivation of spelling variants patterns are applied in parallel and left-hand sides of patterns in words u must not overlap.
We are often interested in keeping track of the positions where patterns are applied when rewriting a modern word u = u 0α1u 1α2 . . . αnun to a spelling variant v.
Definition 2.4
Let u, v as above, let ji = |u 0α1 . . . u i−1|. Assuming that ji is the position where pattern αi ↦ βi is applied, we call τP = 〈α1 ↦ β1, j 1〉, . . ., 〈αn ↦ βn, j n〉 the pattern trace of the derivation of v from u.
We write
to indicate that the spelling variant v is derived from u using pattern trace τP.
The standard Levenshtein distance between two words v, w ∈ Σ* is the minimal number of single-letter deletions, insertions or substitution that are needed to transform v into w. Single-letter deletions, insertions and substitutions are called edit operations. We write dL(v,w) for the Levenshtein distance of the strings v,w ∈ Σ*. In the literature, a number of other word similarity measures besides the standard Levenshtein distance have been used for approximate search in dictionaries (cf. Section 7). As will be explained in detail, the algorithm presented here depends on a special method to determine word similarity based on the standard Levenshtein distance, though other related distance measures would be feasible as well.
By a Levenshtein trace we mean a description τL, which states which kind of edit operations are applied at which positions of v to produce w. We only consider Levenshtein traces that use a minimal number of edit operations.
3 Background scenario and algorithmic problem
Let D denote a lexicon of modern words, let P denote a set of patterns. We consider a scenario where words u ∈ D are garbled following a two-channel model. The first channel (‘spelling variation’) transforms u to a spelling variant v of u using patterns in P. The exact transformation is described in terms of a pattern trace τP. The second channel (‘error channel’) introduces errors by applying edit operations, which results in a possibly erroneous version w of v. The latter process is described in terms of a Levenshtein trace τL. We write
to capture the complete process. An important practical instance of this scenario is the situation where we analyse the result of applying OCR to historical documents. The first channel describes the distinction between modern and historical spelling. The second channel takes recognition errors into account.
In what follows, a quintuple of the form
is called an interpretation of w. In practice we are just given w as input. In this paper we study the following:
Algorithmic problem: Assume we are given a lexicon of modern words, D, a set of patterns P and a small bound k for the Levenshtein distance. For an input word w ∈ Σ*, compute all interpretations
where u ∈ D and d L(v,w) ≤ k. The trace τLmust be minimal in terms of the number of edit operations used.
As a simplification we consider the situation where we are not interested in u, τP and τL and just want to compute, given w ∈ Σ*, the set of spelling variants v where d L(v,w) ≤ k (simplified algorithmic problem).
A solution for the simplified algorithmic problem helps to compute a set of correction suggestions for garbled tokens w. A solution for the full algorithmic problem in addition helps to rank correction suggestions (e.g. when using weighted patterns and/or edit operations) and to collect statistical evidence for properties of the two channels.
4 Representing and traversing hypothetical lexica
Assuming that the lexicon of modern words D and the set of patterns P are given we first look at the simplified algorithmic problem. This section presents a preparatory step, the focus is on the first channel (spelling variation). We introduce a method for enumerating all entries of a hypothetical lexicon. The main advantage of the method is its flexibility. The lexicon of modern words D and the set of patterns P are inputs to the method and can be changed in a simple manner at low computational costs. We avoid an explicit representation of the full hypothetical lexicon, which might lead to storage problems, see Remark 4.5. The three subsections introduce a product construction which leads to a ‘virtual representation’ of the hypothetical lexicon that can be used for enumerating all spelling variants. In the following section (Section 5) we will then combine the virtual representation of the hypothetical lexicon with techniques described by Mihov and Schulz (Reference Mihov and Schulz2004) to solve the simplified algorithmic problem defined in Section 3. We will then see that only a small part of the hypothetical lexicon is visited in the complete procedure.
4.1 Virtual paths of the lexicon automaton
In the following we assume that the base lexicon D is given in the form of a deterministic FSA AD = (Σ,QD,δD,sD,FD). Figure 1 illustrates how AD can be extended to a nondeterministic FSA AH that represents the hypothetical lexicon. The set of states of AH is equal to the set of states of AD. All transitions of AD are also transitions of AH. The needed additional transitions are captured by the relation
It is trivial to see that for each word w in D with one or several occurrences of left-hand sides of patterns in P the new automaton AH recognizes the variant obtained from a parallel application of the rewrite patterns. Conversely, each word v accepted by AH can be rewritten into a word accepted by AD by a reverse parallel application of patterns, hence v is in fact a spelling variant.
Additional transitions to represent hypothetical lexica. Here three patterns are considered: ei ↦ ey, i ↦ j, i ↦ ie.

As we mentioned before, we want to avoid the explicit computation of AH. In our approach the transitions in Δ, which are called virtual transitions, are not explicitly added to AD. In a way to be explained later, virtual transitions are simulated by a special mechanism that is used for traversing AD.
A virtual path is obtained from a path π in AD by replacing (zero or some) subpaths π′ = (p, . . ., q) of π where the label of π′ represents the left-hand side α of a pattern α → β ∈ P by a a single virtual transition (p, β, q). Replaced subpaths must not overlap. The new path
derived from π is called a variant of path π. The label of
is called a variant of the label of π.
It is important to draw the analogy between these definitions and those in Section 2. When looking at the corresponding labels, the substitution of subpaths of a path π of AD by virtual transitions is equivalent to applying patterns to the label of π. Hence the labels of all variants of a path π exactly describe the set of all spelling variants of the label of π.
4.2 Generating all spelling variants
In the following we present an algorithm that enumerates all spelling variants, traversing the lexicon automaton AD in a depth first manner. Let us briefly recall a standard procedure for completely traversing an acyclic deterministic FSA A with initial state s and transition function δ. The procedure is based on a single stack Γ. Entries of Γ are pairs of the form (q,u) where q is a state of A and u ∈ Σ* is the label of a path from s to q. At the beginning, (s,ε) is pushed on the stack (Initialization). As long as Γ is not empty, we treat the top element (q,u) of Γ by applying three steps:
(1) If q is final, then we output u.
(2) For all letters Σ ∈ Σ where δ(q,Σ) is defined we recursively call the procedure after pushing (δ(q,Σ),uΣ) on top of Γ.
(3) We pop (q,u) from Γ.
It is simple to see that the output is the set of words accepted by the automaton.
In our context we modify the procedure. Entries of the stack Γ now have the form (q,u,V) where q, u are as before and V ⊆ Σ* is the set of all variants of u. The computation of the sets V is based on an inductive definition which is found in the following description.
Basic procedure: At the beginning, (sD, ε, {ε}) is pushed on the stack Γ (Initialization). As long as Γ is not empty, we treat the top element (q,u,V) of Γ applying three steps:
(1) If q is final, then we output all elements of V.
(2) For all letters Σ ∈ Σ where δD(q,Σ) is defined we recursively call the procedure after pushing (δD(q,Σ),uΣ,V′) on top of Γ. Here V′ contains V ⋅ {Σ} and in addition all strings of the form v 1 ⋅ β where for some pattern (α → β) ∈ P the string uΣ can be represented in the form u 1 ⋅ α such that v 1 is a variant of u 1.
(3) We pop (q,u,V) from Γ.
In Step 2, the additional strings take into account the situation where uΣ has a suffix α representing the left-hand side of a pattern (α → β) ∈ P. It is important to note that there can be more than one pattern with left-hand side α. Also, uΣ can have suffixes of different lengths matching a left-hand side of a pattern.
For computing V′, the central problem is to efficiently recognize the suffixes α of uΣ = u 1 ⋅ α that represent left-hand sides of patterns in P. In fact, once α and thus u 1 and β are known, we go back to the unique element (p,u 1,V 1) of the stack determined by u 1. Here V 1 lists all variants v 1 of u 1. We use V 1 to compute the additional variants of the form v 1β of V′. The efficient recognition of all suffixes α is described in the next subsection. Some further remarks are in order.
Remark 4.1
In the Basic Procedure, the cardinality of the set V can grow exponentially in the length of the string u. In the next section, where we present the full solution to our algorithmic problem, we shall see that this growth is avoided in practice due to an additional control mechanism.
Remark 4.2
The Basic Procedure is used for solving the simplified algorithmic problem, in a way to be explained in the next section. A straightforward modification can be used for solving the full algorithmic problem. We not only store the set of variants V of the label u of the current path but store for each v ∈ V also the pattern trace which encodes the transformation of u into v. Each spelling variant in the output set then comes with a pattern trace.
Remark 4.3
The Basic Procedure may generate duplicates in the output. When we solve the general algorithmic problem and take pattern traces into account, then there are no duplicates in the output.
4.3 A finite-state data structure to represent the pattern set
In the above description of the Basic Procedure, the efficient recognition of situations where a suffix of the current path can be replaced by a virtual transition was left as an open issue. The solution presented in this section treats this problem as a special variant of multiple string search. In our case, the set of search strings is the set of all left pattern sides L(P) = {α | (α ↦ β) ∈ P}, and we want to find these search strings on the fly as suffixes of u, the label of the current path reached in the lexicon automaton AD. This means that, unlike in a traditional string search application, the search string u is not a static sequence of symbols that can be processed from left to right, but a string dynamically changing with the backtracking procedure.
One classical method for multiple string search that suits to this special application in a natural way is the Aho–Corasick Algorithm (Aho and Corasick Reference Aho and Corasick1975). In this algorithm, the set S of search strings is compiled into a trie TS which is enriched in a specific way. When searching strings of S in an input text, the current status of the search is encoded in a single active state of TS. The following description of the search method, where we use the set L(P) as our set of search strings and replace the input text by the lexicon automaton AD, will make clear how this active state can be stored and updated in parallel with each single step of the traversal of AD.Footnote 1
Data structure. In a pre-processing step a structure
is computed. Σ, QAC, δAC and sAC represent the usual components of a trie automaton which recognizes exactly the strings in L(P) (see Figure 2 for an illustration). The set of final states F AC is defined later.
Aho-Corasick trie for P = {t ↦ tt, t ↦ th, tt ↦ t, ff ↦ f, axf ↦ xff, x ↦ y, xh ↦ x}. The failure function is indicated by dotted arrows.
Apart from the classic components of a deterministic FSA, the so-called failure function fAC and the output function oAC are defined. The failure function is used as an ingredient to define the set of final states.
Following Aho and Corasick (Reference Aho and Corasick1975) we say that a string u represents state q (u
q) if the path from sAC to q has label u. Recall that the correlation between an arbitrary state q and the path leading from the start state to q is always nonambiguous in a trie structure.
The failure function fAC : QAC ↦ QAC maps each state q ∈ QAC (s
q) to the unique state q′ (s′
q′) where s′ is the longest proper suffix of s that is also a prefix of some search string in L(P).
The set of final states FAC contains all states represented by a search string in L(P) and is closed under iterative applications of the following rule: a state q is final if fAC(q) is final.
The output function oAC : FAC ↦ 2P maps each final state q ∈ FAC to the subset of patterns (α ↦ β) where α
q. Here α is unique, but P can contain several patterns with left-hand side α.
Using AC in the Basic Procedure. Consider a traversal of AD, let (q,u,V) denote the top entry of the stack Γ, let s denote the longest suffix of u that is also a prefix of some search string in L(P). The suffix s can be seen as the most promising beginning of a match. With the element (q,u,V) on the stack Γ we associate the state qAC u ∈ QAC represented by s as the current active state of AC.
The actual computation of the active state proceeds as follows. For initialisation we define qAC ε := sAC. Assume we have found qACu which is represented by s. If the traversal procedure then pushes (δD(q,Σ),uΣ,V′) as new top element of the stack, then qAC uΣ is computed in the following way:
• If δAC(q ACu, Σ) is defined, then we have qACuΣ = δAC(q ACu, Σ). In this situation sΣ is a prefix of a search string in L(P).
• If, on the other hand, δAC(q ACu, Σ) is undefined (the current longest prefix s can not be extended with σ), then we apply fAC starting from qACu in an iterated manner until we
(1) either reach a state p with an outgoing σ-transition (possibly p = sAC), or
(2) arrive at the initial state sAC, which in this subcase does not have a σ-transition.
In Case 1 we define qAC uΣ := δAC(p, Σ), in Case 2 we define qAC uΣ := sAC.
Readers familiar with the Aho–Corasick algorithm will note that this is the classical procedure for updating the active state in AC.
Example 4.4
As an illustration consider the AC trie depicted in Figure 2. Here we have qACta = 3, because ‘a’ (which represents State 3) is the longest prefix of all search strings that is also a suffix of ta. When adding character ‘x’ to ‘ta’, it is easy to extend the longest prefix and the updated position in AC, simply by following the ‘x’-transition to state qAC tax = 4. On the other hand, when moving to ‘taf’ we have to follow the failure transition from State 3. Since State 0 has the f-successor 8 we have qAC taf = 8.
Recognizing left pattern sides. If qACu ∈ FAC, this indicates that some search string was found as a suffix of u. Recall that not only all states q which are represented by some k are final, but also those states q where fAC(q) ∈ FAC. For example, State 4 in Figure 2 is final although ‘ax’ is not a search string – but the failure function points to ‘x’ which is the matching search string. Also, ‘tt’ representing the final State 2 is a search string, but following the failure transition to State 1 reveals another, shorter search string ‘t’ that matches at the same position. At any position q = qACu ∈ FAC, the set P match of patterns α → β where α is a suffix of u can be computed using this algorithm:
(1) Add all elements of oAC(q) to P match.
(2) Apply fAC to q: q := fAC(q).
(3) Repeat Steps 1 and 2 as long as q is a final state of AC.
The details of how the trie structure and the failure and output function are computed can be read in Aho and Corasick (Reference Aho and Corasick1975), see also Navarro and Raffinot (Reference Navarro and Raffinot2001). The slight differences between those descriptions and the method as described here (e.g. the output function returning patterns instead of matched strings) are all obvious, so the construction algorithm is not repeated here.
Remark 4.5
At the end of this section let us add a comment. Instead of using the above virtual representation of the hypothetical lexicon in terms of the lexicon automaton and the Aho–Corasick trie, the reader might suggest to compute the full hypothetical lexicon in an offline step and to compile it into a minimal deterministic FSA. However, there are two problems with this idea, memory space and flexibility. We briefly comment on these points.
(1) Memory space. In practice, hypothetical lexica grow very large, and so do their representations as deterministic FSA. Table 1 shows the sizes of hypothetical lexica as they are used in various applications for the handling of historical German language. The base lexicon of modern words contains 2,336,165 inflected forms, the rule set consists of 140 patterns. We ignored the need to store the traces with each variant and built minimized deterministic FSAs, restricting ourselves to spelling variants involving not more than 1 (2, 3, respectively) pattern applications. Even with only one pattern application, more than 114 million spelling variants had to be stored, using 124MB of disk space. For up to three pattern applications, almost 50 billion variants were produced, requiring more than 1,000 MB of memory. The storage of the respective trace with each spelling variant (in order to solve the full algorithmic problem) will be even more problematic.
Sizes of explicitly built minimal deterministic FSAs of hypothetical lexica on the basis of a lexicon containing 2,336,165 German full forms and a rule set of 140 patterns describing historical spelling variation

Note: The application of patterns to each word was restricted to 1,2,3 patterns respectively.
(2) Flexibility. Regardless of the question if such memory requirements are acceptable, or if a nondeterministic variant of such an automaton could be represented in a more compact way, a second good argument not to preprocess hypothetical lexica is flexibility. If we assume that such data structures can usually not be created at runtime, then the parameters for their construction – base lexicon, set of patterns and an upper bound for pattern applications – have to be determined beforehand. Distinct automata will have to be created for each required combination of these parameters.
5 Approximate matching in the hypothetical lexicon
In this section we add to the Basic Procedure described in Section 4 the last missing component that is needed to solve the algorithmic problem introduced in Section 3. We first show how to solve the simplified algorithmic problem and then comment on the modifications that are necessary to solve the full problem.
Given the lexicon of modern words D, the set of patterns P, a bound k, and an input string w we want to find all spelling variants v of entries u in D such that d L(v,w) ≤ k.
Mihov and Schulz (Reference Mihov and Schulz2004) consider the simpler problem of how to find all entries u of the lexicon D such that d L(u,w) ≤ k. We briefly recall this procedure, which can be adapted for our purposes. The approach of Mihov and Schulz (Reference Mihov and Schulz2004) is based on the concept of a universal Levenshtein automaton. A universal Levenshtein automaton ∀k of degree k can be used to decide for any pair of words u,w if d L(u,w) ≤ k. The letters σ of u are translated into bitvectors χΣ of restricted length (depending on k) which encode the distribution of occurrences of σ in subwords of w. For the exact encoding we refer to the original paper (Mihov and Schulz Reference Mihov and Schulz2004). In what follows we write χΣ1 . . . Σn for a sequence χΣ1 . . . χΣn. The sequence of bitvectors χu obtained from the letters of u is used as the input of ∀k. It is accepted iff d L(u,w) ≤ k. In our context, one important aspect is that in the negative case, when the Levenshtein distance between u and w is too large, the traversal in ∀k often fails already after consuming some (translated) letters of u. In fact, the automaton ∀k represents a device that – when reading χu – at the earliest possible point detects that d L(u,w) > k.
In Mihov and Schulz (Reference Mihov and Schulz2004), the lexicon D is encoded as a deterministic FSA AD. To find all entries u of D such that d L(u,w) ≤ k, a complete traversal of AD is started. Each transition label σ represents a letter of a candidate word u to be found in D. Transition labels σ are translated into bitvectors representing occurrences of σ in subwords of w as above. In this way the traversal of AD is controlled using a parallel traversal of ∀k with translated labels as input. When we reach a final state both in AD and in ∀k on a path with label u we know that d L(u,w) ≤ k. The property mentioned earlier guarantees that in most paths we soon reach a point where the traversal in ∀k can not be continued. Hence only a small part of AD is visited in practice.
This idea can be generalized to control the generation of spelling variants in the Basic Procedure. In this procedure, all spelling variants of modern words in D are produced; triples (q,u,V) store with each prefix u of a word in AD the set V of variants of u. For each variant v ∈ V we now maintain a parallel run of ∀k using χv as input. At each step of the traversal we store for each v ∈ V the state of ∀k reached with input χv. If for a variant v the parallel traversal of ∀k leads to failure we delete it. In what follows, all other variants are called ‘promising’. In the new procedure, instead of storing all variants of u the triples (q,u,V) now only store ‘promising’ variants. In practice, small bounds k are used and the set of promising variants remains small (cf. Remark 4.1). When we reach a final state in AD we check for each v ∈ V if the parallel run in ∀k has also lead to a final state. In the positive case we output v.
It should be noted that we cannot immediately start backtracking as soon as the set of promising variants V of the top triple of the stack is empty. Recall that in the basic procedure, when we add (δD(q,Σ),uΣ,V′) on top of (q,u,V), the new set of variants V′ contains not only V ⋅ {Σ} but in addition all new variants of the form v 1β where uΣ can be represented in the form u 1α for α → β ∈ P where v 1 is a variant of u 1. This step may introduce new promising variants. In order to find the optimal time when backtracking can be started, let us look at the depth of qAC uΣ in the Aho-Corasick trie AC, that is, the length of the string representing qAC uΣ. This depth denotes the length of the longest suffix of uΣ that matches a prefix in AC. If the top x elements of the stack have an empty third component V, and a new pattern application is supposed to bridge this gap, then the length of the longest suffix of uΣ that matches a prefix in AC must not be smaller than x. So, a sufficient condition for backtracking to be started is that the depth of the current active state qAC uΣ in AC is smaller than x.
Main procedure: At the beginning, (sD, ε, {ε}) is pushed on the stack Γ (Initialization). As long as Γ is not empty, we treat the top element (q,u,V) of Γ. If the condition for backtracking as formulated in the previous paragraph is fulfilled, we immediately pop (q,u,V) from stack Γ. Otherwise we apply three steps:
(1) If q is final, then we output all elements v of V where we have reached a final state in the parallel traversal of ∀k.
(2) For all letters Σ ∈ Σ where δD(q,Σ) is defined we recursively call the procedure after pushing (δD(q,Σ),uΣ,V′) on top of Γ. Here V′ contains all promising strings of the form vΣ for v ∈ V and in addition all promising strings of the form v 1 ⋅ β where for some pattern (α→ β) ∈ P the string uΣ can be represented in the form u 1 ⋅ α such that v 1 is a promising variant of u 1.
(3) We pop (q,u,V) from Γ.
In Clause 2 we assume that the states reached in ∀k with input χv 1 are storedFootnote 2, we only have to continue the run of ∀k with new input χβ.
Remark 5.1
It is straightforward but technically tedious to extend the Main Procedure in a way that it solves the full algorithmic problem, that is, to provide with each matching variant v also the respective modern word u as well as the pattern trace τP and Levenshtein trace τL. The modern word u is provided by the Main Procedure directly. As to τP, we mentioned in Remark 4.2 that it is simple to store with each generated variant v its pattern trace. For all matches v of the input token w, the Levenshtein trace τL can be computed using the well-known algorithm based on dynamic programming. An extended output procedure then yields the desired result.
In practical applications it is often useful to specify an upper bound of spelling variant patterns applied to one word. If the respective pattern traces are stored with each v ∈ V, it is again straightforward to limit the set of promising variants in that sense, using either a uniform penalty for all patterns or providing pattern-specific weights.
6 Evaluation
Experiments were made using a realistic setup for the processing of historical German language. We solved the full algorithmic problem. The lexicon D GER contains 2,336,165 modern German full forms. P GER is a set of 140 patterns modelling orthographical spelling variation in historical German texts. The rules were selected manually by linguists. The algorithm was implemented in C++ and tested on a linux machine with a Intel(R) Core(TM)2 Duo CPU, 1.80 GHz (using only one CPU).
From a large corpus of German texts from the seventeenth to the nineteenth century we extracted the list of all words (more than 200,000). From this list we randomly chose words of distinct lengths l (6 ≤ l ≤ 14) and introduced, again randomly, k (0 ≤ k ≤ 2) symbol substitutions, deletions or insertions. The result are sets Tk,l of test queries, each containing 1,000 tokens with the specified length and number of errors.
Table 2 shows the average time needed to compute all correction suggestions (in milliseconds) and the average number of correction suggestions obtained for all test sets Tk,l. The bound for the maximal Levenshtein distance between input token and correction suggestion was set to k for each test set. The results show that for k = 0 little more than 0.2 ms are needed to compute one query, quite independent of the lengths of the queries. Only for short words (lengths 6, 7) does the average number of candidates exceed 1. For k = 1,2 the size of the result sets depends heavily on the length of the query, as expected. In contrast to that, it is noteworthy that the average processing time remains quite stable in the region of 4–5 ms for k = 1 and, if the number for length 6 is considered an outlier, 53–55 ms for k = 2.
Average number of correction suggestions and time needed to compute all correction suggestions (in ms) for different bounds k = 0,1,2 of the maximal Levenshtein distance between input w and correction suggestion v
Note: Queries have length 6–14 and contain k errors.
In a second series of tests we restricted the number of patterns that are applied when deriving a historical spelling variant v from a modern word u. The maximal number of applications, denoted maxPat, was set to 0,1,2,3 and ∞. We prepared new test sets T k,_ (0 ≤ k ≤ 2), each containing 1,000 tokens of varying length. Again we garbled the tokens of the sets, randomly introducing k errors (k = 0,1,2).
Table 3 describes the average number of correction suggestions and the average processing time obtained for these test sets and bounds. It shows clearly that the restriction to a small number of variant patterns results in considerably smaller candidate sets and faster processing. For k = 2 the restriction to at most 2 variant patterns cuts reduces the average size of the candidate set from 625.8 to 348.0 and reduces the processing time from 53.3 to 36.7 ms.
Average number of correction suggestions and time needed to compute all correction suggestions (in ms) for different bounds k = 0,1,2 of the maximal Levenshtein distance between input w and correction suggestion v
Note: Correction suggestions are derived from modern words applying maxPat patterns at most.
6.1 Using backwards dictionaries for filtering
For conventional approximate search in dictionaries, Mihov and Schulz (Reference Mihov and Schulz2004) achieve considerable improvements by adapting a filter method known from approximate text search (Wu and Manber Reference Wu and Manber1992). The central idea of the adaptation is to avoid approximate search with high distance bounds in the front part of the lexicon automaton where it is usually densely branched. To this end, the search string is divided into two halves of approximately equal length: w = w 1 ⋅ w 2. Then, approximate search with distance bound k can be split up into several cases considering all possible distributions of up to k errors among the two halves.
For example, for k = 2, the following disjoint cases have to be considered:
(1) No error in w 1, up to 2 errors in w 2.
(2) 1 error in w 1, 0 or 1 error in w 2.
(3) 2 errors in w 1, no errors in w 2.
Mihov and Schulz (Reference Mihov and Schulz2004) explain in detail how the search first for w 1 and subsequently for w 2 can be organized using different distance bounds. For Case 1, as an example, the traversal is started accepting only exact matches for w 1. The much more expensive error-tolerant search only starts at points where w 1 was already found and the search space is narrowed down considerably. To produce the same effect for Case 3, where both errors are to be found in the initial half of the search string, reversed strings w 1−1 and w 2−1 are used as search strings and a backwards lexicon AD −1 containing all reversed strings of D: the search in AD −1 can now begin with w 2−1, not allowing any errors, and continue with distance bound 2.
This same filtering technique can be applied directly to the algorithm presented in this paper, taking some extra care where a pattern application affects both w 1 and w 2. Tables 4 and 5 show that the efficiency of our method is improved significantly using the filter: the method is about two times faster for very short words, and up two 8.5 times faster for very long words. Table 5 shows that for words of different lengths, distributed according to realistic text material, speed-up factors range from 3 to 4.8. Here, the processing time for one query with distance bound k = 1 does not exceed 1 ms.
7 Related work
Rule-based models for historical spelling variation have been proposed by several groups to enhance information retrieval on historical text collections (Pilz et al. Reference Pilz, Luther, Ammon and Fuhr2005; Archer et al. Reference Archer, Ernst-Gerlach, Kempen, Pilz and Rayson2006; Ernst-Gerlach and Fuhr Reference Ernst-Gerlach and Fuhr2006; Hauser et al. Reference Hauser, Heller, Leiss, Schulz and Wanzeck2006; Ernst-Gerlach and Fuhr Reference Ernst-Gerlach and Fuhr2007). The references also describe different approaches on how to obtain good rule sets for historical spelling variation. Brill and Moore (Reference Brill and Moore2000) presents a method to learn good rewrite rules for noisy channels from example material.
Gotscharek et al. (Reference Gotscharek, Neumann, Reffle, Ringlstetter and Schulz2009a) and Gotscharek et al. (Reference Gotscharek, Reffle, Ringlstetter and Schulz2009b) illuminate which lexical resources and rule-based methods are suitable for processing historical German language of different time periods. Experiments show that information retrieval and OCR results can be improved considerably by applying suitable lexica – especially for eighteenth and nineteenth century material, hypothetical lexica help to obtain the best results.
For approximate matching in lexica based on similarity measures, several solutions have been proposed. Most methods rely on a first coarse filter step to narrow down the set of possible candidates. For each of those, a more elaborated distance to the garbled word can be computed. In earlier works the first filter step is often realised using n-gram similarity (Owolabi and McGregor Reference Owolabi and McGregor1988).
The method described by Oflazer (Reference Oflazer1996) can easily deal with very large or even infinite lexica and is based on the Levenshtein distance instead of n-gram measures. It introduces the idea to walk through the lexicon organized as a finite state automaton, and to control the walk such that only prefixes that potentially lead to a correction candidate are generated. This idea is refined in Schulz and Mihov (Reference Schulz and Mihov2002) and Mihov and Schulz (Reference Mihov and Schulz2004) and lead to the concept of universal Levenshtein automata used earlier. In more recent work (Schulz, Mihov, and Mitankin Reference Schulz, Mihov and Mitankin2007), these automata are not restricted to the Levenshtein distance but can be configured to a customized rule set.
8 Conclusion
In this paper we introduced a method for computing correction suggestions for ill-formed words in historical documents, assuming that historical language variation is described in terms of a matching procedure and a lexicon for modern language. Correction candidates are historical spelling variants obtained from modern words via matching.
The method does not use a special lexicon for historical language and it avoids the explicit representation of all matching variants. Instead, only the lexicon of modern words and the set of rewrite rules for the matching procedure are used as input. The importance of this feature relies on the fact that the number of possible spellings in historical documents is astronomic, hence an explicit representation of all possible historical words seems difficult.
The method is very efficient and flexible in the sense that pattern sets and lexica can be changed rapidly at low costs. This is important in applications where document collections from distinct centuries and places are processed.
In the meantime, more complex applications have been built on top of the method. The first application makes use of the fact that our method is able to produce with each correction suggestion a pattern trace and an OCR trace. Given an OCR'ed historical text as input, the traces found for the best correction suggestions are used to collect hypotheses on frequent OCR errors and on the kind of historical language variation – the typical patterns – occurring in the document. This information can be used for improving OCR in a feedback loop. Furthermore, the method introduced in this paper is used as the kernel of a system for postcorrecting OCR results on historical document collections.
Acknowledgements
The author was supported by the EU project IMPACT, which provides a nice natural home for research on language processing with a focus on historical documents. The author also thank the anonymous referees for their helpful comments and suggestions.



