Rust bitboard engine: parity gates and throughput benchmark vs TypeScript and C++ engines
web/content/research/EX-20260824-rust-engine-parity-throughput-4036a91f.mdx and it will appear here. The registered protocol is shown below.The registered protocol
Engineering port, no new science: a column-major nibble-packed Rust reimplementation of the Drop7 engine (7 x u32, 4 bits per cell; gravity as PEXT compaction; whole-board cover-hit counting with a bitboard adder) plus a packed-key transposition-table expectimax search is trace-equivalent to the frozen C++ reference (src/core/native/engine.hpp), the proven C++ fast engine (approaches/lifetime-objective/fast-engine, finding-13/audit-06), and the TypeScript engine (src/core/typescript/engine.ts): identical boards, scores, wave lists, reveal streams, leaf value bit patterns, per-column search values and chosen actions at fixed depth/strata. Expected speedup: at least the C++ fast engine's decisions/second at identical fixed work, with bounded per-searcher memory and near-linear game-level thread scaling; the realised figures are measured and reported with the machine profile. Per docs/benchmarks.md, any deviation in actions, random events, or work semantics reclassifies the port as a new algorithmic candidate and it is then not accepted under this record.
approaches/fair-expectimax/rust-engine/src/lib.rsapproaches/lifetime-objective/fast-engine/fast-search.hppPrimary metric
trace equivalence vs the C++ reference and fast engine: board, score, next disc, wave list, reveal stream on every move; leaf value uint64 bit patterns; per-column search values and chosen actions at fixed depth/strata
Statistical unit: not-applicable
Pass criteria, fixed in advance
- Trajectory gate: >= 4096 complete games per policy arm (center policy and a searching policy) replayed move-by-move through the Rust engine and the C++ reference/fast engine with 0 mismatches on board, next disc, score, score delta, wave list, level, moves remaining, terminal flag.
- Leaf gate: >= 100,000 real leaf states with uint64-bit-identical leaf values vs the C++ fast leaf.
- Search gate: >= 500 real root decisions at d4s7 and a d5s7 probe set with per-column double values bit-identical to the C++ fast search and identical chosen actions; identical completed depths at fixed work bounds.
- Determinism: byte-identical chosen actions across worker counts (1 vs 32) in complete-depth mode and across repeated runs; reflection gate mirrors the C++ behavior.
- TypeScript cross-check: >= 1000 games replayed through the TS engine and the Rust engine from the same Mulberry32 draw stream with identical boards and scores.
- npm test and make test pass; no existing file is modified.
On pass: Record valid + pass (engineering, CHECK tier) with measured throughput, memory and scaling figures and the machine profile; publish the comparative writeup as the approach page; no strength claim and no later cohort is opened by this record.
On fail: Record valid + fail as an engineering result; the C++ fast engine remains the fastest proven-equivalent implementation.
Data and reuse
Zero new leased seeds. Trajectory and search gates read sub-blocks of the already-opened SEEDLEASE-A52-FAST development block 0xa5270000-0xa5277fff (docs/exploratory/lease-map.md, opened for semantics-preserving engine optimisation): Rust uses 0xa5276000-0xa5276fff (gates) and 0xa5277000-0xa5277fff (timing), disjoint from the C++ sub-blocks at 0xa5270000-0xa5275fff. CHECK probes may also read the already-open 0xa5278000-0xa52784ff probe block. No cohort's data status changes; no strength claim is made.
seed leases: none
What happened
The Rust bitboard engine is trace-equivalent to the frozen C++ reference, the proven C++ fast engine, and the TypeScript engine on every observable, and is the fastest of the three. Board representation is seven u32 column words at 4 bits per cell (28 bytes): gravity is a single PEXT bit-gather per column, a row rise is (word << 4) | SOLID, and cover hits are counted board-wide with a 4-way bitboard parallel counter. All parity gates pass with zero mismatches: 3 trajectory arms (512 center + 256 search-policy games vs C++ playHeadlessMove; 256 games vs the TypeScript seededRandom driver) totalling 36,427 moves and 40,286 waves; 150,854 leaf states bit-identical as uint64 patterns; 105 d4s7 and 10 d5s7 roots with bit-identical per-column values and identical actions; the values gate re-run with the transposition table enabled proves cache-independence. Measured on the shared AMD Ryzen AI MAX+ 395 workstation (best-of-N, load 1.1-1.7): single-core engine throughput 12.8M moves/s vs C++ fast 6.5M (1.97x) and TypeScript 0.65M (19.8x); leaf 155.6 ns vs C++ fast 187.5 ns (1.20x); fair search at d4s7 908 ms/decision vs C++ fast 1,071 ms (1.18x) with a 3.1 MB direct-mapped table vs the C++ 16.2 MB LRU; d5s7 7,047 ms at 1M entries vs 7,817 ms (1.11x). Game-level scaling is shared-nothing and near-linear (10.3x on 16 physical cores on the shared machine; 14.1x in a clean run), with identical results at every worker count. A key recorded finding: the transposition table's 1.3% node hit rate is misleading — each hit prunes a whole subtree, so the table eliminates ~47% of work at d4s7 and ~90% at d5s7, and a cheap direct-mapped depth-preferred table captures nearly all of the strict-LRU table's payoff at a fifth of the memory. No strength claim; no new seeds opened.
- ✓Trajectory parity vs C++ reference and TypeScript engine across center, search-policy, and TS-driver arms — observed: 3 arms, 36,427 moves, 40,286 waves, 0 mismatches on board, next disc, score, score delta, wave list, level, moves remaining, terminal/clear/advance flags
- ✓Leaf bit-exactness vs C++ fastFairLeaf as uint64 bit patterns — observed: 150,854 states, 0 mismatches
- ✓Search value/action parity at fixed depth/strata — observed: 105 d4s7 roots (no-table and depth-gated arms) + 10 d5s7 roots, per-column f64 bit patterns and chosen actions identical, 0 mismatches
- ✓Cache independence of the transposition table — observed: values gate re-run with the direct-mapped table enabled: 105 roots, 0 mismatches
- ✓Worker-count independence and determinism — observed: identical move counts, wave counts and mean scores at 1/2/4/8/16/32 game-level workers; each game computed by exactly one worker
- ✓npm test and make test pass; no existing file modified — observed: npm test 137/137 pass; make research-validate OK; all Rust/C++/TS additions live under approaches/fair-expectimax/rust-engine/ and build/rust-engine/
Recorded metrics
- typescript
- 649,471
- cppReference
- 6,799,180
- cppFast
- 6,511,760
- rust
- 12,838,933
- cppFast
- 187.5000
- rust
- 155.6000
- cppBaseline
- 3247.8000
- cppFast
- 1071.5000
- rustNoTable
- 1633.4000
- rustDepthGated64k
- 907.6000
- cppBaseline
- 23992.6000
- cppFast
- 7817.3000
- rustNoTable
- 63325.4000
- rustDepthGated256k
- 7787.9000
- rustDepthGated1M
- 7047.1000
- rustDepthGated4M
- 6748.4000
- nodeHitRateD4S7
- 0.0130
- nodeHitRateD5S7
- 0.0136
- workEliminatedD4S7
- 11.9M -> 6.3M (47%)
- workEliminatedD5S7
- 582.7M -> 59.5M (90%)
- rust
- 129,483,860
- cppFast
- 82,364,000
- rustSearcher
- 2,496
- rustBoard
- 28
- rustTable64k
- 3,145,728
- cppFastTable
- 16,194,304
- CHECK-tier engineering result: proves equivalence and measures speed/memory, but makes no policy-strength claim and advances no benchmark tier.
- Timing measured on a shared workstation (load average 1.1-1.7); ratios between back-to-back arms are the trustworthy quantity, absolute nanoseconds are not.
- The d5s7 arms ran 3 decisions each (1 repeat) because a single d5s7 decision costs 7-63 s; the d4s7 arms ran 21 decisions, best of 3.
- The direct-mapped table's hit rate at d5s7 (748k-825k hits/decision) trails the C++ strict-LRU table (911k); a set-associative table is the recorded reopening direction.
- No GPU, latent-mode, or native-scenario variant: scripted-round and scenario duties stay with the existing engines.