# 8. BEX ensemble for grammar inference **Date:** 2026-07-03 **Status:** Accepted ## Context Given a set of symbol sequences (e.g. `["every", "assertEquals", "verify"]`), we need to infer a grammar that concisely describes the pattern. Three algorithms are available: - **CRX**: Fast, produces unordered CHAREs (e.g. `(a+b+c)+`). Best for vocabulary discovery. - **iDRegEx**: Slower, produces ordered regex with alternation and optionality (e.g. `a.b.(c|d)?`). Best for small, clean sequences. - **kOREInference**: Probabilistic, handles noise well (e.g. `a.b.(b?(a|c))`). Best for diverse sequences with outliers. No single algorithm works best for all codebases. We need to pick the right one for each cluster automatically. ## Decision Run all three algorithms (ensemble), compute MDL (Minimum Description Length) for each, and select the one with the lowest MDL score. MDL = grammar_length + sum of per-example encoding costs. Lower is better — the grammar explains the data most compactly. Ensemble logic in `infer_ensemble()`: ```python def infer_ensemble(sequences, kmax=2, N=3, prefer=None): best = None best_score = float('inf') for name, fn in [('CRX', crx), ('iDRegEx', idregex), ('kOREInference', kore)]: if prefer and name.lower() != prefer.lower(): continue grammar = fn(sequences, ...) mdl = compute_mdl(grammar, sequences) if mdl < best_score: best_score = mdl best = {'algorithm': name, 'grammar': grammar, 'mdl_score': mdl} return {'best': best, 'all': all_results, 'why': {...}} ``` Default `kmax=2`, `N=3` (max k for k-ORE, random trials). ## Consequences **Positive:** - CRX handles large clusters with diverse vocabulary — produces useful vocabulary bags. - iDRegEx fires on small, focused clusters (3-12 methods) — produces ordered grammars with exact subsequences. - kOREInference handles noisy clusters where methods share a theme but vary in exact call order. - MDL provides a principled, automatic selection criterion. **Negative:** - k-ORE algorithms fail on real code when sequences are too diverse (per-file sequences differ more than per-log sequences they were designed for). - Clustering helps by grouping similar methods before inference. - iDRegEx can produce overfit grammars on very small clusters (3 methods) — e.g. `every.every.verify.(assertEquals)?` for 3 methods that happen to share an exact sequence. - MDL comparison assumes grammars are comparable — CRX CHAREs and iDRegEx regex use different notation, so length comparison is approximate. ## Alternatives Considered - **Single algorithm (CRX only)**: Fast but produces only unordered vocab — misses ordering conventions entirely. - **Single algorithm (iDRegEx only)**: Produces ordered grammars but fails on diverse inputs (returns `ε`). - **Single algorithm (kORE only)**: Most robust to noise but slowest, and still fails on highly diverse code sequences. - **Algorithm per cluster size**: Manual heuristic (CRX for >20 methods, iDRegEx for <10). Harder to tune than MDL-driven selection.