Definition · The adversarial pairFor a letter a and a different letter b, write a^k for the string of k copies of a. The adversarial pair at pattern length m is the text a^N for some N ≥ m together with the pattern a^(m − 1) b. Every character of the text is a; the pattern agrees with the text on its first m − 1 characters at every offset and disagrees on its last.
Theorem · The adversarial pair attains the boundOn the text a^N with the pattern a^(m − 1) b, the naive matcher makes exactly m(N − m + 1) comparisons and reports no match — which is the maximum possible for those two lengths.
Fix an alignment at offset i, which exists for 0 ≤ i ≤ N − m. For k < m − 1 the comparison of t[i+k] with p[k] is a against a and succeeds, so the inner loop reaches k = m − 1.
At k = m − 1 the comparison is t[i+m−1] = a against p[m−1] = b, which fails. So the alignment makes exactly m comparisons and reports nothing.
There are N − m + 1 alignments, each costing m, so the total is m(N − m + 1). That is the upper bound proved on the opening page of this module, so it is attained and cannot be improved.
□
At N = 24 and m = 5 this is 5 × 20 = 100, and the panel's status line says so in the strongest terms it has: the measured count IS the bound. No other preset in this kit produces that sentence.
The table that looks like a quadratic and is not one
The first table repeats whatever is in the box 1 to 6 times with the pattern unchanged. On the adversarial text it reads 100, 220, 340, 460, 580, 700 at n = 24, 48, 72, 96, 120, 144. Those differences are 120 each and the comparisons per character creep from 4.17 to 4.86. It is a line with a steep slope.
Theorem · A fixed pattern makes the bound linearWith m held constant, m(n − m + 1) is a linear function of n, and the naive matcher's count is at most that. So no family of inputs with a fixed pattern can make the comparison count grow faster than linearly in n.
This is the claim the kit's author withdrew after printing the numbers, and the docstring records the withdrawal. It is worth being precise about what was wrong: nothing in the six counts was mismeasured, and the growth really is much steeper than on English text. What was wrong was the word. Four and a half comparisons per character is a constant, and a constant times n is not quadratic however large the constant is.
The family where m grows with n
The second table is fixed rather than read from the boxes, because a text that reaches the bound has to be built and cannot be typed by accident. At each m from 3 to 11 it takes the text a^(2(m − 1)) and the pattern a^(m − 1) b, so n = 2(m − 1) and the pattern is half the text.
m n naive m(n - m + 1) per character KMP
3 4 6 6 3/2 6
5 8 20 20 5/2 12
7 12 42 42 7/2 18
9 16 72 72 9/2 24
11 20 110 110 11/2 30
Read the arithmetic rather than the shape. The alignment count is n − m + 1 = 2(m − 1) − m + 1 = m − 1, each alignment costs m, so the total is m(m − 1) and equals the bound in every row. Per character that is m(m − 1)/(2(m − 1)) = m/2, which grows without limit as the family is extended. KMP's column is 3(m − 1), which is 1.5n: flat per character, in every row, for ever.
That is the honest form of the quadratic claim. It is not “naive matching is quadratic”, which is about an algorithm and is false on almost every input anyone types. It is “there is a family of inputs on which naive matching's count is a constant times the product of the two lengths, and that family is exhibited here”. The lower table is the exhibit and the upper table is not.
Horspool, for contrast, is at its best here
The third matcher takes 20 comparisons on the opening text, five times fewer than naive's 100, and m − 1 in every row of the family table. Its shift table sends it forward by 1 each time, but it compares the window from the right, so it meets the b first and fails immediately. The sibling lesson “The Text Where Nothing Is Skipped” reverses the pattern's letters and gets 130 comparisons on 30 characters, which is the same algorithm at its worst on almost the same text.