Skip to content

Commit 284b999

Browse files
committed
probe: W0 D-GTM-0g/0h/0i/0j/0k — mask/trie vs GEMM measured; 0j falsifies the density framing
Adds examples/hex_trie_vs_gemm_probe.rs (--release, #[ignore]-free but example-gated) and records §12. 0k ANSWERED cleanly: the mask hot path materializes 0 bytes/step at every density and depth, both relation shapes, measured with a counting global allocator rather than asserted. GEMM materializes 73,728 B/step. 0j FALSIFIES the plan's own framing. §11.1 pt 6 said "GEMM is attractive when information is dense"; measured, there is no density crossover at all — masks win 745x at 0.02% relation density and 297x at 100%, because both costs are flat in density (GEMM O(N^2) FMAs, mask O(active*N/64) word ORs). The honest boundary is a TYPE boundary: masks win whenever the relation is Boolean; GEMM is required when the relation carries VALUES. §12.5 states plainly that the headline numbers are NOT evidence for the hypothesis: a dense f32 matrix for a 0/1 relation is a mis-specified baseline (a bitmask is 32x denser before any algorithm runs), and the missing arm is CSR SpMV, which would plausibly cross at low density. The one internally fair comparison is PREFIX vs RANDOM within the mask arm — 21-79 ns flat vs 305-35,522 ns scaling with active bits. The probe's correctness gate earned its place: it caught a real bug in the probe itself (the mask arm must union the TRANSPOSE; unioning srcs(i) agrees with the GEMM arm only for a symmetric relation, which bucket membership is and a random relation is not). A second flaw — mask timings at or below timer resolution making every early "speedup" a noise ratio — was caught by reading and fixed with a 50 ms floor. 0h is graded [S]: perf is unavailable in this sandbox, so residency is inferred from timing and that limit is stated, not hidden. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EfrUJH3UNnv5NpDH4jDGHq
1 parent 8c9e80f commit 284b999

3 files changed

Lines changed: 477 additions & 0 deletions

File tree

.claude/plans/gemm-ternlog-mask-consolidation-v1.md

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# gemm-ternlog-mask-consolidation-v1 — one GEMM entry per dtype, masks as the prefilter, ternlog as the mask ALU
22

3+
> **Status:** DRAFT v1.4 (2026-09-05) — §12 RUNS D-GTM-0g/0h/0i/0j/0k. 0k passes
4+
> cleanly (mask hot path = 0 bytes/step, measured by a counting allocator). **0j
5+
> falsifies the framing:** there is no density crossover — masks win 745×→297× from
6+
> 0.02% to 100% relation density — because "GEMM wins when dense" is wrong for a
7+
> BOOLEAN relation; the real boundary is a TYPE one (Boolean ⇒ masks, valued ⇒ GEMM).
8+
> The dense-f32 baseline is mis-specified and the headline numbers are explicitly NOT
9+
> evidence (§12.5); the missing arm is CSR SpMV. D-GTM-0l is now the decisive probe.
10+
>
311
> **Status:** DRAFT v1.3 (2026-09-05) — §11.10 strengthens the invariant to
412
> `substrate == mask geometry == projection surface`: the 3-D field (diamond tracts, the
513
> "cube") is never allocated — it is a mask-address projection of the 2-D 6×2×8 surface,
@@ -687,3 +695,110 @@ the 3×4 standing watch; nothing to probe about arity.
687695

688696
Those two probes together are the hologram's test: recover the relation (0l)
689697
without allocating it (0k). Nothing else in the program changes.
698+
699+
## §12 — WAVE 0 MEASURED: D-GTM-0g/0h/0i/0j/0k run, and the hypothesis's own framing is corrected
700+
701+
Probe: `examples/hex_trie_vs_gemm_probe.rs` (`--release`, committed). N = 4096,
702+
mask = 512 B, dense relation matrix = 64 MB. Task, identical for both arms:
703+
`D` steps of `state = R(state) ∩ constraint`, with a **correctness gate**
704+
survivor counts must match or the run aborts.
705+
706+
### 12.1 The gate fired, and it found a bug in the probe itself
707+
708+
First run: PREFIX passed at every cell, RANDOM failed immediately
709+
(`gemm 912 vs mask 930`). Cause: the GEMM arm computes
710+
`{ i : srcs(i) ∩ active ≠ ∅ }` while the mask arm was unioning `srcs(i)` over
711+
active `i`. **Those agree only for a SYMMETRIC relation** — true of bucket
712+
membership, false of a random relation. The mask arm must union the TRANSPOSE
713+
(`fwd[j]` = what `j` can activate). Fixed; recorded because the asymmetry is
714+
easy to reintroduce and the gate is the only thing that catches it.
715+
716+
A second flaw was caught by reading, not by any gate: the mask arm first timed
717+
at 0.000–0.001 ms — **at or below timer resolution**, so every "speedup" in that
718+
table (25,940× … 853,300×) was a ratio against quantization noise. Both arms now
719+
run to a 50 ms floor and report ns/step.
720+
721+
### 12.2 What was measured (all cells passed the equality gate)
722+
723+
**State-density sweep**, depth ∈ {1, 8, 32}:
724+
725+
| relation | mask ns/step | GEMM ns/step | mask B/step | GEMM B/step |
726+
|---|---|---|---|---|
727+
| PREFIX (structured) | **21–79**, flat in state density | 8.4–8.8 M | **0** | 73,728 |
728+
| RANDOM (no structure) | 305 (1%) → 35,522 (99%), scales with active bits | 10.6–13.0 M | **0** | 73,728 |
729+
730+
**Relation-density sweep** (RANDOM, state 50%, depth 8) — the axis the first
731+
table missed:
732+
733+
| edges/row | relation density | GEMM ns/step | mask ns/step | speedup |
734+
|---|---|---|---|---|
735+
| 1 | 0.02% | 8,758,129 | 11,743 | 745.8× |
736+
| 16 | 0.39% | 12,050,934 | 42,601 | 282.9× |
737+
| 64 | 1.56% | 12,309,149 | 41,855 | 294.1× |
738+
| 256 | 6.25% | 13,112,322 | 42,667 | 307.3× |
739+
| 1024 | 25.00% | 12,525,352 | 42,559 | 294.3× |
740+
| **4096** | **100.00%** | 12,776,345 | 43,024 | **297.0×** |
741+
742+
### 12.3 D-GTM-0k — ANSWERED, and it is the one clean result
743+
744+
**Mask hot path: 0 bytes/step at every density, every depth, both relation
745+
shapes.** GEMM: 73,728 B/step (a packing buffer inside `gemm_f32`). The
746+
invariant's own falsifier passes — nothing is materialized on the mask path,
747+
measured by a counting global allocator rather than asserted.
748+
749+
### 12.4 D-GTM-0j — there is NO crossover, and that falsifies the framing rather than confirming it
750+
751+
§11.1 pt 6 says *"GEMM is attractive when information is dense; a hex/trie field
752+
may win when cognition is mostly successive elimination."* **Measured, the
753+
density axis does not produce a crossover at all** — the mask arm wins by ~300×
754+
at 0.02% and by 297× at 100%. Both costs are flat in relation density: GEMM pays
755+
`O(N²)` FMAs regardless, the mask arm pays `O(active · N/64)` word-ORs
756+
regardless.
757+
758+
**So "GEMM wins when dense" is FALSE as stated for a Boolean relation.** The
759+
honest correction, and it is a TYPE boundary rather than a density:
760+
761+
> **Masks win whenever the relation is Boolean; GEMM is required when the
762+
> relation carries VALUES.** A bitmask is 32× denser than f32 *before any
763+
> algorithm runs*, so a Boolean relation in f32 was never the right
764+
> representation. Where a weight must be accumulated (evidence strength, a
765+
> learned probability, a distance), the mask arm cannot express the operation at
766+
> all — that, not density, is where GEMM becomes mandatory.
767+
768+
### 12.5 The baseline is mis-specified, and the headline numbers are NOT evidence
769+
770+
Stated plainly so no future session cites 297× as support:
771+
772+
1. **A dense f32 matrix for a 0/1 relation is an unfair baseline.** The mask arm
773+
is not beating GEMM; it is beating a 32×-wasteful *representation* of a
774+
Boolean relation. The number is real and the credit is misattributed.
775+
2. **The missing arm is CSR SpMV.** A sparse f32 baseline costs `O(nnz)`, so at
776+
`deg = 1` it is ~4,096 FMAs — the same order as the mask arm's 11.7 µs, and
777+
it would plausibly cross. Until that arm is built, no claim about "mask beats
778+
sparse GEMM" is available, and none is made here.
779+
3. **The structured/unstructured separation is the one comparison that IS
780+
internally fair** (same arm, same representation, same task): PREFIX 21–79 ns
781+
flat vs RANDOM 305–35,522 ns scaling with active bits. ~3 orders of
782+
magnitude, and it degrades exactly where the mask arm has no structure to
783+
exploit — which is the E-Q8 discipline applied to compute rather than recall.
784+
785+
### 12.6 D-GTM-0h — a limit of the sandbox, stated rather than papered over
786+
787+
`perf` is unavailable here, so register/cache residency could not be measured
788+
with counters. The timing proxy is suggestive only: PREFIX per-step cost *falls*
789+
from ~70 ns at depth 1 to ~21–27 ns at depths 8 and 32 (loop-invariant setup
790+
amortizing over more steps), with no knee up to depth 32 — consistent with
791+
staying resident, and **not proof of it**. Graded [S] pending a machine with
792+
counters.
793+
794+
### 12.7 What W0 now leaves open
795+
796+
- **D-GTM-0g** — partially answered; needs the CSR SpMV arm (12.5 pt 2) before
797+
"mask/trie vs GEMM" means anything beyond "packed beats unpacked".
798+
- **D-GTM-0l** — unrun. It is now the *decisive* probe: with the density axis
799+
dead, the hypothesis stands or falls on whether packed-prefix routing can
800+
express real long-range relations without codebook entropy exploding, on the
801+
R2IL/C64 ore.
802+
- **The weighted arm** — new, implied by 12.4: the type boundary needs its own
803+
measurement (where does accumulating a value force GEMM?).
804+
- 0c / 0d / 0e remain unrun.

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ required-features = ["splat3d"]
5151

5252
# AMX examples import `ndarray::simd` / `ndarray::hpc`, both `#[cfg(feature =
5353
# "std")]`, so they must be skipped in `--no-default-features` CI jobs.
54+
[[example]]
55+
name = "hex_trie_vs_gemm_probe"
56+
required-features = ["std"]
57+
5458
[[example]]
5559
name = "amx_gemm_bench"
5660
required-features = ["std"]

0 commit comments

Comments
 (0)