312 lines
15 KiB
Markdown
312 lines
15 KiB
Markdown
# BitBrain gate test — can ADE+SBC predict a fine-grained aim correction?
|
||
|
||
**Question.** Given the already-built generic BitBrain library
|
||
(`common_libs/bitbrain/`, commit `77e6dac`, which reproduced the reference C on
|
||
MNIST to the digit), is there signal in a **fine-grained angular aim
|
||
correction** that neither a naive predictor nor the shipped Pattern gun already
|
||
has? If not, we stop before writing a gun.
|
||
|
||
**Scope.** Offline only. No gun wiring, no battle, no server, no rack
|
||
registration, no changed defaults. Fixtures are read-only.
|
||
|
||
**Tooling (the evidence):**
|
||
|
||
- `common_libs/tests/measure_bitbrain_gate.nim` — the analyzer.
|
||
- `common_libs/tests/measure_bitbrain_gate_results.txt` — its full deterministic
|
||
output.
|
||
- `common_libs/bitbrain/` — the library under test (untouched).
|
||
|
||
Reproduce:
|
||
|
||
```bash
|
||
nim c -r -d:release --nimcache:/tmp/nc_j92 --path:common_libs \
|
||
common_libs/tests/measure_bitbrain_gate.nim
|
||
# optional knobs: BB_POWER, BB_PMAX, BB_TARGET, BB_PASSES, BB_STEP, BB_STRIDE,
|
||
# BB_NADE, BB_NLIST, BB_FILES
|
||
```
|
||
|
||
---
|
||
|
||
## Direct answer
|
||
|
||
**There is signal, but it does not clear the bar as a shipping gun.**
|
||
|
||
- **vs straight-line naive:** BitBrain wins decisively on **every** readout and
|
||
every configuration (pooled mean arrival error **124.7 px vs 160.2 px**).
|
||
- **vs the shipped Pattern gun:** pooled, the best BitBrain configuration
|
||
(per-round reset, argmax readout, N=32, nAde=256) beats Pattern on **mean
|
||
arrival error** (124.6 px vs 139.8 px, −10.8 %; 13.3° vs 15.6°, −14.8 %) and
|
||
on **both hit rates** (18 px hit 8.3 % vs 7.0 %; angular hit 26.1 % vs
|
||
19.1 %). **However** the hit-rate gain is **not robust across fixtures**: it
|
||
is concentrated in the two fixtures where Pattern is weak (modularbot,
|
||
modularbot_shield) and **BitBrain loses hit rate on the two fixtures where
|
||
Pattern is strongest** (spinbot, crazy). It also only works in the
|
||
**per-round-reset** regime; the **retained-across-rounds** regime the user
|
||
actually wants is the weakest (it improves average error slightly but lowers
|
||
the hit rate).
|
||
- **Bottleneck (MEASURED):** sample starvation / SBC memory saturation, not the
|
||
AD synthesis and not an absence of signal.
|
||
|
||
A sword that helps exactly where the incumbent is already weak, and hurts where
|
||
it is strong, is not a gun improvement. The honest verdict is **signal yes,
|
||
shippable improvement no (yet)** — see the bottleneck section.
|
||
|
||
---
|
||
|
||
## What was measured (MEASURED unless tagged INFERRED)
|
||
|
||
### Data
|
||
|
||
The 5 committed Tank-Royale bridge fixtures `tools/fixtures/tr_drussgt_vs_*`
|
||
(open-loop replay), read-only:
|
||
|
||
| fixture | ticks | resolved samples |
|
||
|---|---:|---:|
|
||
| `tr_drussgt_vs_corners.jsonl` | 2575 | 2173 |
|
||
| `tr_drussgt_vs_crazy.jsonl` | 11507 | 11209 |
|
||
| `tr_drussgt_vs_modularbot.jsonl` | 20026 | 19548 |
|
||
| `tr_drussgt_vs_modularbot_shield.jsonl` | 12629 | 12308 |
|
||
| `tr_drussgt_vs_spinbot.jsonl` | 10824 | 10494 |
|
||
| **total** | | **55732** (55 rounds, ~1013 samples/round) |
|
||
|
||
The fixtures are **open-loop**: the recorded enemy does not react to us. That is
|
||
acceptable *here* because this test measures **single-tick prediction quality**,
|
||
the one category where fixture replay reproduces live behaviour faithfully. It
|
||
would **not** be acceptable evidence for a movement or adaptation claim. Do not
|
||
over-read the hit numbers as live hit rates.
|
||
|
||
### Input — the TMHorizon 53 bits, reused, not re-derived
|
||
|
||
The analyzer drives the **live `TmHorizonGun`** one tick at a time and reads its
|
||
own exported builder `tmhBaseBits` (49 draft bits) plus the 4-bit horizon
|
||
one-hot via `tmhLits` — the exact `cachedBits` per-tick path, with
|
||
`g.resetRoundState()` called at each round boundary to mirror the live
|
||
`onRoundStarted`. (The brief calls this `tmhBuildBits`; the actual symbol is
|
||
`tmhBaseBits`.) This keeps the comparison apples-to-apples with the TM gun
|
||
already measured.
|
||
|
||
### Output — fine-grained angular correction class
|
||
|
||
The correction is the bearing offset added to Pattern's prediction. N class
|
||
bins are laid over a fixed **±40°** range (class width 80°/N). Two readouts:
|
||
|
||
- **wm** = the **count-weighted mean** of the class centres, weighted by the
|
||
per-class set-bit counts summed over the 6 cross-AD SBCs. No evidence → 0
|
||
correction (i.e. Pattern).
|
||
- **arg** = the argmax class centre; no evidence → 0.
|
||
|
||
### Label — the +h-tick fact (never across a round)
|
||
|
||
`h = tmhHorizonFor(dist, speed) = clamp(round(dist/(20−3·power)), 10, 50)`.
|
||
At fire tick `t`, the label is the actual angular offset of the enemy at
|
||
`t+h` (from the same fixture, which under perfect-info replay equals the bot's
|
||
own observation ring) relative to Pattern's base bearing. Samples with
|
||
`t+h` past the round end are dropped (never a cross-boundary label). Pooled
|
||
`|label err|`: mean 15.9°, p50 11.6°, p90 37.2°, p99 52.0°.
|
||
|
||
### Metric — arrival aim error, not accuracy
|
||
|
||
Harness `bmPoint` geometry, the relation `measure_aim_vs_power.nim` validated
|
||
against the harness resolver: `fireDist = |Pattern − self|`,
|
||
`arrivalTick = t + ceil(fireDist/v) − 1`. A rotation preserves `fireDist`, so
|
||
the corrected aim point is rotated around the shooter. `miss = |aim − actual
|
||
enemy pos at arrivalTick|`; hit = `miss < 18 px`. Angular error = `|aim
|
||
bearing − actual bearing|`; angular hit = `|angErr| < atan(18/range)`. Timed
|
||
resolution happens on `arrivalTick`, which can differ from `t+h` by ≤ half a
|
||
tick; the label uses `h`, the metric uses `arrivalTick`, exactly as the brief
|
||
specifies.
|
||
|
||
**The px metric includes range error**, and because the head is a pure
|
||
rotation it cannot fix range; this is why the 18 px hit is dominated by range
|
||
error and the angular metric is the cleaner measure of a rotation head. Both
|
||
are reported.
|
||
|
||
### Protocol — prequential (predict-then-learn, streaming)
|
||
|
||
For every sample the model predicts **before** it is updated with the label.
|
||
Two regimes:
|
||
|
||
- **retained** — learning accumulates across all rounds of one battle
|
||
(fixture); reset only when the battle/enemy changes. This is what the user
|
||
asked for.
|
||
- **perRound** — reset at every round boundary (the worst case).
|
||
|
||
### Baselines
|
||
|
||
1. **straight-line naive** — enemy keeps its fire-tick velocity over the same
|
||
`arrivalTick` window.
|
||
2. **always-the-same-answer** — a fixed correction equal to the global mean
|
||
label (+0.20°).
|
||
3. **Pattern** — the shipped gun's own prediction (zero correction).
|
||
|
||
Pooled over all 55732 samples:
|
||
|
||
| predictor | meanPx | medPx | p90Px | meanDeg | medDeg | pxHit% | angHit% |
|
||
|---|---:|---:|---:|---:|---:|---:|---:|
|
||
| Pattern (zero corr) | 139.78 | 112.71 | 299.10 | 15.56 | 11.73 | 7.0 | 19.1 |
|
||
| straight-line naive | 160.17 | 131.57 | 336.48 | 16.01 | 12.18 | 5.0 | 18.8 |
|
||
| fixed (+0.20°) | 139.76 | 112.66 | 298.85 | 15.56 | 11.74 | 7.0 | 19.0 |
|
||
|
||
---
|
||
|
||
## The AD layer (synthesised for our data)
|
||
|
||
Random ADs (`initRandomAddressDecoder`, widths {6, 8, 10, 12}, **center = 0**),
|
||
then the deterministic homeostatic controller (`accumulateFiring` +
|
||
`adaptThresholds`, target 1 %). **center = 0 is forced by our data:** the
|
||
reference's 127 is the midpoint of 0..255; centring **binary** 0/1 inputs at 127
|
||
makes every synapse contribute ≈ −127 and collapses the ADE code to a mere
|
||
polarity count, destroying the signal.
|
||
|
||
The paper's `step = 1` controller would need thousands of intervals to find the
|
||
1 % operating point — **far more than a battle (500–2000 ticks) provides**.
|
||
This is itself the first measured symptom of sample starvation. The analyzer
|
||
therefore initialises each ADE's threshold at the score that puts it closest to
|
||
the 1 % firing count (a fast, unsupervised percentile), then runs the
|
||
deterministic controller (`step = 1`, 2 passes) to refine it. Achieved firing
|
||
rates (MEASURED, on the fit stride):
|
||
|
||
| nAde | w6 | w8 | w10 | w12 | mean |
|
||
|---:|---:|---:|---:|---:|---:|
|
||
| 128, pct-init | 0.47 % | 0.56 % | 0.66 % | 0.70 % | 0.59 % |
|
||
| 128, +homeostasis | 1.20 % | 1.50 % | 1.34 % | 1.32 % | **1.34 %** |
|
||
| 256, pct-init | 0.37 % | 0.50 % | 0.62 % | 0.69 % | 0.54 % |
|
||
| 256, +homeostasis | 1.16 % | 1.30 % | 1.31 % | 1.47 % | **1.31 %** |
|
||
|
||
So the paper's ~1 % operating point **is** reached. (The controller alone
|
||
overshot in an earlier pass at `step = 2`; `step = 1` lands it.)
|
||
|
||
---
|
||
|
||
## Sweep — N × AD size × regime (pooled, mean px error)
|
||
|
||
`wm` = count-weighted mean, `arg` = argmax. `hit%` is the 18 px arrival hit.
|
||
|
||
| config | wm meanPx | arg meanPx | wm pxHit% | arg pxHit% |
|
||
|---|---:|---:|---:|---:|
|
||
| Pattern | 139.78 | — | 7.0 | — |
|
||
| straight-line | 160.17 | — | 5.0 | — |
|
||
| fixed | 139.76 | — | 7.0 | — |
|
||
| nAde128 / N4 / retained | 136.93 | 166.79 | 4.8 | 2.4 |
|
||
| nAde128 / N4 / perRound | 130.27 | 140.28 | 4.3 | 3.0 |
|
||
| nAde128 / N8 / perRound | 128.87 | 134.81 | 4.5 | 4.7 |
|
||
| nAde128 / N16 / perRound | 128.78 | 133.72 | 5.2 | 6.7 |
|
||
| nAde128 / N32 / perRound | 128.83 | 133.97 | 5.2 | 7.5 |
|
||
| nAde128 / N64 / perRound | 128.97 | 134.67 | 5.2 | 7.6 |
|
||
| nAde256 / N8 / perRound | 124.78 | 125.60 | 4.3 | 4.7 |
|
||
| nAde256 / N16 / perRound | 124.72 | 124.46 | 4.8 | 7.3 |
|
||
| **nAde256 / N32 / perRound** | 124.95 | **124.62** | 4.9 | **8.3** |
|
||
| nAde256 / N64 / perRound | 125.13 | 125.34 | 5.0 | 8.5 |
|
||
| nAde256 / N16 / retained | 134.31 | 149.00 | 5.4 | 5.6 |
|
||
| nAde256 / N32 / retained | 134.23 | 149.43 | 5.3 | 6.5 |
|
||
| nAde256 / N64 / retained | 134.30 | 151.60 | 5.3 | 6.5 |
|
||
|
||
Full per-config degrees/p90/angular-hit rows are in
|
||
`measure_bitbrain_gate_results.txt`.
|
||
|
||
### Where the error stops falling, and why
|
||
|
||
- **N:** the `wm` error is flat from N=8 to N=64 (≈124.7–125.1 px); the `arg`
|
||
error falls to N=16–32 then flattens. **Optimum N ≈ 16–32.** Beyond it the
|
||
correction classes get finer than the loop can resolve, and the SBC
|
||
coincidence cells are already too few to constrain their class bits — more
|
||
classes only split the same evidence.
|
||
- **AD size:** nAde=256 beats 128 by a modest ~3 % in `wm`; both are far from
|
||
saturating, but the classes saturate first. Doubling the ADE count does not
|
||
double the information.
|
||
- **Why it stops:** MNIST needed ~60 000 examples for **10** mutually exclusive
|
||
classes. Here we have ~55 000 samples for **16–64** correction classes whose
|
||
evidence must separate by 1–2° — i.e. ~2 orders of magnitude less evidence per
|
||
class. The SBC is idempotent (a cell accumulates *every* class that ever
|
||
co-occurred, with no decay), so with too few examples per cell the per-class
|
||
counts blur toward uniform and the readout regresses toward the mean. That is
|
||
**sample starvation / memory saturation**, and it is consistent with every
|
||
other observation (flat N tail, weak nAde scaling, retained < perRound).
|
||
|
||
### Count-weighted mean vs argmax (the brief's hypothesis)
|
||
|
||
The brief expected the **count-weighted mean** to be the key readout because
|
||
the TM's discarded magnitude. **MEASURED, that is only half right:**
|
||
|
||
- The `wm` is the **shrinkage** readout: it reduces *mean* error (and extreme
|
||
misses) but **lowers the hit rate** (pooled pxHit 4.8 % vs Pattern 7.0 %,
|
||
angular hit 14.9 % vs 19.1 %). It never makes a confident, sharp correction.
|
||
- The `argmax` is the **decision** readout: it keeps the same mean-error
|
||
reduction *and* improves the hit rate (pxHit 8.3 %, angular hit 26.1 %). It is
|
||
the readout that beats Pattern on all four metrics.
|
||
|
||
So the fine-grained head works, but as a **classifier** (argmax), not as a soft
|
||
regression (weighted mean). The weighted mean is a useful control: it is the
|
||
readout whose shuffled-label null collapses to the baseline.
|
||
|
||
### Retained vs per-round reset
|
||
|
||
**Per-round reset beats retained across rounds on every readout and every N**
|
||
(retained `wm` ≈ 134.2 px, retained `arg` ≈ 149–162 px; per-round `wm` ≈ 124.7,
|
||
per-round `arg` ≈ 124.5). The user wants retention across the battle; the
|
||
measurement says the idempotent SBC **accumulates stale, conflicting class bits
|
||
across rounds** and the extra evidence hurts. This mirrors the project's earlier
|
||
TM finding ("forgetting is stronger than accumulation"). A viable gun would
|
||
need a bounded/decaying SBC, which the library does not have.
|
||
|
||
### Per-fixture breakdown (perRound, N=32, argmax)
|
||
|
||
| fixture (n) | Pattern meanPx / pxHit% / angHit% | BitBrain arg meanPx / pxHit% / angHit% |
|
||
|---|---|---|
|
||
| corners (2173) | 164.76 / 3.9 / 18.5 | 132.64 / 3.6 / 23.8 |
|
||
| crazy (11209) | 126.34 / 7.3 / 25.8 | 111.95 / **5.9** / **24.6** |
|
||
| modularbot (19548) | 151.80 / 3.3 / 10.5 | 134.46 / **7.5** / **25.1** |
|
||
| shield (12308) | 144.28 / 6.6 / 14.1 | 124.98 / **10.5** / **28.5** |
|
||
| spinbot (10494) | 121.29 / 15.0 / 33.7 | 117.72 / **10.6** / **27.3** |
|
||
|
||
Mean error improves on **all five**. Hit rate improves on modularbot and shield
|
||
(where Pattern is weak) and **regresses on spinbot and crazy** (where Pattern is
|
||
strong), with corners a wash. That is the whole verdict in one table.
|
||
|
||
### Shuffled-label control (must collapse)
|
||
|
||
Labels permuted across all samples (3 seeds), same inputs:
|
||
|
||
| regime | wm shuffled meanPx / pxHit% | arg shuffled meanPx / pxHit% |
|
||
|---|---|---|
|
||
| retained | 141.51 / 5.8 | 200.10 / 2.4 |
|
||
| perRound | 146.74 / 4.6 | 193.22 / 2.4 |
|
||
|
||
The **weighted mean collapses toward the baseline** (141.5 vs Pattern 139.8) —
|
||
expected, because it shrinks to the (near-zero) label mean. The **argmax does
|
||
not collapse to the baseline: its null is worse than the baseline** — with no
|
||
signal it still makes a confident, essentially random rotation, which is worse
|
||
than no correction. That is the correct null behaviour for a non-shrinking
|
||
readout, and it is why the honest control is **real vs shuffled within the same
|
||
readout**: BitBrain argmax is ~124.6 px on real labels vs ~193 px on shuffled
|
||
labels. The learning is real; the signal is not an artifact.
|
||
|
||
---
|
||
|
||
## Bottleneck and recommendation (MEASURED)
|
||
|
||
Ranked by how much each could plausibly close the gap:
|
||
|
||
1. **Sample starvation / SBC memory saturation — the dominant one.** N
|
||
saturates at ~16–32, nAde barely scales, and per-round reset beats retention.
|
||
The library has no bounded/decaying SBC, so a long battle only blurs.
|
||
2. **Fixture-dependent gain.** The pooled hit win is carried by the
|
||
weak-Pattern fixtures. Without an online per-fixture selector, a blanket
|
||
substitution would lose on spinbot/crazy.
|
||
3. **AD synthesis is *not* the bottleneck.** The ~1 % operating point is
|
||
reached and the shuffle control shows the ADs are informative. The forced
|
||
`center = 0` for binary inputs is a correctness requirement, not a defect.
|
||
|
||
**Do not build the gun yet.** The cheap decisive next step, if pursued, is a
|
||
**bounded/decaying SBC** (a per-round or recency-weighted memory) plus an
|
||
**online selection gate** that keeps Pattern where BitBrain is worse — the only
|
||
shape the data supports. A wider class range or a larger nAde will not fix the
|
||
starvation.
|
||
|
||
---
|
||
|
||
*All numbers MEASURED by `common_libs/tests/measure_bitbrain_gate.nim` on this
|
||
machine, deterministic (fixed seeds). Arrival geometry is the harness `bmPoint`
|
||
relation validated in `measure_aim_vs_power.nim`. The fixtures are open-loop;
|
||
treat the hit rates as prediction-quality evidence only.*
|