Files
SirRoboGarage/common_libs/guns/lead_gain.README.md
T
SirStone 7a6237ec20 j140 rename the lead-gain corrector: BitBrain -> LEADGAIN (+ legacy TR_BITBRAIN_* aliases)
The gun at rack id 16 learned a multiplier for Pattern's lead, separately
per range band. It was called BITBRAIN and shipped a TR_BITBRAIN_* prefix,
which is why the name read as a neural network it no longer contains.

  guns/bitbrain_gun.nim -> guns/lead_gain.nim  (rack id 16 UNCHANGED)
  RackGunNames[16]       BITBRAIN -> LEADGAIN
  TR_BITBRAIN_* knobs    -> TR_LEADGAIN_*
  [bb] log line          -> [lg]

BACKWARD COMPATIBILITY is mandatory: the live .env carries
TR_RACK_BITBRAIN=both, TR_BITBRAIN_GAINS, TR_BITBRAIN_MEM=decay and
TR_BITBRAIN_LOG=1, and those must keep behaving identically. The new ADE+SBC
gun (next commit) claims the BITBRAIN name and the TR_BITBRAIN_* prefix, so
the namespace is disambiguated by ONE deterministic switch, TR_BITBRAIN_NET
(default 0):

  TR_BITBRAIN_NET unset/0 -> LEGACY: the 14 frozen legacy suffixes are aliases
                              for TR_LEADGAIN_*, and TR_RACK_BITBRAIN still
                              selects rack id 16. One [depr] line on stderr
                              names the new spelling of each honoured knob.
  TR_BITBRAIN_NET = 1      -> the TR_BITBRAIN_* names belong to the new gun.

The legacy suffix set and the new gun's knob set are DISJOINT, so no name is
ever claimed twice; the new name always wins over its alias.

Parity: shipped rack is still onlyPattern, shipped movement is still strafe.
Guards unchanged: test_env_report 25, test_rack_membership 48,
test_tm_pattern_registration 20, test_lead_gain_registration 13 (was
test_bitbrain_registration), test_bitbrain 56, test_gun_harness 39,
test_tfil_commit_env 30. New: test_lead_gain_legacy 24.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-26 15:54:00 +02:00

7.6 KiB
Raw Blame History

lead_gain — quick recap (inputs / outputs)

Recap card. Everything below is read off common_libs/guns/lead_gain.nim.

The name

This gun is LEADGAIN (rack id 16, TR_LEADGAIN_*). It used to be called BITBRAIN and to live in guns/bitbrain_gun.nim, but the ADE+SBC network was removed when it was rebuilt into what it actually is: it learns a multiplier for Pattern's lead, separately per range band. The rack id is unchanged. The real ADE+SBC gun is guns/bitbrain_net.nim (rack id 17).

Backward compatibility (read this before editing your .env)

The TR_BITBRAIN_* names your .env already contains still work, and still select this gun. The disambiguation is one switch, TR_BITBRAIN_NET (default 0):

TR_BITBRAIN_NET who owns TR_BITBRAIN_*
unset / 0 LEGACY — these are aliases for TR_LEADGAIN_*; the new ADE+SBC gun is off
1 the new ADE+SBC gun (rack id 17)

So the owner's existing TR_RACK_LEADGAIN=both TR_BITBRAIN_GAINS=… TR_BITBRAIN_MEM=decay TR_BITBRAIN_LOG=1 keeps behaving exactly as before, and one [depr] line on stderr names the new TR_LEADGAIN_* spelling of each knob it honoured. The two name sets are disjoint by construction, so no name is ever claimed twice. Migrated names are TR_LEADGAIN_GAINS, _MEM, _MIN_OBS, _DECAY, _DECAY_FRAC, _LOG, _RESET_ON_TARGET, _N, _NADE, _RANGE, _WARMUP, _ADAPT, _CALIB, _SEED and TR_RACK_LEADGAIN.

What it is today

  • A lead-gain corrector on top of Pattern's prediction. It scales Pattern's lead over the line of sight by a learned gain.
  • The ADE/SBC neural network is REMOVED from this gun (it lives in guns/bitbrain_net.nim now). The generic common_libs/bitbrain/ library is intact and tested separately (test_bitbrain.nim, 56 checks).

INPUTS

