Comparison Semantics and Tokenization
A comparison algorithm operates on tokens, so bytes, code points, grapheme clusters, words, lines, and syntax nodes define different optimization problems. Specify normalization, case policy, whitespace handling, edit costs, move detection, and deterministic tie-breaking before computing a score. Preserve original slices for display even when normalized tokens are compared.
Tokenization changes the optimization problem, not merely its presentation: a minimum line edit script need not induce a minimum word or grapheme edit script. Record the unit, normalization, cost model, and tie-breaking policy with every score or diff.
LCS and Edit-Script Engines
LCS maximizes retained ordered tokens and yields a shortest insertion/deletion script. Levenshtein instead minimizes insertion, deletion, and substitution costs. Full tables support direct traceback in $O(nm)$ space; rolling rows compute only the score in linear space, while Hirschberg reconstructs an LCS in $O(nm)$ time and $O(\min(n,m))$ auxiliary space.
Alignment and Similarity Modes
Different objectives can give similar scores but different witnesses. LCS models insertions and deletions; Levenshtein permits substitution; Needleman-Wunsch aligns complete sequences; Smith-Waterman finds the best local region; Gotoh distinguishes gap opening from extension. Publish raw objectives with normalized scores because denominators such as maximum length, total length, and alignment length are not interchangeable.
| Mode | Objective | Operations | Output | Complexity | Best use |
|---|---|---|---|---|---|
| LCS diff | Maximize retained order | Insert, delete | Common subsequence and hunks | $O(nm)$ time | Human-readable diffs |
| Levenshtein | Minimize unit or weighted edits | Insert, delete, substitute | Distance and script | $O(nm)$ time | Typographical comparison |
| Damerau-Levenshtein | Include transposition | Four edit types | Distance and script | Usually $O(nm)$ | Spelling errors |
| Needleman-Wunsch | Maximize global score | Match, mismatch, gap | End-to-end alignment | $O(nm)$ | Globally related sequences |
| Smith-Waterman | Maximize local score | Match, mismatch, gap, restart | Best local region | $O(nm)$ | Shared regions in unrelated context |
| Gotoh | Apply affine gap costs | Match, mismatch, gap open/extend | Global or local alignment | $O(nm)$ with three states | Long contiguous gaps |
| Hirschberg | Reconstruct with divide and conquer | Objective-dependent | Linear-space witness | $O(nm)$ time, linear space | Large traceback problems |
Approximate Dictionary Search
A BK-tree indexes terms under an integer metric. At a node distance $d$ from query $q$ and threshold $k$, the triangle inequality permits only child edges in $[d-k,d+k]$. Exact distance verifies candidates. For small fixed thresholds, intersecting a Levenshtein automaton with a trie shares dictionary prefixes; q-gram indexes offer another filter for large dictionaries.
flowchart TD
A["Raw query"] --> B["Normalize and tokenize"]
B --> C{"Candidate index"}
C --> D["BK-tree range traversal"]
C --> E["Trie × Levenshtein automaton"]
C --> F["q-gram filter"]
D --> G["Candidate terms"]
E --> G
F --> G
G --> H["Exact distance and traceback"]
H --> I{"Within threshold?"}
I -- "No" --> J["Discard"]
I -- "Yes" --> K["Stable rank and return witness"]
Evaluation and UX
Verify optimal costs against a trusted table and confirm that applying every reconstructed script yields the target. Test identity, symmetry for symmetric costs, metric properties where applicable, Unicode normalization, deterministic ties, empty inputs, and agreement between full and rolling distance computations. For large files, trim common ends, anchor unique lines, refine changed blocks at finer granularity, and use Hirschberg or justified banding.
Which Diff Is Better?
Before: prepare(), validate(), save(), notify(). After: validate(), prepare(), save(), notify().
Two optimal cost-two LCS scripts exist. Diff A deletes the old prepare() and inserts it after validate(); Diff B inserts validate() first and deletes its old occurrence. Both reconstruct the same target, but one reads as moving prepare down and the other as moving validate up.
Choose using explicit UX criteria—few hunks, preservation of unique anchors, nearby stable context, and deterministic ties—not edit cost alone. Repeating the exercise at character granularity changes the optimization problem and may obscure the line-level reorder.