Commit 3fb7e2b
committed
feat(speculation): generator contract and bestfirst impl
Add submitqueue/extension/speculation/generator, the candidate-stream composition point (Generator/PathIterator) the standard Speculator pulls from, plus the bestfirst implementation and mocks.
bestfirst ranks each path by the product of its dependencies' landing chances (scored through an injected scorer) and generates lazily at two levels. A cross-head heap holds one real, non-terminal candidate per head — never an optimistic upper bound — so popping it yields the globally best-ranked path; each head is itself a lazy stream that materializes its next candidate only once the current one is consumed. Pulling k candidates materializes O(k) paths however large the space behind them, so a head with twelve unresolved dependencies costs no more at the front of the queue than one with two.
Within a head, the best path takes the preferred (likelier) bet on every unresolved dependency, and every other path flips some subset of those choices, each flip multiplying the score by that choice's penalty (alternative over preferred). Subsets are walked by a canonical expansion under which every subset has exactly one parent, so each combination is generated exactly once with no visited set, and a child never outranks its parent — which is what lets the heap pop in true descending order.
Also corrects the generator README: the leading path is the preferred-bet path, not the all-included one. The two differ whenever a dependency is likelier to fail than to land, so the old wording was wrong for any below-even dependency.
The two heaps (across heads, and within a head) order candidates identically, so they share one generic rankedHeap over the standard library's container/heap rather than repeating the heap.Interface boilerplate twice.
Test coverage is 22 cases, including the exact emitted sequence across heads, the preferred bet on a below-even dependency, mixed pinned dependencies dropping out of the search, terminal filtering across every terminal status (and deliberately not filtering the non-terminal ones), the materialization counts behind the laziness claim, deterministic tie-breaking, and a randomized cross-check of the whole walk against brute-force enumeration. The generator README gains a worked walkthrough tracing the frontier pop by pop.
A head over the depth bound is now recognised from its dependencies' states alone, before anything is scored. Previously every unfinished dependency was scored and only then was the head found to be over the bound. Scoring can be expensive and a head we skip should not pay for it. One visible consequence: a scorer error on a head that was going to be skipped no longer fails Open.1 parent 648e491 commit 3fb7e2b
8 files changed
Lines changed: 1611 additions & 0 deletions
File tree
- submitqueue/extension/speculation/generator
- bestfirst
- mock
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
Lines changed: 26 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
0 commit comments