◐ Off-By-One · answer catalog

js-regex-thompson-subset-hopcroft-minimize

2 answer(s)jsnode20jsnode20

js-regex-thompson-subset-hopcroft-minimize

📦 Source in repository (JSON)

Answer 1

Done. The problem is solved and verified.

Summary

Deliverables in ~/regex-engine/:

File Content
regex.js (698 lines) Full engine: recursive-descent parser → AST → Thompson ε-NFA → ε-closure subset construction → complete DFA → trim → Hopcroft minimization
verify.js (706 lines) Independent verification suite
SOLUTION.md (941 lines) The required markdown: title, root-cause analysis, exact fix (byte-accurate embedded code), verification

API: compile(pattern, alphabet) / new Regex(pattern, alphabet) returning {test, match, exec, states, ast, nfa, dfa, minimized, alphabet}; stages also exported (parse, thompson, determinize, hopcroft, trimUnreachable).

Root causes diagnosed and fixed (each with an independent oracle in verify.js): 1. Epsilon-closure must reach a fixed point through all ε-edges (fragment skips, star/plus loops) — including accept states with no out-edges. 2. Subset construction must produce a complete DFA (explicit dead state) before Hopcroft. 3. Unreachable-state trimming — the subtle one: a* over {a} is truly 1 state; an unreachable dead state must not count. This is also why the alphabet must be explicit (., [^…], and minimal counts are alphabet-relative). 4. Hopcroft work-list bookkeeping — split blocks replaced in the work list, both halves enqueued; validated against brute-force partition enumeration (true minimum), Moore's algorithm, and exact pairwise distinguishability. 5. JS-compatible parsing edges — [] empty class, [^] any char, first-] closes, ranges need plain chars, { literal unless valid quantifier, a{2,1}/a** errors, lazy *? — each verified against Node's own RegExp.

Verification results (exit 0, ~1.4 s): - Exhaustive language equality vs. independent AST interpreter: ~320K strings over {a,b}/{a,b,c} — all match - Minimization: Hopcroft === Moore === brute-force true minimum for all patterns and 400 random DFAs; minimized DFAs proven minimal and equivalent - Native RegExp cross-check: 422 patterns × 150 random strings over a 31-char alphabet — all match - Malformed patterns correctly rejected; known minimal counts (e.g., a*/{a} = 1, ab/{a,b} = 4, (a|b)*/{a,b} = 1) exact

Evidence & signatures

# Evidence
- Problem class: js-regex-thompson-subset-hopcroft-minimize
- Model: openrouter/deepseek/deepseek-v4-flash-0731
- Solved: 2026-08-29T22:25:44.717Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Implement a full regex engine in JavaScript: parse an expression supporting alternation, concatenation, Kleene star/plus, optionality, character classes, and groups into an AST, compile it to an NFA via Thompson construction, determinize with epsilon-closure subset construction, then minimize the DFA with Hopcroft partition refinement. The final DFA must accept exactly the pattern language on adversarial positive/negative strings, and its state count must match the true minimum (checked against brute-force minimization on small alphabets).", "environment": "node20", "language": "js", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "js-regex-thompson-subset-hopcroft-minimize", "provider": "openrouter", "solved_at": "2026-08-29T22:25:44.717Z", "version": "20"}

Answer 2

Done. The problem is solved and verified.

Summary

Deliverables in ~/regex-engine/:

File Content
regex.js (698 lines) Full engine: recursive-descent parser → AST → Thompson ε-NFA → ε-closure subset construction → complete DFA → trim → Hopcroft minimization
verify.js (706 lines) Independent verification suite
SOLUTION.md (941 lines) The required markdown: title, root-cause analysis, exact fix (byte-accurate embedded code), verification

API: compile(pattern, alphabet) / new Regex(pattern, alphabet) returning {test, match, exec, states, ast, nfa, dfa, minimized, alphabet}; stages also exported (parse, thompson, determinize, hopcroft, trimUnreachable).

Root causes diagnosed and fixed (each with an independent oracle in verify.js): 1. Epsilon-closure must reach a fixed point through all ε-edges (fragment skips, star/plus loops) — including accept states with no out-edges. 2. Subset construction must produce a complete DFA (explicit dead state) before Hopcroft. 3. Unreachable-state trimming — the subtle one: a* over {a} is truly 1 state; an unreachable dead state must not count. This is also why the alphabet must be explicit (., [^…], and minimal counts are alphabet-relative). 4. Hopcroft work-list bookkeeping — split blocks replaced in the work list, both halves enqueued; validated against brute-force partition enumeration (true minimum), Moore's algorithm, and exact pairwise distinguishability. 5. JS-compatible parsing edges — [] empty class, [^] any char, first-] closes, ranges need plain chars, { literal unless valid quantifier, a{2,1}/a** errors, lazy *? — each verified against Node's own RegExp.

Verification results (exit 0, ~1.4 s): - Exhaustive language equality vs. independent AST interpreter: ~320K strings over {a,b}/{a,b,c} — all match - Minimization: Hopcroft === Moore === brute-force true minimum for all patterns and 400 random DFAs; minimized DFAs proven minimal and equivalent - Native RegExp cross-check: 422 patterns × 150 random strings over a 31-char alphabet — all match - Malformed patterns correctly rejected; known minimal counts (e.g., a*/{a} = 1, ab/{a,b} = 4, (a|b)*/{a,b} = 1) exact

Evidence & signatures

# Evidence
- Problem class: js-regex-thompson-subset-hopcroft-minimize
- Model: openrouter/deepseek/deepseek-v4-flash-0731
- Solved: 2026-08-29T22:25:44.717Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Implement a full regex engine in JavaScript: parse an expression supporting alternation, concatenation, Kleene star/plus, optionality, character classes, and groups into an AST, compile it to an NFA via Thompson construction, determinize with epsilon-closure subset construction, then minimize the DFA with Hopcroft partition refinement. The final DFA must accept exactly the pattern language on adversarial positive/negative strings, and its state count must match the true minimum (checked against brute-force minimization on small alphabets).", "environment": "node20", "language": "js", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "js-regex-thompson-subset-hopcroft-minimize", "provider": "openrouter", "solved_at": "2026-08-29T22:25:44.717Z", "version": "20"}
Generated from the verified corpus · MIT licensedBack to the catalog