Input Source in code
World state (self pos, enemy pos, tick) WorldState state
Base aim — Pattern's prediction g.tmh.pattern.predict(state, bulletSpeed): TmHorizonGun.pattern, a PatternMatcherGun (guns/pattern_matcher)
Range band (5 bands: 0/100/200/300/450) lgBandOf(dist), LG_BAND_LO/HI
Gate — gain applies only from band 3 up LG_GAIN_BAND_MIN = 3 → range ≥ ~300 px
Label / feedback — deferred observation lookup at fire time store lead + tolerance; h = round(dist/speed) ticks later tmhObservedAt(g.tmh, state.tick, selfX, selfY) returns the enemy's OBSERVED bearing
Aim tolerance (target's angular half-width) lgTolDeg(dist) = atan(18/range) in degrees
Config knobs env, resolved once in initLeadGainGun (see table)

OUTPUTS

Output Formula / meaning
Aim point aim = LOS + gain * (patternAim - LOS) — applied as angular shift = (gain - 1.0) * lead deg via tmhApplyShift; when gain == 1.0 the base prediction is returned unchanged
gain argmax hit rate per band over the candidate list; LG_CAND default has 5 candidates {0.0, 0.25, 0.5, 0.75, 1.0} (0 = HeadOn, 1 = Pattern); one candidate = fixed gain, no learning
[lg] log line (only if TR_LEADGAIN_LOG=1; emitted only when (gain, band) changes) see below
Does NOT output a predicted angle / bearing. It never aims on its own — it only rescales Pattern's lead.

[lg] fields, one at a time:

field meaning
t current tick
band lower edge of the range band in use (e.g. 300+)
gain the gain being applied to Pattern's lead
shift angular shift actually applied = (gain-1)*lead, degrees
rate hit rate of the chosen gain in this band
n resolved samples in this band
ncand number of candidate gains
trained total resolved samples this battle
pend deferred labels still waiting
dropped labels that could not be resolved (stale / out-of-order)
mode memory mode: perRound / retained / decay

KNOB TABLE (TR_LEADGAIN_*)

Every old TR_BITBRAIN_<X> in the LIVE and INERT tables below is still honoured as an alias, and one [depr] line on stderr names the TR_LEADGAIN_* spelling (see "The name" above). The ADE+SBC gun uses a different set of TR_BITBRAIN_* names (TR_BITBRAIN_INPUT, _NCLASSES, _NADES, …) plus TR_BITBRAIN_MODE / _DECAY_EVERY / _DECAY_SHIFT from the library; the two sets are disjoint, so nothing is claimed twice.

LIVE — the resolved field is read by the learner/predict path:

Env (new / legacy alias) Meaning
TR_LEADGAIN_GAINS / TR_BITBRAIN_GAINS comma-separated candidate gains (replaces LG_CAND)
TR_LEADGAIN_MEM / TR_BITBRAIN_MEM perRound / retained / decay memory
TR_LEADGAIN_MIN_OBS / TR_BITBRAIN_MIN_OBS samples before a band is trusted (in lgGainFor)
TR_LEADGAIN_DECAY / TR_BITBRAIN_DECAY decay interval in resolved samples (resolvePending)
TR_LEADGAIN_DECAY_FRAC / TR_BITBRAIN_DECAY_FRAC per-decay shrink of the hit counts (lgApplyDecay)
TR_LEADGAIN_LOG / TR_BITBRAIN_LOG 1 = emit the [lg] line
TR_LEADGAIN_RESET_ON_TARGET / TR_BITBRAIN_RESET_ON_TARGET wipe learning when the enemy id changes (targetChanged)
TR_RACK_LEADGAIN / TR_RACK_BITBRAIN the rack admission switch
TR_BITBRAIN_NET 0 (default) keeps TR_BITBRAIN_* legacy; 1 hands the namespace to the new ADE+SBC gun

INERT — kept only so old configs and the boot report don't warn; never touch the gain learner:

Env Stored as (only read by boot report / guard test)
TR_LEADGAIN_N / TR_BITBRAIN_N nClasses
TR_LEADGAIN_NADE / TR_BITBRAIN_NADE nAde
TR_LEADGAIN_RANGE / TR_BITBRAIN_RANGE maxDeg
TR_LEADGAIN_WARMUP / TR_BITBRAIN_WARMUP warmupN
TR_LEADGAIN_ADAPT / TR_BITBRAIN_ADAPT adaptEvery
TR_LEADGAIN_CALIB / TR_BITBRAIN_CALIB calibEvery
TR_LEADGAIN_SEED / TR_BITBRAIN_SEED seed

HOW TO TURN IT ON

Default is off; the shipped rack never calls it. Minimal .env:

TR_RACK_LEADGAIN=both
TR_RACK_PATTERN=off
TR_LEADGAIN_GAINS=1.0        # 1.0 = identity = aims EXACTLY like Pattern
TR_LEADGAIN_MEM=decay
TR_LEADGAIN_LOG=1

⚠️ TR_LEADGAIN_GAINS=1.0 is the identity — with one candidate at 1.0 the gun aims exactly like Pattern. Do not read the candidate list as a recommendation. Measured live: fixed gains above 1.0 are decisively harmful (1.5 → −93.8 dmg/run, p=0.0006; 1.25 → −34.2 dmg/run), a learner restricted to ≤ 1.0 is a wash (−2.5 dmg/run, p=0.87), and zero lead (= HeadOn) is catastrophic (14 vs 279 dmg/run). So the default set {0, 0.25, 0.5, 0.75, 1.0} is not a recommendation either — it merely allows the gun to shrink the lead toward HeadOn. Multi-candidate lists are for running the experiment, not for playing.

MEASURED VERDICT (measured under the old BITBRAIN name)

  • Neutral vs Pattern across many opponents: damage/run 214.5 vs 210.9, round wins 49.4% vs 49.8% over 32 opponents (docs/gauntlet_bitbrain_vs_pattern.md).
  • Specifically worse on DrussGT alone: −18.1 damage/run (docs/gauntlet_bitbrain_vs_pattern.md, docs/bitbrain_gun_verdict.md).
  • The lead-amplitude (gain) axis is CLOSED — nothing beats Pattern in either direction (docs/bitbrain_campaign.md §Phase 2 / §2.6).

PROVENANCE

  • Derived from code (this file): what it is today, all inputs, the output formula, the [lg] fields, the LIVE/INERT split, and the "how to turn it on" env lines.
  • Taken from the named evidence docs: the numbers in MEASURED VERDICT above — see docs/gauntlet_bitbrain_vs_pattern.md, docs/bitbrain_gun_verdict.md, docs/bitbrain_campaign.md.