Workbench Contract and Exact Oracle
Every matcher accepts Unicode strings text and pattern and returns sorted, zero-based starts, including overlaps. The empty pattern matches all $n+1$ boundaries; a pattern longer than the text has no matches. A short $O(nm)$ baseline checks every alignment and serves as the independent correctness oracle.
Instrumentation is separate from results. Preprocessing tables, comparisons, shifts, fallbacks, hash collisions, and bit states belong in trace events so enabling visualization never changes the answer.
Every registered matcher must return exactly the naive oracle’s sorted overlapping positions, including empty and oversized patterns. Probabilistic filters may skip work, but an exact matcher must verify every reported hash candidate.
Algorithm Implementations
The registry below exposes naive, KMP, Z, verified Rabin-Karp, Horspool, Shift-And, and an optimized runtime adapter through one contract. The adapter is named runtime because an interpreter may select Two-Way or another internal strategy; a portable Two-Way implementation should be registered only with independent critical-factorization tests.
Preprocessing and Scan Visualizations
A synchronized trace separates immutable preprocessing from scan state. KMP exposes prefix values and border length; Z shows its active box; Rabin-Karp shows rolling hashes and verification; Horspool shows the mismatch and chosen shift; Shift-And shows masks, state, and accepting bit. Each event retains shared alignment and action fields plus an algorithm-specific payload.
Correctness and Differential Testing
Differential tests send each generated case to every matcher and compare with the naive oracle. Record the seed, inputs, preprocessing state, and trace prefix on failure. Combine random alphabets and Unicode with adversarial periodic strings, long near-misses, empty inputs, word-boundary pattern lengths, and intentionally collision-prone Rabin-Karp configurations.
Metamorphic properties add coverage: prefixing text and expected positions by a symbol shifts old matches; appending a symbol absent from the pattern cannot create an earlier occurrence; duplicating text preserves matches inside each copy aside from new boundary-spanning matches.
Debug the Matcher
Use text ababababac and pattern ababac. The correct prefix table is [0,0,1,2,3,0], and the sole match begins at index 4. Corrupt the final entry to 3. A first-match test can still pass, but after a report the matcher resumes with a nonexistent border.
Check the table invariant pattern[:pi[i]] == pattern[i-pi[i]+1:i+1]. At index 5, prefix aba differs from suffix bac, exposing the defect. Recompute from pi[4]=3: c mismatches twice along the fallback chain and reaches zero. Restore pi[5]=0, then rerun overlapping and back-to-back cases. Output tests alone can miss bad preprocessing states, so validate table invariants independently.
Benchmark Report
Benchmark only verified implementations. Separate preprocessing, scanning, and end-to-end time; warm up the runtime, randomize algorithm order, repeat trials, and report medians with environment metadata. Record comparisons, fallbacks, shifts, hash hits, verified collisions, processed words, output size, and peak memory alongside throughput.
The matrix below defines reproducible regimes rather than inventing machine-dependent timings. Populate timing columns by running the harness on the target runtime.
| Corpus regime | Construction | Match density | Primary metric | Expected diagnostic result | Algorithms favored |
|---|---|---|---|---|---|
| Random large alphabet | $n=1{,}000{,}000$, $m=32$, 64 symbols | Near zero | Throughput and comparisons per byte | Late mismatches permit large shifts | Horspool or runtime |
| Repetitive near-miss | a repeated then b; pattern ends in c | Zero | Comparisons and fallbacks | Naive repeats work; prefix methods remain linear | KMP, Z, or runtime |
| Dense overlaps | Text and pattern both all a | $n-m+1$ | Output throughput | Reporting dominates | KMP, Shift-And, or runtime |
| Periodic text | Repeated ab; pattern ends in ac | Low | Shift and fallback distribution | Period structure stresses reuse | KMP, Z, or runtime |
| Short pattern | $m\le64$ over a small alphabet | Variable | Words processed per byte | One integer tracks all prefix states | Shift-And |
| Long pattern | $m=4096$ in multi-megabyte text | Low | Preprocessing and memory | Big-integer bit state grows; linear arrays stay stable | KMP, Z, or runtime |
| Collision laboratory | Small hash modulus with adversarial collisions | Controlled | Hash hits versus verified matches | Verification preserves exact output | Rabin-Karp |
| Many texts, one pattern | One pattern searched in 1,000 texts | Variable | Amortized preprocessing | Reusable tables reduce total cost | KMP, Horspool, Shift-And |
| Unicode code points | ASCII, combining marks, and emoji | Controlled | Semantic agreement and throughput | Agreement requires a fixed symbol-unit contract | Any verified matcher |