Skip to content

Commit af72945

Browse files
committed
review: address codex + coderabbit on the HEVC amortization map (#234)
- codex P2 (R-5 crossover): the tile path is NOT unconditional per block. Carry the R-5 dispatch rule — per-block WHT butterflies win below the batch crossover (~400× for a 32×32 DCT), batched BF16 tile GEMM only wins above it; crossover per-arch (SPR=64, ICX=32, Zen4=96, Apple M=256, Graviton=128). Ship both, dispatch on N. Removes the misleading "every block pays a tile op". - coderabbit (status vocab): add SHIPPED + PARTIAL to the legend so the table's tags match the declared taxonomy. - coderabbit (palette proposal vs contract): label the palette-index entropy layer as SHIPPED module / PROPOSED codec wiring — the shipped codec uses hpc::codec::ans static rANS over the 4 CellMode tags today. Fix the "fully parallel end to end" vs "light rANS" tension: the substrate has no context-adaptive serial stage; an optional non-adaptive order-0 rANS over the packed indices is interleavable, not a CABAC dependency chain. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MLBnPuScZy6w9di2QEjsXM
1 parent df74237 commit af72945

1 file changed

Lines changed: 37 additions & 19 deletions

File tree

.claude/knowledge/hevc-amortization-map.md

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
> READ BY: cognitive-architect, savant-architect, amx-savant, truth-architect,
44
> l3-strategist, product-engineer
55
>
6-
> Status ledger. Every row is tagged **[MEASURED #PR]** / **[MECHANISM —
7-
> unmeasured, probe named]** / **[DOESN'T FIT]**. No unmarked conjecture.
8-
> Companion to `.claude/knowledge/pr-x12-codec-cognitive-substrate-mapping.md`
9-
> (the E-7/H-7 plan this measures against).
6+
> Status ledger. Every row is tagged **[MEASURED #PR]** (probe run) /
7+
> **[SHIPPED]** (code exists + tested, not yet wired into the codec pipeline) /
8+
> **[MECHANISM — unmeasured, probe named]** / **[PARTIAL]** / **[DOESN'T FIT]**.
9+
> No unmarked conjecture. Companion to
10+
> `.claude/knowledge/pr-x12-codec-cognitive-substrate-mapping.md` (the E-7/H-7
11+
> plan this measures against).
1012
1113
## The thesis (operator, 2026-07-04)
1214

@@ -49,20 +51,32 @@ matching the DCT within 2%. Same ±1 sign butterfly, two names.
4951
| **Reference-sample smoothing / covariance** | Gaussian/covariance projection = the EWA sandwich | **[MEASURED #233]**`sandwich_x16` shape @ 0.4% |
5052
| **CTU quad-tree partition** (64→32→16→8) | Morton/HHTL tier cascade = the address pyramid | **[MECHANISM — shipped]** `hpc::cascade`, blasgraph HHTL; codec `Ctu` quad-tree. Routing-parity probe unmeasured |
5153
| **Deblocking + SAO** (in-loop filters) | conditional edge filter + offset LUT — clip/branch-heavy, *not pure GEMM* | **[PARTIAL — AMX masking]** the operator's "AMX masking": the filter is a masked tile op (predicated add), SAO is a gather-LUT. Fits with masking, not plain GEMM. Unmeasured |
52-
| **Entropy — substrate-native** (palettise, don't arithmetic-code) | small alphabet (≤256 basin/centroid indices) → **variable-width SIMD palette pack** (VPSHUFB, 16 idx/cycle) | **[SHIPPED]** `ndarray::palette_codec` (Pumpkin/Minecraft port, 28 tests): `pack_indices_simd`/`unpack_indices_simd` bit-exact all 1–8 bit widths; `transcode` = per-block bit-width adaptivity; `nibble` (4-bit) + `byte_scan` (NBT) complete the byte layer. Fully parallel — NO serial stage |
53-
| **CABAC entropy** (context-adaptive binary arithmetic — `.265` compat only) | serial, bit-level, data-dependent arithmetic coding | **[DOESN'T FIT — but the substrate doesn't need it]** CABAC is a serial dependency chain, not a GEMM; AMX/tiles do not help. It is required ONLY to decode an *existing* `.265` bitstream (the M2 serial front-end). A substrate-**native** codec replaces it with the SIMD palette-pack row above (the codec already quantises to a small palette), so the native encode+decode pipeline is fully parallel end to end: `gather + tile op + palette-pack`. The boundary is `.265`-compat, not the substrate's own entropy needs. |
54+
| **Entropy — palette-pack module** (parallel, small-alphabet) | small alphabet (≤256 basin/centroid indices) → **variable-width SIMD palette pack** (VPSHUFB, 16 idx/cycle) | **[SHIPPED module / PROPOSED codec wiring]** `ndarray::palette_codec` (Pumpkin/Minecraft port, 28 tests): `pack_indices_simd`/`unpack_indices_simd` bit-exact all 1–8 widths; `transcode` = per-block bit-width; `nibble`+`byte_scan` complete the byte layer. **Not yet wired as the codec's entropy stage** — the shipped codec (`hpc::codec::ans`) currently does static per-block rANS over the 4 `CellMode` tags. Using palette-index packing *as* the codec's entropy layer is the proposed change. |
55+
| **CABAC entropy** (context-adaptive binary arithmetic — `.265` compat only) | serial, bit-level, data-dependent arithmetic coding | **[DOESN'T FIT — and the substrate can route around it]** CABAC is a serial dependency chain, not a GEMM; AMX/tiles do not help. It is required ONLY to decode an *existing* `.265` bitstream (the M2 serial front-end). The substrate quantises to a small palette, so its entropy need is met by the SIMD-parallel palette-pack row above (SHIPPED module; PROPOSED as the codec's stage) — with, at most, a light static-rANS pass over the packed indices for the last few %. So "route around CABAC" = replace context-adaptive arithmetic coding with parallel palette-pack (+ optional non-adaptive rANS), NOT "zero entropy coding." The boundary is `.265`-compat, not the substrate's own entropy needs. |
5456

5557
## What amortizes, precisely
5658

5759
- **Build once, reuse per block.** The transform basis (WHT ±1 sign matrix), the
5860
interpolation taps, the Morton pyramid, the palette/centroid codebooks, and the
5961
golden-spiral place template are **deterministic** — computed once, never
60-
stored per-block (helix principle). Every block pays only: a gather + 1–2 tile
61-
ops + a residue magnitude. The 64×64 gridlake = 4×4 = **16 tile ops**.
62-
- **One kernel, many stages.** ME, inverse transform, intra prediction, sub-pel,
63-
and covariance all route through `bf16_tile_gemm_16x16`. The substrate is the
64-
zero-FP cognitive shader (gather + tile ops), so "the codec IS the substrate"
65-
holds down to the instruction (`TDPBF16PS`).
62+
stored per-block (helix principle). The 64×64 gridlake = 4×4 = 16 tile positions.
63+
- **BUT: dispatch at the R-5 batch crossover — the tile path is NOT unconditional.**
64+
Per the companion plan's **R-5** rule (`pr-x12-codec-cognitive-substrate-mapping.md`
65+
§2.2; `pr-x12-substrate-canon-resolutions.md` §R-5): a single 32×32 DCT via
66+
butterflies is ~80 ops vs ~32K for the GEMM form — **per-block, butterflies win
67+
by ~400×**. The BF16 tile GEMM only wins **above** the batch crossover, where
68+
hardware fusion amortises across many blocks. Crossover is per-arch:
69+
**SPR = 64, ICX = 32, Zen4 = 96, Apple M = 256, Graviton = 128** blocks. So the
70+
amortized dispatch is: **per-CTU / low-latency / small-batch → per-block WHT
71+
butterflies; per-frame / large-batch (N ≥ crossover) → batched BF16 tile GEMM.**
72+
A ledger that read "every block pays a tile op" would mis-route small-CTU work
73+
onto the tile path and invalidate the measurement — ship both, dispatch on N.
74+
- **One kernel family, many stages.** ME, inverse transform, intra prediction,
75+
sub-pel, and covariance are all the same *algebra* (`M·X` / `Xᵀ·X` / `Mᵀ·Σ·M`),
76+
realised as **butterflies below the crossover, `bf16_tile_gemm_16x16` above it**.
77+
The substrate is the zero-FP cognitive shader (gather + tile/butterfly ops), so
78+
"the codec IS the substrate" holds down to the instruction (`TDPBF16PS` in the
79+
batched regime).
6680
- **The transform mostly vanishes.** Per #232, good motion whitens the residual
6781
and the transform's advantage → 1 (a no-op); where it survives it is a
6882
multiply-free WHT. So the amortized codec spends tile ops on prediction, not on
@@ -74,15 +88,19 @@ matching the DCT within 2%. Same ±1 sign butterfly, two names.
7488
(de)coding is inherently serial arithmetic coding; the tile substrate does not
7589
amortize it, and a real `.265` decoder still needs it (the M2 serial
7690
front-end). BUT the substrate does not *need* CABAC: it quantises to a small
77-
palette (≤256 basin/centroid indices), so its native entropy layer is
91+
palette (≤256 basin/centroid indices), so its entropy need can be met by
7892
**variable-width SIMD palette packing** (`ndarray::palette_codec`, the
7993
Pumpkin/Minecraft port — `unpack_indices_simd`, VPSHUFB, 16 idx/cycle,
80-
`transcode` for per-block bit-width). A substrate-native encode+decode is then
81-
fully parallel end to end — `gather + tile op + palette-pack`, no serial stage.
82-
The boundary is therefore `.265` *compatibility*, not the substrate's own
83-
entropy needs. (Palette packing is a rate/parallelism trade vs an optimal
84-
arithmetic coder — cheaper and parallel, near-optimal when the palette is
85-
well-chosen; a light rANS pass on the packed indices recovers the rest.)
94+
`transcode` for per-block bit-width). This module is **shipped + tested** but
95+
**not yet wired as the codec's entropy stage** (the shipped codec uses
96+
`hpc::codec::ans` static rANS over the 4 `CellMode` tags) — the wiring is the
97+
proposed change. The point stands: a substrate-native pipeline has **no
98+
context-adaptive serial stage**`gather + tile op + palette-pack` — with, at
99+
most, a *non-adaptive* static-rANS pass over the packed indices (order-0,
100+
interleavable, not a CABAC-style dependency chain). The boundary is `.265`
101+
*compatibility*, not the substrate's own entropy needs. (Palette packing is a
102+
rate/parallelism trade vs an optimal arithmetic coder — near-optimal when the
103+
palette is well-chosen.)
86104
2. **The golden-spiral is for directional/sparse data, not dense scalars.** Per
87105
#231 (measured negative), coding a *dense scalar* residual with sparse
88106
golden-spiral anchors loses to local DPCM; the golden-spiral / helix codec

0 commit comments

Comments
 (0)