Skip to content

Add regex engine, edit distance, and Bloom filter playgrounds - #204

Merged
ianalloway merged 1 commit into
mainfrom
claude/playgrounds-2-729tge
Jul 27, 2026
Merged

Add regex engine, edit distance, and Bloom filter playgrounds#204
ianalloway merged 1 commit into
mainfrom
claude/playgrounds-2-729tge

Conversation

@ianalloway

Copy link
Copy Markdown
Owner

Three playgrounds in domains the site didn't yet cover: automata/compilers, dynamic programming, and probabilistic data structures. Consolidated into one PR per the new convention.

Route Playground
/regex Regex engine — pattern → NFA → DFA
/editdistance Levenshtein DP table with traceback
/bloom Bloom filter with live false-positive measurement

How each was verified

/regex — parses to a syntax tree, compiles to an NFA by Thompson's construction, determinises by subset construction, then walks the DFA with no backtracking (linear time). Verified differentially against JavaScript's own RegExp: 460 curated cases plus 5,200 randomly generated pattern/input pairs — zero mismatches. The classic (a|b)*abb compiles to 14 NFA states → 5 DFA states.

/editdistance — Wagner–Fischer with per-cell provenance so the traceback recovers an actual edit script. Verified against 10 textbook distances (kitten→sitting = 3, intention→execution = 5), the metric axioms over 300 random triples (symmetry, identity, triangle inequality), length bounds, and 400 traceback round-trips where applying the recovered script to the source reproduces the target at exactly the stated cost.

/bloom — bit array with k derived hashes, plus closed-form FPR and optimal-sizing helpers. Verified: never a false negative, empty rejects everything, saturated accepts everything, sizing for a 1% target measures 0.94%.

A real bug this caught

The Bloom filter initially looked better than theory — false-positive rates 2–3× below the formula. That's not luck, it's a symptom. Raw FNV-1a mixes its low bits poorly, and bucket selection is hash % m, which reads exactly those bits:

before after expected
chi-square (df=1023) 1335 ✗ 1016 ~1023
fill vs theory −29% ✗ within 1.9%
FPR vs theory 2–3× off ✗ within 9% 1.0×

Adding a MurmurHash3 fmix32 avalanche finalizer fixed all three. Worth noting because a filter that quietly under-collides would have looked perfectly fine on screen.

Checks

  • npm run lint0 errors (only the two pre-existing react-refresh warnings in badge.tsx / button.tsx)
  • npm run build — succeeds; all three pages confirmed to emit their own lazy chunk

One note on the diff: the Bloom page originally held the filter in a useRef and rebuilt it in an effect, which tripped react-hooks/refs (reading a ref during render). Since the filter is fully determined by (k, addedWords) it's now a useMemo — simpler and correct by construction rather than by discipline.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WgEKRuVdor8KhaiPkv38aQ


Generated by Claude Code

Three playgrounds in domains the site did not yet cover: automata and
compilers, dynamic programming, and probabilistic data structures.

- /regex  src/features/regex/engine.ts
  Pattern -> syntax tree -> NFA (Thompson's construction) -> DFA (subset
  construction), then a linear-time non-backtracking walk. Verified
  differentially against JavaScript's own RegExp: 460 curated cases plus
  5,200 randomly generated pattern/input pairs, zero mismatches.

- /editdistance  src/features/editdistance/levenshtein.ts
  Wagner-Fischer DP with per-cell provenance and traceback. Verified
  against 10 textbook distances (kitten->sitting=3, intention->execution=5),
  the metric axioms over 300 random triples, length bounds, and 400
  traceback round-trips where applying the recovered edit script to the
  source reproduces the target at exactly the stated cost.

- /bloom  src/features/bloom/bloom.ts
  Bit array with k derived hashes, plus the closed-form false-positive
  rate and optimal-sizing helpers. Verified: never a false negative, empty
  rejects everything, saturated accepts everything, and the measured
  false-positive rate tracks the theoretical formula.

  Testing caught a real bug here. Raw FNV-1a mixes its low bits poorly and
  bucket selection is hash % m, which reads exactly those bits, so the
  filter collided in structured ways: chi-square 1335 against df=1023, fill
  29% below theory, and false-positive rates 2-3x off. Adding a MurmurHash3
  fmix32 avalanche step brings chi-square to 1016, fill within 1.9% of
  theory, and the false-positive rate within 9% of the formula.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgEKRuVdor8KhaiPkv38aQ
@netlify

netlify Bot commented Jul 27, 2026

Copy link
Copy Markdown

Deploy Preview for ianalloway ready!

Name Link
🔨 Latest commit b615f5f
🔍 Latest deploy log https://app.netlify.com/projects/ianalloway/deploys/6a66bebfe510f100086535b5
😎 Deploy Preview https://deploy-preview-204--ianalloway.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@vercel

vercel Bot commented Jul 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ian-web-forge Ready Ready Preview, Comment Jul 27, 2026 2:13am

@ianalloway
ianalloway marked this pull request as ready for review July 27, 2026 02:14
Copilot AI review requested due to automatic review settings July 27, 2026 02:14
@cursor

cursor Bot commented Jul 27, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@ianalloway
ianalloway merged commit 472fa33 into main Jul 27, 2026
10 checks passed
@ianalloway
ianalloway deleted the claude/playgrounds-2-729tge branch July 27, 2026 02:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants