Skip to main content

logicaffeine_compile/model/
author.rs

1//! A model's computation written as a LOGOS program, from its [`ModelSpec`].
2//!
3//! Every program here is ordinary LOGOS tensor sugar — the claim "the model is authored in LOGOS" rests on it — and
4//! nothing in it is written for one model: a layer's statements follow from its mixer, its feed-forward block and
5//! its norms. The forms are the ones a deployment runs: the single-token forward, a decode step over KV caches and
6//! recurrent state, a prefill chunk, a batch of decode steps; each also cut into its embedding, its layers and its
7//! head, so a backend can lower a layer at a time. Weights are declared as tensors the host fills, and recorded with
8//! the file each is loaded from: `<var>.f` (f32) or `<var>.q`/`<var>.s` (Q8_0 quants and block scales).
9//!
10//! A stacked form (prefill, batch) carries its tensors with a `b` prefix (`bxn0`); per-sequence state carries a
11//! `_s{b}` suffix (`Kc3_s1`).
12
13use std::collections::HashMap;
14
15use super::bind::{rotation_of, rotations, HostTable, RotaryTable};
16use super::spec::{Act, Attention, Ffn, GateActivation, GatedDelta, Gating, Mixer, Mla, ModelSpec};
17
18/// A program and its weight manifest: `(source, f32 weights → (file, count), q8 weights → file stem)`.
19pub type Authored = (
20    String,
21    HashMap<String, (String, usize)>,
22    HashMap<String, String>,
23);
24
25/// Why a spec cannot be written as a program yet.
26#[derive(Clone, Debug, PartialEq, Eq)]
27pub struct NotYet(pub &'static str);
28
29impl std::fmt::Display for NotYet {
30    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31        write!(f, "the language cannot write {} yet", self.0)
32    }
33}
34
35/// Can every layer of `spec` be written in the language as it stands? The sugar's rotation is NEOX-paired (an
36/// interleaved checkpoint is bound through a per-head permutation of its Q and K rows, a fused projection through each
37/// part's rows); an attention reads values of any width at the scale it gives, its scores and the logits soft-capped
38/// where the model caps them, and a latent attention its latent at the scale it gives.
39pub fn check(spec: &ModelSpec) -> Result<(), NotYet> {
40    if !(spec.rms_eps.is_finite() && spec.rms_eps > 0.0) {
41        return Err(NotYet("an RMSNorm epsilon that is not a positive number"));
42    }
43    if spec.final_logit_softcap.is_some_and(|cap| !(cap.is_finite() && cap > 0.0)) {
44        return Err(NotYet("a final logit softcap that is not a positive number"));
45    }
46    // Qwen3.8-Flash-Next's parts: a program written without them would compute another model.
47    if spec.hyper.is_some() {
48        return Err(NotYet("hyper-connections in place of the norms"));
49    }
50    if spec.ple.is_some() {
51        return Err(NotYet("a per-layer n-gram embedding"));
52    }
53    if spec.indexer.as_ref().is_some_and(|ix| !ix.layers.is_empty()) {
54        return Err(NotYet("a sparse selection of the attended positions (QSA)"));
55    }
56    for layer in &spec.layers {
57        if let Mixer::Attention(a) = &layer.mixer {
58            if a.output_gate && (a.fused_qkv || a.value_dim != a.head_dim) {
59                return Err(NotYet("an output gate on a fused projection or over values unlike the keys in width"));
60            }
61            if a.softcap.is_some_and(|cap| !(cap.is_finite() && cap > 0.0)) {
62                return Err(NotYet("an attention softcap that is not a positive number"));
63            }
64            if a.temperature.is_some() && a.head_dim % 2 != 0 {
65                return Err(NotYet("an attention temperature over an odd head width"));
66            }
67        }
68        match &layer.ffn {
69            Ffn::Dense { act, .. } if !matches!(act, Act::Silu | Act::GeluTanh) => {
70                return Err(NotYet("a gated activation other than SiLU or GeLU"))
71            }
72            Ffn::Moe(m) if !matches!(m.act, Act::Silu | Act::SwigluOai { .. }) => {
73                return Err(NotYet("an expert mixture other than top-k experts gated by a SwiGLU"))
74            }
75            Ffn::Moe(m) if !(m.weights_scale.is_finite() && m.weights_scale >= 0.0) => {
76                return Err(NotYet("a routed scale that is not a positive number"))
77            }
78            Ffn::Moe(m) if m.shared_experts > 0 && m.act != Act::Silu => {
79                return Err(NotYet("shared experts gated other than by a SwiGLU"))
80            }
81            // A softmax over the kept logits chooses by the logits themselves, so its groups would rank by logits where
82            // the sugar ranks them by scores.
83            Ffn::Moe(m) if m.gating == Gating::SoftmaxOfTopK && m.groups.is_some() => {
84                return Err(NotYet("a group limit over a softmax of the kept logits"))
85            }
86            Ffn::Moe(m)
87                if m.groups.is_some_and(|(count, used)| {
88                    count == 0 || m.experts % count != 0 || !(1..=count).contains(&used) || used * (m.experts / count) < m.top_k
89                }) =>
90            {
91                return Err(NotYet("a group limit that does not split the experts evenly or keeps fewer than it chooses"))
92            }
93            _ => {}
94        }
95    }
96    Ok(())
97}
98
99/// The program `src` with every norm statement given the model's epsilon `eps` — the RMSNorms, the gated delta rule's
100/// output norm and the L2 norms of its queries and keys, all of which the model computes with its one epsilon. The
101/// sugar's own epsilon is 1e-6, so a model with that one is written without the clause.
102fn with_epsilon(src: &str, eps: f64) -> String {
103    if eps == 1e-6 {
104        return src.to_string();
105    }
106    src.lines()
107        .map(|line| {
108            let norm = [" be rmsnorm of ", " be l2norm of ", " be gated delta of "].iter().any(|n| line.contains(n));
109            match line.strip_suffix('.') {
110                Some(stmt) if norm && line.starts_with("Let ") => format!("{stmt} with epsilon {eps:?}.\n"),
111                _ => format!("{line}\n"),
112            }
113        })
114        .collect()
115}
116
117/// How an attention layer reads its keys and values.
118#[derive(Clone, Copy, Debug, PartialEq, Eq)]
119pub enum AttnForm {
120    /// The current token's own key and value — the forward of one token with no history.
121    Current,
122    /// A decode step's KV cache of `ctx` positions: this token's key and value are appended as row `pos`, and the
123    /// layer attends over the first `pos` rows. The caches are the step's carried state.
124    Cached { ctx: usize },
125}
126
127/// Whose carried state the rows of a stacked step update.
128#[derive(Clone, Copy, Debug, PartialEq, Eq)]
129pub enum RowState {
130    /// Each row is its own sequence with its own state — a batched decode step (`Kc3_s1`).
131    PerSequence,
132    /// Every row is the next token of ONE sequence — a prefill chunk: the rows update the sequence's single state
133    /// (`Kc3`, the decode step's own), one after another.
134    Shared,
135}
136
137impl RowState {
138    /// The name row `b`'s copy of the state tensor `base` goes by.
139    fn state(self, base: &str, b: usize) -> String {
140        match self {
141            RowState::PerSequence => format!("{base}_s{b}"),
142            RowState::Shared => base.to_string(),
143        }
144    }
145
146    /// The rows whose copy of the state is declared: every row's, or the one the rows share.
147    fn holders(self, bsz: usize) -> std::ops::Range<usize> {
148        match self {
149            RowState::PerSequence => 0..bsz,
150            RowState::Shared => 0..1,
151        }
152    }
153}
154
155/// A program being written, and the weights it declares.
156struct Program<'a> {
157    spec: &'a ModelSpec,
158    dir: &'a str,
159    s: String,
160    f32w: HashMap<String, (String, usize)>,
161    q8w: HashMap<String, String>,
162}
163
164/// The widths a layer's statements use: the queries' and keys' `aq` and `akv`, the values' `avd` and the attended
165/// rows' `ao` (`kv_heads` and `heads` of `value_dim`).
166struct Dims {
167    d: usize,
168    aq: usize,
169    akv: usize,
170    avd: usize,
171    ao: usize,
172    hd: usize,
173    h: usize,
174    kv: usize,
175}
176
177fn attn_dims(spec: &ModelSpec, a: &Attention) -> Dims {
178    Dims {
179        d: spec.d,
180        aq: a.heads * a.head_dim,
181        akv: a.kv_heads * a.head_dim,
182        avd: a.kv_heads * a.value_dim,
183        ao: a.heads * a.value_dim,
184        hd: a.head_dim,
185        h: a.heads,
186        kv: a.kv_heads,
187    }
188}
189
190impl<'a> Program<'a> {
191    fn new(spec: &'a ModelSpec, dir: &'a str) -> Self {
192        Program {
193            spec,
194            dir,
195            s: String::from("## Main\n"),
196            f32w: HashMap::new(),
197            q8w: HashMap::new(),
198        }
199    }
200
201    fn finish(self) -> Authored {
202        (with_epsilon(&self.s, self.spec.rms_eps), self.f32w, self.q8w)
203    }
204
205    fn decl_f32(&mut self, var: &str, r: usize, c: usize) {
206        self.s.push_str(&format!("Let {var} be a {r} by {c} tensor of Real.\n"));
207        self.f32w
208            .insert(var.to_string(), (format!("{}/{var}.f", self.dir), r * c));
209    }
210
211    fn decl_q8(&mut self, var: &str, r: usize, c: usize) {
212        self.s.push_str(&format!("Let {var} be a {r} by {c} tensor of Real.\n"));
213        self.q8w.insert(var.to_string(), format!("{}/{var}", self.dir));
214    }
215
216    /// The rotary tables of every rotation the layers `only` names (all of them when `None`) turn by: a decode step's
217    /// caches of `ctx` positions (`cached`), or a forward's one row — `dims / 2` angles a position.
218    fn rotary_tables(&mut self, only: Option<usize>, cached: bool, ctx: usize) {
219        let spec = self.spec;
220        for (rotation, rope) in rotations(spec).into_iter().enumerate() {
221            if only.is_some_and(|l| rotation_of(spec, l) != Some(rotation)) {
222                continue;
223            }
224            for cos in [true, false] {
225                let name = RotaryTable { rotation, cached, cos }.name();
226                self.decl_f32(&name, if cached { ctx } else { 1 }, rope.dims / 2);
227            }
228        }
229    }
230
231    /// A host table (`model::bind::HostTable`) declared once for the program, `rows` by `cols`: its name.
232    fn host_table(&mut self, table: HostTable, rows: usize, cols: usize) -> String {
233        let name = table.name();
234        if !self.f32w.contains_key(&name) {
235            self.decl_f32(&name, rows, cols);
236        }
237        name
238    }
239
240    /// Llama 4's query and key after the rotation: each normed per head (`norm_heads` query and key heads) by an RMSNorm
241    /// whose weight is a row of ones, when the layer norms them; on a rotation-free layer the query (`rope_heads` heads)
242    /// scaled by its position's attention temperature — a rotation whose cosine is the factor and whose sine is zero,
243    /// read from position `from` of a decode step's tables of `ctx` positions, or a forward's one row when `from` is
244    /// `None`. `name` names each intermediate from its base.
245    fn llama4_qk(
246        &mut self,
247        a: &Attention,
248        (q, k): (String, String),
249        norm_heads: (usize, usize),
250        rope_heads: usize,
251        from: Option<(String, usize)>,
252        name: &dyn Fn(&str) -> String,
253    ) -> (String, String) {
254        let (mut q, mut k) = (q, k);
255        if a.qk_unit_norm {
256            let ones = self.host_table(HostTable::Ones(a.head_dim), 1, a.head_dim);
257            let (qu, ku, (hq, hkv)) = (name("qu"), name("ku"), norm_heads);
258            self.s.push_str(&format!(
259                "Let {qu} be rmsnorm of {q} with weight {ones} across {hq} heads.\n\
260                 Let {ku} be rmsnorm of {k} with weight {ones} across {hkv} heads.\n"
261            ));
262            (q, k) = (qu, ku);
263        }
264        if a.temperature.is_some() {
265            let half = a.head_dim / 2;
266            let (cached, rows) = from.as_ref().map_or((false, 1), |(_, ctx)| (true, *ctx));
267            let cos = self.host_table(HostTable::Temperature { cached, cos: true, half }, rows, half);
268            let sin = self.host_table(HostTable::Temperature { cached, cos: false, half }, rows, half);
269            let at = from.as_ref().map_or(String::new(), |(pos, _)| format!(" from position {pos}"));
270            let qt = name("qt");
271            self.s.push_str(&format!("Let {qt} be rope of {q} with cos {cos} and sin {sin}{at} across {rope_heads} heads.\n"));
272            q = qt;
273        }
274        (q, k)
275    }
276
277    /// The angles layer `l`'s rope reads, as the sugar names them: the forward's one-row tables, or a decode step's
278    /// caches from the position `pos` names.
279    fn angles(&self, l: usize, form: AttnForm, pos: &str) -> String {
280        let rotation = rotation_of(self.spec, l).expect("a layer that rotates");
281        let cached = matches!(form, AttnForm::Cached { .. });
282        let (cos, sin) = (RotaryTable { rotation, cached, cos: true }.name(), RotaryTable { rotation, cached, cos: false }.name());
283        match form {
284            AttnForm::Current => format!("cos {cos} and sin {sin}"),
285            AttnForm::Cached { .. } => format!("cos {cos} and sin {sin} from position {pos}"),
286        }
287    }
288
289    /// `out = act(gate)·up`, the gated activation of layer `l`'s dense FFN, written into the program; the names it
290    /// binds, `out` last.
291    fn glu(&mut self, l: usize, gate: &str, up: &str, out: &str) -> Vec<String> {
292        match &self.spec.layers[l].ffn {
293            Ffn::Dense { act: Act::GeluTanh, .. } => {
294                let act = format!("{out}_a");
295                self.s.push_str(&format!("Let {act} be gelu of {gate}.\nLet {out} be {act} hadamard {up}.\n"));
296                vec![act, out.to_string()]
297            }
298            _ => {
299                self.s.push_str(&format!("Let {out} be swiglu of {gate} and {up}.\n"));
300                vec![out.to_string()]
301            }
302        }
303    }
304
305    /// The block output `x` as the residual adds it: `x` itself, or — after a mixer (`after_mixer`) or an FFN whose
306    /// layer norms its output too (Gemma's sandwich) — `x` normed by the layer's post-norm weight.
307    fn post_norm(&mut self, l: usize, x: &str, after_mixer: bool) -> String {
308        let layer = &self.spec.layers[l];
309        let (on, weight) = if after_mixer { (layer.post_mixer_norm, "pan") } else { (layer.post_ffn_norm, "pfn") };
310        if !on {
311            return x.to_string();
312        }
313        let w = format!("{weight}{l}");
314        if !self.f32w.contains_key(&w) {
315            self.decl_f32(&w, 1, self.spec.d);
316        }
317        self.s.push_str(&format!("Let {x}n be rmsnorm of {x} with weight {w}.\n"));
318        format!("{x}n")
319    }
320
321    /// `Let out be x matmul w`, plus the row `bias` (declared once, `width` wide) when the layer has one — the matmul then
322    /// binds `out_r` and `out` is the biased sum, so every later statement reads `out` alike.
323    fn project(&mut self, out: &str, x: &str, w: &str, bias: Option<String>, width: usize) {
324        match bias {
325            Some(b) => {
326                if !self.f32w.contains_key(&b) {
327                    self.decl_f32(&b, 1, width);
328                }
329                self.s.push_str(&format!("Let {out}_r be {x} matmul {w}.\nLet {out} be {out}_r plus {b}.\n"));
330            }
331            None => self.s.push_str(&format!("Let {out} be {x} matmul {w}.\n")),
332        }
333    }
334
335    /// An attention's sinks clause, ` with sinks Sk{l}` (the sinks declared once), or nothing.
336    fn sinks(&mut self, l: usize, a: &Attention) -> String {
337        if !a.sinks {
338            return String::new();
339        }
340        let sk = format!("Sk{l}");
341        if !self.f32w.contains_key(&sk) {
342            self.decl_f32(&sk, 1, a.heads);
343        }
344        format!(" with sinks {sk}")
345    }
346
347    /// The embedding rows `rows` as the first layer reads them, bound to `out`: scaled by the model's embedding scale
348    /// when it has one.
349    fn embedded(&mut self, rows: &str, out: &str) {
350        match self.spec.embedding_scale {
351            Some(scale) => self.s.push_str(&format!("Let {out}e be {rows}.\nLet {out} be {out}e scaled by {scale:?}.\n")),
352            None => self.s.push_str(&format!("Let {out} be {rows}.\n")),
353        }
354    }
355
356    /// Layer `l`, reading the hidden state `cur` and producing `xo{l}`.
357    fn layer(&mut self, l: usize, cur: &str, form: AttnForm) {
358        let spec = self.spec;
359        self.decl_f32(&format!("an{l}"), 1, spec.d);
360        match &spec.layers[l].mixer {
361            Mixer::Attention(a) => self.attention(l, a, cur, form),
362            Mixer::GatedDelta(g) => self.gated_delta(l, g, cur),
363            Mixer::Mla(m) => self.mla(l, m, cur, form),
364        }
365        self.ffn(l, cur, None);
366    }
367
368    /// A latent attention layer's weights and, in a decode step, its caches of `ctx` rows of the latent and the shared
369    /// rotated key (`kv_lora_rank + qk_rope` wide) — one, or one a sequence of a batch of `bsz`.
370    fn mla_weights(&mut self, l: usize, m: &Mla, ctx: Option<(usize, usize, RowState)>) {
371        let d = self.spec.d;
372        let (h, qk, lora, kw) = (m.heads, m.qk_nope + m.qk_rope, m.kv_lora_rank, m.kv_lora_rank + m.qk_rope);
373        match m.q_lora_rank {
374            None => self.decl_q8(&format!("Wq{l}"), d, h * qk),
375            Some(r) => {
376                self.decl_q8(&format!("Wqa{l}"), d, r);
377                self.decl_f32(&format!("Qan{l}"), 1, r);
378                self.decl_q8(&format!("Wqb{l}"), r, h * qk);
379            }
380        }
381        self.decl_q8(&format!("Wkva{l}"), d, kw);
382        self.decl_f32(&format!("Kan{l}"), 1, lora);
383        self.decl_q8(&format!("Wkb{l}"), h * m.qk_nope, lora);
384        self.decl_q8(&format!("Wvb{l}"), h * lora, m.v_dim);
385        self.decl_q8(&format!("Wo{l}"), h * m.v_dim, d);
386        if let Some((ctx, bsz, rows)) = ctx {
387            for b in rows.holders(bsz) {
388                self.s.push_str(&format!("Let {} be a {ctx} by {kw} tensor of Real.\n", rows.state(&format!("Kc{l}"), b)));
389            }
390        }
391    }
392
393    /// The position-free half of a latent attention, from its normed input `{p}xn{l}` (a stack when `p` is `b`): the
394    /// query (through its low-rank halves when it has them) cut into each head's unrotated part — absorbed into the
395    /// latent's space by `Wkb` as `{p}ql{l}` — and its rotated part `{p}qe{l}`; the latent `{p}kvn{l}`, RMS-normed; the
396    /// shared key's rotated part `{p}kpe{l}`.
397    fn mla_projections(&mut self, l: usize, m: &Mla, p: &str) {
398        let (h, nope, rope, lora) = (m.heads, m.qk_nope, m.qk_rope, m.kv_lora_rank);
399        let (qk, kw) = (nope + rope, lora + rope);
400        match m.q_lora_rank {
401            None => self.s.push_str(&format!("Let {p}qr{l} be {p}xn{l} matmul Wq{l}.\n")),
402            Some(_) => self.s.push_str(&format!(
403                "Let {p}qx{l} be {p}xn{l} matmul Wqa{l}.\n\
404                 Let {p}qxn{l} be rmsnorm of {p}qx{l} with weight Qan{l}.\n\
405                 Let {p}qr{l} be {p}qxn{l} matmul Wqb{l}.\n"
406            )),
407        }
408        self.s.push_str(&format!(
409            "Let {p}kva{l} be {p}xn{l} matmul Wkva{l}.\n\
410             Let {p}kvl{l} be the first {lora} of every {kw} of {p}kva{l}.\n\
411             Let {p}kpe{l} be the last {rope} of every {kw} of {p}kva{l}.\n\
412             Let {p}kvn{l} be rmsnorm of {p}kvl{l} with weight Kan{l}.\n\
413             Let {p}qn{l} be the first {nope} of every {qk} of {p}qr{l}.\n\
414             Let {p}qe{l} be the last {rope} of every {qk} of {p}qr{l}.\n\
415             Let {p}ql{l} be {p}qn{l} matmul Wkb{l} across {h} heads.\n"
416        ));
417    }
418
419    /// The position's half: the shared key's part `{x}kpe{t}` and the queries' rotated parts `{x}qe{t}` turned by
420    /// `angles`, joined after the latent `{x}kvn{t}` into the cache row `{x}kc{t}` and after the absorbed queries
421    /// `{x}ql{t}` into each head's query `{x}qa{t}` — `x` the stack prefix and `t` the layer and sequence suffix.
422    fn mla_turned(&mut self, m: &Mla, x: &str, t: &str, angles: &str) {
423        let h = m.heads;
424        self.s.push_str(&format!(
425            "Let {x}kpp{t} be rope of {x}kpe{t} with {angles} across 1 heads.\n\
426             Let {x}kc{t} be {x}kvn{t} joined with {x}kpp{t}.\n\
427             Let {x}qpp{t} be rope of {x}qe{t} with {angles} across {h} heads.\n\
428             Let {x}qa{t} be {x}ql{t} joined with {x}qpp{t} across {h} heads.\n"
429        ));
430    }
431
432    /// MULTI-HEAD LATENT ATTENTION, ABSORBED (llama.cpp `models/deepseek2.cpp`'s MLA path): the cache holds one row a
433    /// position, the RMS-normed latent then the shared rotated key; each head's query reaches the latent's space
434    /// through `Wkb` (the key half of the expansion), so every head attends over the same rows, one key/value group —
435    /// its values the rows' latent part — at the score scale the model gives; each head's attended latent leaves
436    /// through `Wvb` (the value half), and `Wo` projects the heads. The same scores the expanded attention takes, over a
437    /// cache `heads · (qk_nope + v_dim) / (kv_lora_rank + qk_rope)` times smaller.
438    fn mla(&mut self, l: usize, m: &Mla, cur: &str, form: AttnForm) {
439        let (d, h, lora, kw, scale) = (self.spec.d, m.heads, m.kv_lora_rank, m.kv_lora_rank + m.qk_rope, m.scale);
440        let ctx = match form {
441            AttnForm::Cached { ctx } => Some((ctx, 1, RowState::Shared)),
442            AttnForm::Current => None,
443        };
444        self.mla_weights(l, m, ctx);
445        self.s.push_str(&format!("Let xn{l} be rmsnorm of {cur} with weight an{l}.\n"));
446        let angles = self.angles(l, form, "pos");
447        self.mla_projections(l, m, "");
448        self.mla_turned(m, "", &l.to_string(), &angles);
449        match form {
450            AttnForm::Current => self.s.push_str(&format!(
451                "Let Vl{l} be the first {lora} of every {kw} of kc{l}.\n\
452                 Let ol{l} be attention of qa{l} over kc{l} and Vl{l} with {h} heads 1 groups scaled by {scale:?}.\n"
453            )),
454            AttnForm::Cached { .. } => self.s.push_str(&format!(
455                "Set row pos of Kc{l} to kc{l}.\n\
456                 Let Vl{l} be the first {lora} of every {kw} of Kc{l}.\n\
457                 Let ol{l} be attention of qa{l} over Kc{l} and Vl{l} with {h} heads 1 groups up to pos scaled by {scale:?}.\n"
458            )),
459        }
460        self.s.push_str(&format!("Let ct{l} be ol{l} matmul Wvb{l} across {h} heads.\n"));
461        self.project(&format!("ao{l}"), &format!("ct{l}"), &format!("Wo{l}"), None, d);
462    }
463
464    /// [`Self::mla`] on a stack of `bsz` rows: the position-free half on the whole stack, then one sequence's chunk
465    /// turning and appending its rows as a block and attending as one causal block, or each row its own sequence's
466    /// step.
467    fn stacked_mla(&mut self, l: usize, m: &Mla, cur: &str, ctx: usize, bsz: usize, rows: RowState) {
468        let (d, h, lora, kw, scale) = (self.spec.d, m.heads, m.kv_lora_rank, m.kv_lora_rank + m.qk_rope, m.scale);
469        self.mla_weights(l, m, Some((ctx, bsz, rows)));
470        self.s.push_str(&format!("Let bxn{l} be rmsnorm of {cur} with weight an{l}.\n"));
471        self.mla_projections(l, m, "b");
472        match rows {
473            RowState::Shared => {
474                let angles = self.angles(l, AttnForm::Cached { ctx }, "pos_s0");
475                self.mla_turned(m, "b", &l.to_string(), &angles);
476                let kc = rows.state(&format!("Kc{l}"), 0);
477                self.s.push_str(&format!(
478                    "Set rows from pos_s0 of {kc} to bkc{l}.\n\
479                     Let Vl{l} be the first {lora} of every {kw} of {kc}.\n\
480                     Let bol{l} be causal attention of bqa{l} over {kc} and Vl{l} with {h} heads 1 groups from pos_s0 scaled by {scale:?}.\n"
481                ));
482            }
483            // Each sequence's row turns by its own position, appends to its own cache and attends it.
484            RowState::PerSequence => {
485                self.s.push_str(&format!("Let bol{l} be a {bsz} by {} tensor of Real.\n", h * lora));
486                for b in 0..bsz {
487                    let (r, t) = (b + 1, format!("{l}_s{b}"));
488                    let angles = self.angles(l, AttnForm::Cached { ctx }, &format!("pos_s{b}"));
489                    for part in ["kvn", "kpe", "ql", "qe"] {
490                        self.s.push_str(&format!("Let {part}{t} be row {r} of b{part}{l}.\n"));
491                    }
492                    self.mla_turned(m, "", &t, &angles);
493                    let kc = rows.state(&format!("Kc{l}"), b);
494                    self.s.push_str(&format!(
495                        "Set row pos_s{b} of {kc} to kc{t}.\n\
496                         Let Vl{t} be the first {lora} of every {kw} of {kc}.\n\
497                         Let ol{t} be attention of qa{t} over {kc} and Vl{t} with {h} heads 1 groups up to pos_s{b} scaled by {scale:?}.\n\
498                         Set row {r} of bol{l} to ol{t}.\n"
499                    ));
500                }
501            }
502        }
503        self.s.push_str(&format!("Let bct{l} be bol{l} matmul Wvb{l} across {h} heads.\n"));
504        self.project(&format!("bao{l}"), &format!("bct{l}"), &format!("Wo{l}"), None, d);
505    }
506
507    fn attention(&mut self, l: usize, a: &Attention, cur: &str, form: AttnForm) {
508        let Dims { d, aq, akv, avd, ao, h, kv, .. } = attn_dims(self.spec, a);
509        self.decl_q8(&format!("Wq{l}"), d, aq);
510        if a.output_gate {
511            self.decl_q8(&format!("Wqg{l}"), d, aq);
512        }
513        self.decl_q8(&format!("Wk{l}"), d, akv);
514        self.decl_q8(&format!("Wv{l}"), d, avd);
515        let ((nq, nk), (wq, wk)) = qk_norm_segments(a);
516        if a.qk_norm {
517            self.decl_f32(&format!("Qn{l}"), 1, wq);
518            self.decl_f32(&format!("Kn{l}"), 1, wk);
519        }
520        self.decl_q8(&format!("Wo{l}"), ao, d);
521        if let AttnForm::Cached { ctx } = form {
522            self.s.push_str(&format!(
523                "Let Kc{l} be a {ctx} by {akv} tensor of Real.\nLet Vc{l} be a {ctx} by {avd} tensor of Real.\n"
524            ));
525        }
526        let bias = |b: &str| a.bias.then(|| format!("{b}{l}"));
527        self.s.push_str(&format!("Let xn{l} be rmsnorm of {cur} with weight an{l}.\n"));
528        self.project(&format!("qr{l}"), &format!("xn{l}"), &format!("Wq{l}"), bias("Bq"), aq);
529        if a.output_gate {
530            self.s.push_str(&format!("Let gr{l} be xn{l} matmul Wqg{l}.\n"));
531        }
532        self.project(&format!("kr{l}"), &format!("xn{l}"), &format!("Wk{l}"), bias("Bk"), akv);
533        self.project(&format!("vr{l}"), &format!("xn{l}"), &format!("Wv{l}"), bias("Bv"), avd);
534        let (mut q, mut k) = (format!("qr{l}"), format!("kr{l}"));
535        if a.qk_norm {
536            self.s.push_str(&format!(
537                "Let qm{l} be rmsnorm of qr{l} with weight Qn{l} across {nq} heads.\n\
538                 Let km{l} be rmsnorm of kr{l} with weight Kn{l} across {nk} heads.\n"
539            ));
540            (q, k) = (format!("qm{l}"), format!("km{l}"));
541        }
542        if a.rope.is_some() {
543            let angles = self.angles(l, form, "pos");
544            self.s.push_str(&format!(
545                "Let qp{l} be rope of {q} with {angles} across {h} heads.\n\
546                 Let kp{l} be rope of {k} with {angles} across {kv} heads.\n"
547            ));
548            (q, k) = (format!("qp{l}"), format!("kp{l}"));
549        }
550        let from = match form {
551            AttnForm::Current => None,
552            AttnForm::Cached { ctx } => Some(("pos".to_string(), ctx)),
553        };
554        (q, k) = self.llama4_qk(a, (q, k), (h, kv), h, from, &|base| format!("{base}{l}"));
555        let (w, sk) = (score_clauses(a), self.sinks(l, a));
556        match form {
557            AttnForm::Current => self.s.push_str(&format!(
558                "Let ct{l} be attention of {q} over {k} and vr{l} with {h} heads {kv} groups{w}{sk}.\n"
559            )),
560            AttnForm::Cached { .. } => self.s.push_str(&format!(
561                "Set row pos of Kc{l} to {k}.\n\
562                 Set row pos of Vc{l} to vr{l}.\n\
563                 Let ct{l} be attention of {q} over Kc{l} and Vc{l} with {h} heads {kv} groups up to pos{w}{sk}.\n"
564            )),
565        }
566        let gated = if a.output_gate {
567            self.s.push_str(&format!("Let gs{l} be sigmoid of gr{l}.\nLet cg{l} be ct{l} hadamard gs{l}.\n"));
568            format!("cg{l}")
569        } else {
570            format!("ct{l}")
571        };
572        self.project(&format!("ao{l}"), &gated, &format!("Wo{l}"), a.output_bias.then(|| format!("Bo{l}")), d);
573    }
574
575    fn gated_delta(&mut self, l: usize, g: &GatedDelta, cur: &str) {
576        let gate = gate_clause(g);
577        let d = self.spec.d;
578        let (qk, vw, taps) = (g.k_heads * g.head_dim, g.v_heads * g.head_dim, g.conv_taps);
579        let (nk, nv, ghd) = (g.k_heads, g.v_heads, g.head_dim);
580        self.decl_q8(&format!("Wq{l}"), d, qk);
581        self.decl_q8(&format!("Wk{l}"), d, qk);
582        self.decl_q8(&format!("Wv{l}"), d, vw);
583        self.decl_q8(&format!("Wz{l}"), d, vw);
584        self.decl_f32(&format!("Wcq{l}"), taps, qk);
585        self.decl_f32(&format!("Wck{l}"), taps, qk);
586        self.decl_f32(&format!("Wcv{l}"), taps, vw);
587        self.decl_f32(&format!("Csq{l}"), taps, qk);
588        self.decl_f32(&format!("Csk{l}"), taps, qk);
589        self.decl_f32(&format!("Csv{l}"), taps, vw);
590        self.decl_q8(&format!("Wb{l}"), d, nv);
591        self.decl_q8(&format!("Wa{l}"), d, nv);
592        self.decl_f32(&format!("Dt{l}"), 1, nv);
593        self.decl_f32(&format!("Al{l}"), 1, nv);
594        self.decl_f32(&format!("St{l}"), vw, ghd);
595        self.decl_f32(&format!("Gn{l}"), 1, ghd);
596        self.decl_q8(&format!("Wo{l}"), vw, d);
597        self.s.push_str(&format!(
598            "Let xn{l} be rmsnorm of {cur} with weight an{l}.\n\
599             Let qr{l} be xn{l} matmul Wq{l}.\n\
600             Let kr{l} be xn{l} matmul Wk{l}.\n\
601             Let vr{l} be xn{l} matmul Wv{l}.\n\
602             Let zz{l} be xn{l} matmul Wz{l}.\n\
603             Let qc{l} be causal conv of qr{l} with weight Wcq{l} state Csq{l} over {taps} taps.\n\
604             Let kc{l} be causal conv of kr{l} with weight Wck{l} state Csk{l} over {taps} taps.\n\
605             Let vc{l} be causal conv of vr{l} with weight Wcv{l} state Csv{l} over {taps} taps.\n\
606             Let qs{l} be silu of qc{l}.\n\
607             Let ks{l} be silu of kc{l}.\n\
608             Let vs{l} be silu of vc{l}.\n\
609             Let qn{l} be l2norm of qs{l} across {nk} heads.\n\
610             Let kn{l} be l2norm of ks{l} across {nk} heads.\n\
611             Let br{l} be xn{l} matmul Wb{l}.\n\
612             Let bt{l} be sigmoid of br{l}.\n\
613             Let ar{l} be xn{l} matmul Wa{l}.\n\
614             Let dy{l} be decay of ar{l} with bias Dt{l} rate Al{l}.\n\
615             Let od{l} be gated delta of qn{l} over kn{l} and vs{l} with {gate} zz{l} beta bt{l} decay dy{l} state St{l} norm Gn{l} with {nv} heads {nk} groups.\n\
616             Let ao{l} be od{l} matmul Wo{l}.\n",
617        ));
618    }
619
620    /// The block's tail: the residual, the pre-FFN norm, the FFN and the second residual — for one row, or for a
621    /// stack of `rows` (its tensors prefixed `b`).
622    fn ffn(&mut self, l: usize, cur: &str, rows: Option<usize>) {
623        let d = self.spec.d;
624        let p = if rows.is_some() { "b" } else { "" };
625        self.decl_f32(&format!("fn{l}"), 1, d);
626        match self.spec.layers[l].ffn.clone() {
627            Ffn::Dense { dff, .. } => {
628                self.decl_q8(&format!("Wg{l}"), d, dff);
629                self.decl_q8(&format!("Wu{l}"), d, dff);
630                self.decl_q8(&format!("Wd{l}"), dff, d);
631                let ao = self.post_norm(l, &format!("{p}ao{l}"), true);
632                self.s.push_str(&format!(
633                    "Let {p}xr{l} be {cur} plus {ao}.\n\
634                     Let {p}x2n{l} be rmsnorm of {p}xr{l} with weight fn{l}.\n\
635                     Let {p}gt{l} be {p}x2n{l} matmul Wg{l}.\n\
636                     Let {p}up{l} be {p}x2n{l} matmul Wu{l}.\n"
637                ));
638                self.glu(l, &format!("{p}gt{l}"), &format!("{p}up{l}"), &format!("{p}hh{l}"));
639                self.s.push_str(&format!("Let {p}dn{l} be {p}hh{l} matmul Wd{l}.\n"));
640                let dn = self.post_norm(l, &format!("{p}dn{l}"), false);
641                self.s.push_str(&format!("Let {p}xo{l} be {p}xr{l} plus {dn}.\n"));
642            }
643            Ffn::Moe(m) => {
644                let (e, k, dff) = (m.experts, m.top_k, m.expert_dff);
645                self.decl_q8(&format!("Wr{l}"), d, e);
646                self.decl_q8(&format!("Wg{l}"), e * dff, d);
647                self.decl_q8(&format!("Wu{l}"), e * dff, d);
648                self.decl_q8(&format!("Wd{l}"), e * d, dff);
649                let ao = self.post_norm(l, &format!("{p}ao{l}"), true);
650                self.s.push_str(&format!(
651                    "Let {p}xr{l} be {cur} plus {ao}.\n\
652                     Let {p}x2n{l} be rmsnorm of {p}xr{l} with weight fn{l}.\n"
653                ));
654                if m.biases {
655                    self.decl_f32(&format!("Br{l}"), 1, e);
656                    self.decl_f32(&format!("Bg{l}"), e, dff);
657                    self.decl_f32(&format!("Bu{l}"), e, dff);
658                    self.decl_f32(&format!("Bd{l}"), e, d);
659                }
660                if m.gating == (Gating::Sigmoid { bias: true }) {
661                    self.decl_f32(&format!("Bs{l}"), 1, e);
662                }
663                let plus = |b: &str| if m.biases { format!(" plus {b}{l}") } else { String::new() };
664                let (br, bg, bu, bd) = (plus("Br"), plus("Bg"), plus("Bu"), plus("Bd"));
665                let act = match m.act {
666                    Act::SwigluOai { alpha, limit } => format!(" using a swiglu clamped at {limit:?} with slope {alpha:?}"),
667                    _ => String::new(),
668                };
669                // A softmax over the kept experts is the softmax over all, renormalized over them. Sigmoid scores are each
670                // expert's own, DeepSeek-V3's chosen by each plus its selection bias, and Llama 4's weigh the inputs; a
671                // routed scale of zero is llama.cpp's absent one.
672                let score = match m.gating {
673                    Gating::Sigmoid { bias: true } => format!(" by sigmoid biased by Bs{l}"),
674                    Gating::Sigmoid { .. } | Gating::SigmoidScaledInput => " by sigmoid".to_string(),
675                    _ => String::new(),
676                };
677                let groups = m.groups.map_or(String::new(), |(count, used)| format!(" within the top {used} of {count} groups"));
678                let norm = match !matches!(m.gating, Gating::SoftmaxOfTopK) && !m.norm_top_k {
679                    true => " without renormalizing",
680                    false => "",
681                };
682                let scale = match m.weights_scale {
683                    s if s == 0.0 || s == 1.0 => String::new(),
684                    s => format!(" scaled by {s:?}"),
685                };
686                let inputs = match m.gating {
687                    Gating::SigmoidScaledInput => " weighting the inputs",
688                    _ => "",
689                };
690                let route = |x: &str, out: &str| {
691                    format!(
692                        "Let {out} be moe of {x} with router Wr{l}{br} gate Wg{l}{bg} up Wu{l}{bu} down Wd{l}{bd} choosing {k} of {e}{score}{groups}{norm}{scale}{inputs}{act}.\n"
693                    )
694                };
695                match rows {
696                    None => self.s.push_str(&route(&format!("x2n{l}"), &format!("mo{l}"))),
697                    // The router chooses experts per token: each row of the stack is routed on its own.
698                    Some(bsz) => {
699                        self.s.push_str(&format!("Let bmo{l} be a {bsz} by {d} tensor of Real.\n"));
700                        for b in 0..bsz {
701                            let r = b + 1;
702                            self.s.push_str(&format!("Let x2n{l}_s{b} be row {r} of bx2n{l}.\n"));
703                            self.s.push_str(&route(&format!("x2n{l}_s{b}"), &format!("mo{l}_s{b}")));
704                            self.s.push_str(&format!("Set row {r} of bmo{l} to mo{l}_s{b}.\n"));
705                        }
706                    }
707                }
708                // The shared experts, one SwiGLU FFN every token takes, add to the routed experts' sum.
709                let routed = match m.shared_experts {
710                    0 => format!("{p}mo{l}"),
711                    _ => {
712                        let sdff = m.shared_dff;
713                        self.decl_q8(&format!("Wsg{l}"), d, sdff);
714                        self.decl_q8(&format!("Wsu{l}"), d, sdff);
715                        self.decl_q8(&format!("Wsd{l}"), sdff, d);
716                        self.s.push_str(&format!(
717                            "Let {p}sg{l} be {p}x2n{l} matmul Wsg{l}.\n\
718                             Let {p}su{l} be {p}x2n{l} matmul Wsu{l}.\n\
719                             Let {p}sh{l} be swiglu of {p}sg{l} and {p}su{l}.\n\
720                             Let {p}sd{l} be {p}sh{l} matmul Wsd{l}.\n"
721                        ));
722                        // Qwen's shared expert is scaled by `σ(x·g)`: the gate a column over the input, its sigmoid spread
723                        // across the row by the host's row of ones (`s·1` is `s`), then multiplied in.
724                        let shared = if m.shared_gate {
725                            self.decl_f32(&format!("Wsgi{l}"), d, 1);
726                            let ones = self.host_table(HostTable::Ones(d), 1, d);
727                            self.s.push_str(&format!(
728                                "Let {p}sgi{l} be {p}x2n{l} matmul Wsgi{l}.\n\
729                                 Let {p}sgw{l} be sigmoid of {p}sgi{l}.\n\
730                                 Let {p}sgr{l} be {p}sgw{l} matmul {ones}.\n\
731                                 Let {p}sdg{l} be {p}sd{l} hadamard {p}sgr{l}.\n"
732                            ));
733                            format!("{p}sdg{l}")
734                        } else {
735                            format!("{p}sd{l}")
736                        };
737                        self.s.push_str(&format!("Let {p}me{l} be {p}mo{l} plus {shared}.\n"));
738                        format!("{p}me{l}")
739                    }
740                };
741                let mo = self.post_norm(l, &routed, false);
742                self.s.push_str(&format!("Let {p}xo{l} be {p}xr{l} plus {mo}.\n"));
743            }
744        }
745    }
746
747    /// The final norm and the LM head.
748    fn head(&mut self, cur: &str) {
749        let (d, vocab) = (self.spec.d, self.spec.vocab);
750        self.decl_f32("on", 1, d);
751        self.decl_q8("Wout", d, vocab);
752        self.s.push_str(&format!("Let xf be rmsnorm of {cur} with weight on.\n"));
753        self.s.push_str(&capped_logits("xf matmul Wout", "logits", self.spec.final_logit_softcap));
754    }
755
756    /// The decode step's first hidden state: row `tok` of the embedding table.
757    fn embed(&mut self) {
758        let (vocab, d) = (self.spec.vocab, self.spec.d);
759        self.decl_q8("Emb", vocab, d);
760        self.embedded("row tok of Emb", "x");
761    }
762
763    /// The token a greedy decode emits: the arg-max of the logits.
764    fn next_token(&mut self) {
765        self.s.push_str("Let next be argmax of logits.\n");
766    }
767
768    /// The rotary caches a decode step reads its angles from: `ctx` positions of `dims / 2` angles each — none for a
769    /// model no layer of which rotates.
770    fn rope_cache(&mut self, ctx: usize) {
771        self.rotary_tables(None, true, ctx);
772    }
773
774    /// The stack's first hidden states: row `toks[k]` of the embedding table as row `k + 1` of `X`.
775    fn batched_embed(&mut self, toks: &[usize]) {
776        let (vocab, d) = (self.spec.vocab, self.spec.d);
777        self.decl_q8("Emb", vocab, d);
778        self.s.push_str(&format!("Let toks be a 1 by {} tensor of Int.\n", toks.len()));
779        for (k, tok) in toks.iter().enumerate() {
780            self.s.push_str(&format!("Set item {} of toks to {tok}.\n", k + 1));
781        }
782        self.embedded("rows toks of Emb", "X");
783    }
784
785    /// The batch's head: the final norm and the LM head on the stack, then each sequence's logits and arg-max.
786    fn batched_head(&mut self, cur: &str, bsz: usize) {
787        let (d, vocab) = (self.spec.d, self.spec.vocab);
788        self.decl_f32("on", 1, d);
789        self.decl_q8("Wout", d, vocab);
790        self.s.push_str(&format!("Let bxf be rmsnorm of {cur} with weight on.\n"));
791        self.s.push_str(&capped_logits("bxf matmul Wout", "blogits", self.spec.final_logit_softcap));
792        for b in 0..bsz {
793            self.s.push_str(&format!(
794                "Let logits_s{b} be row {} of blogits.\nLet next_s{b} be argmax of logits_s{b}.\n",
795                b + 1
796            ));
797        }
798    }
799
800    /// The next token after a stack's last row: its row `rows` alone through the head and the arg-max.
801    fn last_row_head(&mut self, cur: &str, rows: usize) {
802        self.s.push_str(&format!("Let xl be row {rows} of {cur}.\n"));
803        self.head("xl");
804        self.next_token();
805    }
806
807    /// Layer `l` of a stacked step: the stacked hidden states `cur` (`B × d`) in, `bxo{l}` out — the single step's
808    /// layer with its weight reads on the stack and its per-sequence state per row.
809    fn stacked_layer(&mut self, l: usize, cur: &str, ctx: usize, bsz: usize, rows: RowState) {
810        let spec = self.spec;
811        self.decl_f32(&format!("an{l}"), 1, spec.d);
812        match &spec.layers[l].mixer {
813            Mixer::Attention(a) => self.stacked_attention(l, a, cur, ctx, bsz, rows),
814            Mixer::GatedDelta(g) => self.stacked_gated_delta(l, g, cur, bsz, rows),
815            Mixer::Mla(m) => self.stacked_mla(l, m, cur, ctx, bsz, rows),
816        }
817        self.ffn(l, cur, Some(bsz));
818    }
819
820    fn stacked_attention(&mut self, l: usize, a: &Attention, cur: &str, ctx: usize, bsz: usize, rows: RowState) {
821        let st = |base: String, b: usize| rows.state(&base, b);
822        let Dims { d, aq, akv, avd, ao, h, kv, .. } = attn_dims(self.spec, a);
823        self.decl_q8(&format!("Wq{l}"), d, aq);
824        if a.output_gate {
825            self.decl_q8(&format!("Wqg{l}"), d, aq);
826        }
827        self.decl_q8(&format!("Wk{l}"), d, akv);
828        self.decl_q8(&format!("Wv{l}"), d, avd);
829        let ((nq, nk), (wq, wk)) = qk_norm_segments(a);
830        if a.qk_norm {
831            self.decl_f32(&format!("Qn{l}"), 1, wq);
832            self.decl_f32(&format!("Kn{l}"), 1, wk);
833        }
834        self.decl_q8(&format!("Wo{l}"), ao, d);
835        for b in rows.holders(bsz) {
836            self.s.push_str(&format!(
837                "Let {} be a {ctx} by {akv} tensor of Real.\nLet {} be a {ctx} by {avd} tensor of Real.\n",
838                st(format!("Kc{l}"), b),
839                st(format!("Vc{l}"), b)
840            ));
841        }
842        let bias = |b: &str| a.bias.then(|| format!("{b}{l}"));
843        self.s.push_str(&format!("Let bxn{l} be rmsnorm of {cur} with weight an{l}.\n"));
844        self.project(&format!("bqr{l}"), &format!("bxn{l}"), &format!("Wq{l}"), bias("Bq"), aq);
845        if a.output_gate {
846            self.s.push_str(&format!("Let bgr{l} be bxn{l} matmul Wqg{l}.\n"));
847        }
848        self.project(&format!("bkr{l}"), &format!("bxn{l}"), &format!("Wk{l}"), bias("Bk"), akv);
849        self.project(&format!("bvr{l}"), &format!("bxn{l}"), &format!("Wv{l}"), bias("Bv"), avd);
850        match rows {
851            // ★ ONE SEQUENCE'S ROWS ARE ONE BLOCK, END TO END. The QK-norm runs over every row's heads at once, the rope
852            // turns row `i` by row `i` of the chunk's tables, the block's keys and values go into the cache in one write
853            // each from the chunk's first position, and the block attends once — row `i` up to `pos_s0 + i`, its own
854            // position, so no row sees a later one. No statement of the layer is per row.
855            RowState::Shared => {
856                let (kc, vc) = (st(format!("Kc{l}"), 0), st(format!("Vc{l}"), 0));
857                let (mut q, mut k) = (format!("bqr{l}"), format!("bkr{l}"));
858                if a.qk_norm {
859                    let (qh, kh) = (bsz * nq, bsz * nk);
860                    self.s.push_str(&format!(
861                        "Let bqm{l} be rmsnorm of bqr{l} with weight Qn{l} across {qh} heads.\n\
862                         Let bkm{l} be rmsnorm of bkr{l} with weight Kn{l} across {kh} heads.\n"
863                    ));
864                    (q, k) = (format!("bqm{l}"), format!("bkm{l}"));
865                }
866                if a.rope.is_some() {
867                    let angles = self.angles(l, AttnForm::Cached { ctx }, "pos_s0");
868                    self.s.push_str(&format!(
869                        "Let bqp{l} be rope of {q} with {angles} across {h} heads.\n\
870                         Let bkp{l} be rope of {k} with {angles} across {kv} heads.\n"
871                    ));
872                    (q, k) = (format!("bqp{l}"), format!("bkp{l}"));
873                }
874                (q, k) = self.llama4_qk(a, (q, k), (bsz * h, bsz * kv), h, Some(("pos_s0".to_string(), ctx)), &|base| format!("b{base}{l}"));
875                let (w, sk) = (score_clauses(a), self.sinks(l, a));
876                self.s.push_str(&format!(
877                    "Set rows from pos_s0 of {kc} to {k}.\n\
878                     Set rows from pos_s0 of {vc} to bvr{l}.\n\
879                     Let bct{l} be causal attention of {q} over {kc} and {vc} with {h} heads {kv} groups from pos_s0{w}{sk}.\n"
880                ));
881            }
882            // Rows of different sequences append to and attend their own caches, one row each.
883            RowState::PerSequence => {
884                self.s.push_str(&format!("Let bct{l} be a {bsz} by {ao} tensor of Real.\n"));
885                for b in 0..bsz {
886                    let r = b + 1;
887                    let (kc, vc) = (st(format!("Kc{l}"), b), st(format!("Vc{l}"), b));
888                    self.s.push_str(&format!(
889                        "Let qr{l}_s{b} be row {r} of bqr{l}.\n\
890                         Let kr{l}_s{b} be row {r} of bkr{l}.\n\
891                         Let vr{l}_s{b} be row {r} of bvr{l}.\n"
892                    ));
893                    let (mut q, mut k) = (format!("qr{l}_s{b}"), format!("kr{l}_s{b}"));
894                    if a.qk_norm {
895                        self.s.push_str(&format!(
896                            "Let qm{l}_s{b} be rmsnorm of qr{l}_s{b} with weight Qn{l} across {nq} heads.\n\
897                             Let km{l}_s{b} be rmsnorm of kr{l}_s{b} with weight Kn{l} across {nk} heads.\n"
898                        ));
899                        (q, k) = (format!("qm{l}_s{b}"), format!("km{l}_s{b}"));
900                    }
901                    if a.rope.is_some() {
902                        let angles = self.angles(l, AttnForm::Cached { ctx }, &format!("pos_s{b}"));
903                        self.s.push_str(&format!(
904                            "Let qp{l}_s{b} be rope of {q} with {angles} across {h} heads.\n\
905                             Let kp{l}_s{b} be rope of {k} with {angles} across {kv} heads.\n"
906                        ));
907                        (q, k) = (format!("qp{l}_s{b}"), format!("kp{l}_s{b}"));
908                    }
909                    (q, k) = self.llama4_qk(a, (q, k), (h, kv), h, Some((format!("pos_s{b}"), ctx)), &|base| format!("{base}{l}_s{b}"));
910                    let (w, sk) = (score_clauses(a), self.sinks(l, a));
911                    self.s.push_str(&format!(
912                        "Set row pos_s{b} of {kc} to {k}.\n\
913                         Set row pos_s{b} of {vc} to vr{l}_s{b}.\n\
914                         Let ct{l}_s{b} be attention of {q} over {kc} and {vc} with {h} heads {kv} groups up to pos_s{b}{w}{sk}.\n\
915                         Set row {r} of bct{l} to ct{l}_s{b}.\n"
916                    ));
917                }
918            }
919        }
920        let gated = if a.output_gate {
921            self.s.push_str(&format!("Let bgs{l} be sigmoid of bgr{l}.\nLet bcg{l} be bct{l} hadamard bgs{l}.\n"));
922            format!("bcg{l}")
923        } else {
924            format!("bct{l}")
925        };
926        self.project(&format!("bao{l}"), &gated, &format!("Wo{l}"), a.output_bias.then(|| format!("Bo{l}")), d);
927    }
928
929    fn stacked_gated_delta(&mut self, l: usize, g: &GatedDelta, cur: &str, bsz: usize, rows: RowState) {
930        let gate = gate_clause(g);
931        let st = |base: String, b: usize| rows.state(&base, b);
932        let d = self.spec.d;
933        let (qk, vw, taps) = (g.k_heads * g.head_dim, g.v_heads * g.head_dim, g.conv_taps);
934        let (nk, nv, ghd) = (g.k_heads, g.v_heads, g.head_dim);
935        self.decl_q8(&format!("Wq{l}"), d, qk);
936        self.decl_q8(&format!("Wk{l}"), d, qk);
937        self.decl_q8(&format!("Wv{l}"), d, vw);
938        self.decl_q8(&format!("Wz{l}"), d, vw);
939        self.decl_f32(&format!("Wcq{l}"), taps, qk);
940        self.decl_f32(&format!("Wck{l}"), taps, qk);
941        self.decl_f32(&format!("Wcv{l}"), taps, vw);
942        for b in rows.holders(bsz) {
943            self.decl_f32(&st(format!("Csq{l}"), b), taps, qk);
944            self.decl_f32(&st(format!("Csk{l}"), b), taps, qk);
945            self.decl_f32(&st(format!("Csv{l}"), b), taps, vw);
946            self.decl_f32(&st(format!("St{l}"), b), vw, ghd);
947        }
948        self.decl_q8(&format!("Wb{l}"), d, nv);
949        self.decl_q8(&format!("Wa{l}"), d, nv);
950        self.decl_f32(&format!("Dt{l}"), 1, nv);
951        self.decl_f32(&format!("Al{l}"), 1, nv);
952        self.decl_f32(&format!("Gn{l}"), 1, ghd);
953        self.decl_q8(&format!("Wo{l}"), vw, d);
954        self.s.push_str(&format!(
955            "Let bxn{l} be rmsnorm of {cur} with weight an{l}.\n\
956             Let bqr{l} be bxn{l} matmul Wq{l}.\n\
957             Let bkr{l} be bxn{l} matmul Wk{l}.\n\
958             Let bvr{l} be bxn{l} matmul Wv{l}.\n\
959             Let bzz{l} be bxn{l} matmul Wz{l}.\n\
960             Let bbr{l} be bxn{l} matmul Wb{l}.\n\
961             Let bar{l} be bxn{l} matmul Wa{l}.\n"
962        ));
963        match rows {
964            // ★ ONE SEQUENCE'S ROWS TAKE THE RECURRENCE AS A BLOCK. The rings take the block's rows in order, the gates and
965            // norms run over every row's heads at once, and the gated delta steps the one memory row after row — each
966            // sugar the rows fed in turn, so no statement of the layer is per row.
967            RowState::Shared => {
968                let bnk = bsz * nk;
969                let (csq, csk, csv, stt) = (
970                    st(format!("Csq{l}"), 0),
971                    st(format!("Csk{l}"), 0),
972                    st(format!("Csv{l}"), 0),
973                    st(format!("St{l}"), 0),
974                );
975                self.s.push_str(&format!(
976                    "Let bqc{l} be causal conv of bqr{l} with weight Wcq{l} state {csq} over {taps} taps.\n\
977                     Let bkc{l} be causal conv of bkr{l} with weight Wck{l} state {csk} over {taps} taps.\n\
978                     Let bvc{l} be causal conv of bvr{l} with weight Wcv{l} state {csv} over {taps} taps.\n\
979                     Let bqs{l} be silu of bqc{l}.\n\
980                     Let bks{l} be silu of bkc{l}.\n\
981                     Let bvs{l} be silu of bvc{l}.\n\
982                     Let bqn{l} be l2norm of bqs{l} across {bnk} heads.\n\
983                     Let bkn{l} be l2norm of bks{l} across {bnk} heads.\n\
984                     Let bbt{l} be sigmoid of bbr{l}.\n\
985                     Let bdy{l} be decay of bar{l} with bias Dt{l} rate Al{l}.\n\
986                     Let bod{l} be gated delta of bqn{l} over bkn{l} and bvs{l} with {gate} bzz{l} beta bbt{l} decay bdy{l} state {stt} norm Gn{l} with {nv} heads {nk} groups.\n\
987                     Let bao{l} be bod{l} matmul Wo{l}.\n"
988                ));
989            }
990            RowState::PerSequence => {
991                self.s.push_str(&format!("Let bod{l} be a {bsz} by {vw} tensor of Real.\n"));
992                for b in 0..bsz {
993                    let r = b + 1;
994                    let (csq, csk, csv, stt) = (
995                        st(format!("Csq{l}"), b),
996                        st(format!("Csk{l}"), b),
997                        st(format!("Csv{l}"), b),
998                        st(format!("St{l}"), b),
999                    );
1000                    self.s.push_str(&format!(
1001                        "Let qr{l}_s{b} be row {r} of bqr{l}.\n\
1002                         Let kr{l}_s{b} be row {r} of bkr{l}.\n\
1003                         Let vr{l}_s{b} be row {r} of bvr{l}.\n\
1004                         Let zz{l}_s{b} be row {r} of bzz{l}.\n\
1005                         Let br{l}_s{b} be row {r} of bbr{l}.\n\
1006                         Let ar{l}_s{b} be row {r} of bar{l}.\n\
1007                         Let qc{l}_s{b} be causal conv of qr{l}_s{b} with weight Wcq{l} state {csq} over {taps} taps.\n\
1008                         Let kc{l}_s{b} be causal conv of kr{l}_s{b} with weight Wck{l} state {csk} over {taps} taps.\n\
1009                         Let vc{l}_s{b} be causal conv of vr{l}_s{b} with weight Wcv{l} state {csv} over {taps} taps.\n\
1010                         Let qs{l}_s{b} be silu of qc{l}_s{b}.\n\
1011                         Let ks{l}_s{b} be silu of kc{l}_s{b}.\n\
1012                         Let vs{l}_s{b} be silu of vc{l}_s{b}.\n\
1013                         Let qn{l}_s{b} be l2norm of qs{l}_s{b} across {nk} heads.\n\
1014                         Let kn{l}_s{b} be l2norm of ks{l}_s{b} across {nk} heads.\n\
1015                         Let bt{l}_s{b} be sigmoid of br{l}_s{b}.\n\
1016                         Let dy{l}_s{b} be decay of ar{l}_s{b} with bias Dt{l} rate Al{l}.\n\
1017                         Let od{l}_s{b} be gated delta of qn{l}_s{b} over kn{l}_s{b} and vs{l}_s{b} with {gate} zz{l}_s{b} beta bt{l}_s{b} decay dy{l}_s{b} state {stt} norm Gn{l} with {nv} heads {nk} groups.\n\
1018                         Set row {r} of bod{l} to od{l}_s{b}.\n"
1019                    ));
1020                }
1021                self.s.push_str(&format!("Let bao{l} be bod{l} matmul Wo{l}.\n"));
1022            }
1023        }
1024    }
1025}
1026
1027/// An attention's clauses before its sinks: ` within a window of W` (or ` within chunks of C`) for an attention over
1028/// part of its history, ` scaled by S` for a score scale other than the sugar's `1/√hd`, and ` capped at C` for scores
1029/// soft-capped before their softmax.
1030fn score_clauses(a: &Attention) -> String {
1031    let mut clauses = a.window.map_or_else(String::new, |w| w.clause());
1032    if (a.scale - 1.0 / (a.head_dim as f64).sqrt()).abs() > 1e-15 {
1033        clauses.push_str(&format!(" scaled by {:?}", a.scale));
1034    }
1035    if let Some(cap) = a.softcap {
1036        clauses.push_str(&format!(" capped at {cap:?}"));
1037    }
1038    clauses
1039}
1040
1041/// `Let logits be <product>.`, or for logits the model soft-caps the product first and `Let logits be <raw> capped at
1042/// C.` after it, the raw product bound as `<logits>_raw`.
1043fn capped_logits(product: &str, logits: &str, cap: Option<f64>) -> String {
1044    match cap {
1045        Some(cap) => format!("Let {logits}_raw be {product}.\nLet {logits} be {logits}_raw capped at {cap:?}.\n"),
1046        None => format!("Let {logits} be {product}.\n"),
1047    }
1048}
1049
1050/// An attention's QK norm as the sugar takes it: the query's and the key's segments a row and each segment's width — a
1051/// head each, or (MiniMax-M2) the whole projection as one.
1052fn qk_norm_segments(a: &Attention) -> ((usize, usize), (usize, usize)) {
1053    if a.qk_norm_whole {
1054        ((1, 1), (a.heads * a.head_dim, a.kv_heads * a.head_dim))
1055    } else {
1056        ((a.heads, a.kv_heads), (a.head_dim, a.head_dim))
1057    }
1058}
1059
1060/// The hidden-state tensor layer `l` reads: `x` for the first layer, the previous layer's output after.
1061pub fn layer_input(l: usize) -> String {
1062    if l == 0 {
1063        "x".to_string()
1064    } else {
1065        format!("xo{}", l - 1)
1066    }
1067}
1068
1069/// The stacked hidden states layer `l` of a stacked step reads: `X` for the first layer, the previous `bxo` after.
1070pub fn stacked_layer_input(l: usize) -> String {
1071    if l == 0 {
1072        "X".to_string()
1073    } else {
1074        format!("bxo{}", l - 1)
1075    }
1076}
1077
1078/// The single-token forward with no history: the token's hidden state `x` in, the logits out.
1079pub fn forward(spec: &ModelSpec, dir: &str) -> Authored {
1080    let mut p = Program::new(spec, dir);
1081    p.s.push_str(&format!("Let x be a 1 by {} tensor of Real.\n", spec.d));
1082    p.rotary_tables(None, false, 1);
1083    let mut cur = "x".to_string();
1084    for l in 0..spec.layers.len() {
1085        p.layer(l, &cur, AttnForm::Current);
1086        cur = format!("xo{l}");
1087    }
1088    p.head(&cur);
1089    p.finish()
1090}
1091
1092/// ONE DECODE STEP: token `tok` at position `pos` (1-based) in, the next token out. Every attention layer appends
1093/// this token's key and value to its KV cache (`ctx` positions, the step's carried state alongside any recurrent
1094/// memories and conv rings) and attends over the first `pos` rows; the step ends with the arg-max of the logits.
1095pub fn decode_step(spec: &ModelSpec, dir: &str, ctx: usize, tok: usize, pos: usize) -> Authored {
1096    let mut p = Program::new(spec, dir);
1097    p.s.push_str(&format!("Let tok be {tok}.\nLet pos be {pos}.\n"));
1098    p.embed();
1099    p.rope_cache(ctx);
1100    let mut cur = "x".to_string();
1101    for l in 0..spec.layers.len() {
1102        p.layer(l, &cur, AttnForm::Cached { ctx });
1103        cur = format!("xo{l}");
1104    }
1105    p.head(&cur);
1106    p.next_token();
1107    p.finish()
1108}
1109
1110/// A PREFILL CHUNK: the tokens `toks` of ONE sequence at positions `pos0, pos0 + 1, …` (1-based) as one step, the
1111/// next token after the last of them out. The hidden states are stacked into a `T × d` matrix, so every projection,
1112/// norm, FFN and residual reads its weights once for the chunk; the chunk's keys and values append to the cache as
1113/// one block from `pos0`, and the rows attend as one causal block. The state is the decode step's own, so a decode
1114/// step continues where the chunk stops; the LM head reads the last row only.
1115pub fn prefill(spec: &ModelSpec, dir: &str, ctx: usize, toks: &[usize], pos0: usize) -> Authored {
1116    let t = toks.len();
1117    assert!(
1118        t > 0 && pos0 >= 1 && pos0 + t - 1 <= ctx,
1119        "a chunk of {t} tokens from position {pos0} fits a context of {ctx}"
1120    );
1121    let mut p = Program::new(spec, dir);
1122    p.s.push_str(&format!("Let pos_s0 be {pos0}.\n"));
1123    p.batched_embed(toks);
1124    p.rope_cache(ctx);
1125    let mut cur = stacked_layer_input(0);
1126    for l in 0..spec.layers.len() {
1127        p.stacked_layer(l, &cur, ctx, t, RowState::Shared);
1128        cur = stacked_layer_input(l + 1);
1129    }
1130    p.last_row_head(&cur, t);
1131    p.finish()
1132}
1133
1134/// B DECODE STEPS AT ONCE: sequence `b` brings token `tok_b` at position `pos_b` (1-based) and its own carried
1135/// state, and every sequence emits its own next token. The hidden states are stacked into a `B × d` matrix and
1136/// everything that reads a weight runs on the stack; what depends on one sequence's position or state runs per
1137/// sequence, on that sequence's row, exactly as the single step writes it.
1138pub fn decode_batch(spec: &ModelSpec, dir: &str, ctx: usize, seqs: &[(usize, usize)]) -> Authored {
1139    let bsz = seqs.len();
1140    let mut p = Program::new(spec, dir);
1141    for (b, (_, pos)) in seqs.iter().enumerate() {
1142        p.s.push_str(&format!("Let pos_s{b} be {pos}.\n"));
1143    }
1144    p.batched_embed(&seqs.iter().map(|(tok, _)| *tok).collect::<Vec<_>>());
1145    p.rope_cache(ctx);
1146    let mut cur = stacked_layer_input(0);
1147    for l in 0..spec.layers.len() {
1148        p.stacked_layer(l, &cur, ctx, bsz, RowState::PerSequence);
1149        cur = stacked_layer_input(l + 1);
1150    }
1151    p.batched_head(&cur, bsz);
1152    p.finish()
1153}
1154
1155/// Layer `l` alone, as the forward writes it: its incoming hidden state declared as an input, the RoPE tables when
1156/// it is an attention layer, then the layer.
1157pub fn layer(spec: &ModelSpec, l: usize, dir: &str) -> Authored {
1158    let mut p = Program::new(spec, dir);
1159    let input = layer_input(l);
1160    p.s.push_str(&format!("Let {input} be a 1 by {} tensor of Real.\n", spec.d));
1161    p.rotary_tables(Some(l), false, 1);
1162    p.layer(l, &input, AttnForm::Current);
1163    p.finish()
1164}
1165
1166/// Layer `l` of a decode step alone, its attention reading a KV cache of `ctx` positions up to `pos`.
1167pub fn decode_layer(spec: &ModelSpec, l: usize, dir: &str, ctx: usize, pos: usize) -> Authored {
1168    let mut p = Program::new(spec, dir);
1169    let input = layer_input(l);
1170    p.s.push_str(&format!("Let pos be {pos}.\n"));
1171    p.s.push_str(&format!("Let {input} be a 1 by {} tensor of Real.\n", spec.d));
1172    p.rotary_tables(Some(l), true, ctx);
1173    p.layer(l, &input, AttnForm::Cached { ctx });
1174    p.finish()
1175}
1176
1177/// The final norm and LM head alone, reading the last layer's output.
1178pub fn head(spec: &ModelSpec, dir: &str) -> Authored {
1179    let mut p = Program::new(spec, dir);
1180    let input = layer_input(spec.layers.len());
1181    p.s.push_str(&format!("Let {input} be a 1 by {} tensor of Real.\n", spec.d));
1182    p.head(&input);
1183    p.finish()
1184}
1185
1186/// A decode step's embedding lookup alone: token `tok` in, the first hidden state `x` out.
1187pub fn decode_embed(spec: &ModelSpec, dir: &str, tok: usize) -> Authored {
1188    let mut p = Program::new(spec, dir);
1189    p.s.push_str(&format!("Let tok be {tok}.\n"));
1190    p.embed();
1191    p.finish()
1192}
1193
1194/// A decode step's head alone: the final norm, the LM head and the arg-max.
1195pub fn decode_head(spec: &ModelSpec, dir: &str) -> Authored {
1196    let mut p = Program::new(spec, dir);
1197    let input = layer_input(spec.layers.len());
1198    p.s.push_str(&format!("Let {input} be a 1 by {} tensor of Real.\n", spec.d));
1199    p.head(&input);
1200    p.next_token();
1201    p.finish()
1202}
1203
1204/// A batched decode step's embedding lookups alone: the stacked `X` out.
1205pub fn decode_batch_embed(spec: &ModelSpec, dir: &str, toks: &[usize]) -> Authored {
1206    let mut p = Program::new(spec, dir);
1207    p.batched_embed(toks);
1208    p.finish()
1209}
1210
1211/// Layer `l` of a stacked step alone, its rows' state held as `rows` says: the positions the rows read, the stacked
1212/// input, the RoPE tables when it is an attention layer, then the layer.
1213pub fn stacked_layer(spec: &ModelSpec, l: usize, dir: &str, ctx: usize, poss: &[usize], rows: RowState) -> Authored {
1214    let bsz = poss.len();
1215    let mut p = Program::new(spec, dir);
1216    // A chunk's rows sit at consecutive positions and read only the first; a batch's sequences each read their own.
1217    let read = if rows == RowState::Shared { &poss[..1] } else { poss };
1218    for (b, pos) in read.iter().enumerate() {
1219        p.s.push_str(&format!("Let pos_s{b} be {pos}.\n"));
1220    }
1221    let input = stacked_layer_input(l);
1222    p.s.push_str(&format!("Let {input} be a {bsz} by {} tensor of Real.\n", spec.d));
1223    p.rotary_tables(Some(l), true, ctx);
1224    p.stacked_layer(l, &input, ctx, bsz, rows);
1225    p.finish()
1226}
1227
1228/// A prefill chunk's head alone: the last layer's stacked output in, the next token after the chunk's last out.
1229pub fn prefill_head(spec: &ModelSpec, dir: &str, chunk: usize) -> Authored {
1230    let mut p = Program::new(spec, dir);
1231    let input = stacked_layer_input(spec.layers.len());
1232    p.s.push_str(&format!("Let {input} be a {chunk} by {} tensor of Real.\n", spec.d));
1233    p.last_row_head(&input, chunk);
1234    p.finish()
1235}
1236
1237/// A batched decode step's head alone: the last layer's stacked output in, every sequence's next token out.
1238pub fn decode_batch_head(spec: &ModelSpec, dir: &str, bsz: usize) -> Authored {
1239    let mut p = Program::new(spec, dir);
1240    let input = stacked_layer_input(spec.layers.len());
1241    p.s.push_str(&format!("Let {input} be a {bsz} by {} tensor of Real.\n", spec.d));
1242    p.batched_head(&input, bsz);
1243    p.finish()
1244}
1245
1246// ── Tensor parallelism ─────────────────────────────────────────────────────────────────────────────────────────────
1247//
1248// A program spread over `tp` chips, Megatron's split: the norms and the residual spine replicated; each chip's
1249// column-parallel projections onto its own heads (its own FFN columns), every per-head operation, its slices of the KV
1250// caches and recurrent state, then its row-parallel output projection — a PARTIAL of the full row; the partials
1251// summed (the all-reduce, written as the left fold of `plus` it means). The manifest records which chip holds each
1252// chip-local tensor, which full tensor each slice is cut from, and each collective.
1253//
1254// Any width splits a model: a chip holds ⌊n/tp⌋ or ⌈n/tp⌉ of each head count and of the FFN's columns ([`share`]),
1255// and a chip with no share of a layer — fewer heads than chips — folds the empty sum, a zero partial, so every
1256// all-reduce still draws a partial from every chip.
1257
1258use crate::spatial::tensor_parallel::{SliceAxis, TpCollective, TpManifest, TpSlice};
1259
1260/// A tensor-parallel program, its weight manifest, and its placement.
1261pub type TpAuthored = (
1262    String,
1263    HashMap<String, (String, usize)>,
1264    HashMap<String, String>,
1265    TpManifest,
1266);
1267
1268/// Can `spec` be split over `tp` chips? At any width of at least one chip (`share`), when every attention is
1269/// unbiased and sinkless and every FFN is dense (its columns split; an expert mixture would split by experts).
1270pub fn check_tp(spec: &ModelSpec, tp: usize) -> Result<(), NotYet> {
1271    check(spec)?;
1272    if tp == 0 {
1273        return Err(NotYet("a tensor-parallel width of zero chips"));
1274    }
1275    for layer in &spec.layers {
1276        match &layer.mixer {
1277            Mixer::Attention(a) if a.bias || a.output_bias || a.sinks => {
1278                return Err(NotYet("a tensor-parallel attention with biases or sinks"))
1279            }
1280            // A norm across every head would sum each chip's heads before it scales any of them.
1281            Mixer::Attention(a) if a.qk_norm_whole => return Err(NotYet("a tensor-parallel QK norm across every head")),
1282            Mixer::Mla(_) => return Err(NotYet("a tensor-parallel latent attention")),
1283            _ => {}
1284        }
1285        if let Ffn::Moe(_) = &layer.ffn {
1286            return Err(NotYet("a tensor-parallel expert mixture"));
1287        }
1288    }
1289    Ok(())
1290}
1291
1292/// The `c`-th of `tp` balanced runs of `n` units, `(first, count)`: `[⌊c·n/tp⌋, ⌊(c+1)·n/tp⌋)` — every unit in exactly
1293/// one run, each ⌊n/tp⌋ or ⌈n/tp⌉ long.
1294fn run_of(n: usize, tp: usize, c: usize) -> (usize, usize) {
1295    let (lo, hi) = (c * n / tp, (c + 1) * n / tp);
1296    (lo, hi - lo)
1297}
1298
1299/// Chip `c`'s share of `units` units of `parts` parts each over `tp` chips: `(first unit, units held)` and, within
1300/// each unit held, `(first part, parts held)`.
1301///
1302/// ★ A UNIT'S PARTS STAY WITH IT. With no more chips than units, chip `c` holds a balanced run of the units, every part
1303/// of each. With more, unit `u` is held by a balanced run of the chips — chip `c` by unit `⌊c·units/tp⌋` — each holding
1304/// it whole and a balanced run of its parts; a chip whose unit has fewer parts than chips holding it may hold none, and
1305/// then holds no unit. Over the chips every part of every unit is held exactly once. When `tp` divides `units` (or
1306/// `units` divides `tp` and `tp/units` divides `parts`), chip `c`'s parts are `[c·n/tp, (c+1)·n/tp)` of the `n` in
1307/// unit order — Megatron's split.
1308fn share(units: usize, parts: usize, tp: usize, c: usize) -> ((usize, usize), (usize, usize)) {
1309    if tp <= units {
1310        return (run_of(units, tp, c), (0, parts));
1311    }
1312    let u = c * units / tp;
1313    let first = (u * tp).div_ceil(units);
1314    let holders = ((u + 1) * tp).div_ceil(units) - first;
1315    let (p0, pn) = run_of(parts, holders, c - first);
1316    ((u, usize::from(pn > 0)), (p0, pn))
1317}
1318
1319/// Chip `c`'s attention heads of `tp`: its query heads and the KV heads they read, each `(first, count)`.
1320///
1321/// ★ WHERE THE KV HEADS GO. Query head `q` reads KV head `⌊q / g⌋`, `g = h/kv`: the KV heads are the units of a
1322/// [`share`] and their `g` query heads its parts. A chip holds whole groups, or — past one chip a KV head — one KV
1323/// head REPLICATED on the chips sharing its group (vLLM's rule when `tp/kv` divides `g`), each computing and caching
1324/// the same key and value. Either way a chip's query heads read its KV heads `count_q / count_kv` apiece: one grouped
1325/// attention.
1326fn attn_heads_of_chip(a: &Attention, tp: usize, c: usize) -> ((usize, usize), (usize, usize)) {
1327    let g = a.heads / a.kv_heads;
1328    let ((k0, kn), (p0, pn)) = share(a.kv_heads, g, tp, c);
1329    ((k0 * g + p0, kn * pn), (k0, kn))
1330}
1331
1332/// Chip `c`'s Gated-DeltaNet heads of `tp`: its key-head column run (per head of `head_dim`) and its value heads as
1333/// `(first head, count)` blocks.
1334///
1335/// ★ THE KEYS ARE TILED. Value head `h` reads key head `h mod HK`, so the value heads reading key heads `[k0, k0+kn)`
1336/// are one block per recurrence `r < HV/HK`, `r·HK + [k0, k0+kn)`: the key heads are the units of a [`share`] and the
1337/// recurrences its parts. In recurrence order the blocks keep the tiling on the chip; a key head shared by several
1338/// chips is computed alike on each, and its recurrences split among them.
1339/// A gated delta's gate clause in the sugar: `gate` for SiLU, `sigmoid gate` for the sigmoid (Qwen3.8-Flash-Next).
1340fn gate_clause(g: &GatedDelta) -> &'static str {
1341    match g.gate {
1342        GateActivation::Silu => "gate",
1343        GateActivation::Sigmoid => "sigmoid gate",
1344    }
1345}
1346
1347fn gdn_heads_of_chip(g: &GatedDelta, tp: usize, c: usize) -> (Vec<(usize, usize)>, Vec<(usize, usize)>) {
1348    let (nk, ghd) = (g.k_heads, g.head_dim);
1349    let ((k0, kn), (r0, rn)) = share(nk, g.v_heads / nk, tp, c);
1350    (vec![(k0 * ghd, kn * ghd)], (r0..r0 + rn).map(|r| (r * nk + k0, kn)).collect())
1351}
1352
1353/// The heads in `(first, count)` blocks.
1354fn heads_in(blocks: &[(usize, usize)]) -> usize {
1355    blocks.iter().map(|(_, n)| n).sum()
1356}
1357
1358/// The per-head ranges scaled to columns of `width` each.
1359fn head_cols(heads: &[(usize, usize)], width: usize) -> Vec<(usize, usize)> {
1360    heads.iter().map(|(h, n)| (h * width, n * width)).collect()
1361}
1362
1363impl Program<'_> {
1364    /// Chip `c`'s slice of a full tensor `of` (`of_shape` whole): declared under its own name, recorded in the manifest.
1365    #[allow(clippy::too_many_arguments)]
1366    fn decl_slice(
1367        &mut self,
1368        m: &mut TpManifest,
1369        var: &str,
1370        c: usize,
1371        of: &str,
1372        of_shape: (usize, usize),
1373        axis: SliceAxis,
1374        ranges: Vec<(usize, usize)>,
1375    ) {
1376        let slice = TpSlice {
1377            of: of.to_string(),
1378            of_shape,
1379            axis,
1380            ranges,
1381        };
1382        let (r, cols) = slice.shape();
1383        self.s.push_str(&format!("Let {var} be a {r} by {cols} tensor of Real.\n"));
1384        m.place(var, c, Some(slice));
1385    }
1386
1387    /// [`Program::decl_slice`] of a weight the checkpoint stores Q8_0: the full tensor is recorded as `decl_q8` records it.
1388    #[allow(clippy::too_many_arguments)]
1389    fn decl_q8_slice(
1390        &mut self,
1391        m: &mut TpManifest,
1392        var: &str,
1393        c: usize,
1394        of: &str,
1395        of_shape: (usize, usize),
1396        axis: SliceAxis,
1397        ranges: Vec<(usize, usize)>,
1398    ) {
1399        self.q8w.insert(of.to_string(), format!("{}/{of}", self.dir));
1400        self.decl_slice(m, var, c, of, of_shape, axis, ranges);
1401    }
1402
1403    /// `out = Σ partials` as the left fold of `plus` it means — `out_f1 = p0 + p1`, `out_f2 = out_f1 + p2`, …, the
1404    /// last binding `out` — recorded as a collective.
1405    fn fold(&mut self, m: &mut TpManifest, out: &str, partials: Vec<String>) {
1406        let mut folds = Vec::new();
1407        let mut acc = partials[0].clone();
1408        for (i, p) in partials.iter().enumerate().skip(1) {
1409            let binder = if i + 1 == partials.len() {
1410                out.to_string()
1411            } else {
1412                format!("{out}_f{i}")
1413            };
1414            self.s.push_str(&format!("Let {binder} be {acc} plus {p}.\n"));
1415            folds.push(binder.clone());
1416            acc = binder;
1417        }
1418        m.collectives.push(TpCollective {
1419            out: out.to_string(),
1420            partials,
1421            folds,
1422        });
1423    }
1424
1425    /// Chip `c`'s partial `out` of a layer it holds no share of — the empty sum: the replicated input `like` scaled by
1426    /// zero, a zero for each of its entries.
1427    fn zero_partial(&mut self, m: &mut TpManifest, out: &str, like: &str, c: usize) -> String {
1428        self.s.push_str(&format!("Let {out} be {like} scaled by 0.0.\n"));
1429        m.place(out, c, None);
1430        out.to_string()
1431    }
1432
1433    /// Chip `c`'s slices of an attention layer's weights: its query (and gate) columns, its KV heads' key and value
1434    /// columns, its query heads' rows of the output projection.
1435    fn decl_attn_weight_slices(&mut self, m: &mut TpManifest, a: &Attention, l: usize, c: usize, tp: usize) {
1436        let Dims { d, aq, akv, avd, ao, hd, .. } = attn_dims(self.spec, a);
1437        let vd = a.value_dim;
1438        let ((q0, hq), (kv0, hkv)) = attn_heads_of_chip(a, tp, c);
1439        let (q, k) = (vec![(q0 * hd, hq * hd)], vec![(kv0 * hd, hkv * hd)]);
1440        let (o, v) = (vec![(q0 * vd, hq * vd)], vec![(kv0 * vd, hkv * vd)]);
1441        self.decl_q8_slice(m, &format!("Wq{l}_c{c}"), c, &format!("Wq{l}"), (d, aq), SliceAxis::Cols, q.clone());
1442        if a.output_gate {
1443            self.decl_q8_slice(m, &format!("Wqg{l}_c{c}"), c, &format!("Wqg{l}"), (d, aq), SliceAxis::Cols, q.clone());
1444        }
1445        self.decl_q8_slice(m, &format!("Wk{l}_c{c}"), c, &format!("Wk{l}"), (d, akv), SliceAxis::Cols, k.clone());
1446        self.decl_q8_slice(m, &format!("Wv{l}_c{c}"), c, &format!("Wv{l}"), (d, avd), SliceAxis::Cols, v);
1447        self.decl_q8_slice(m, &format!("Wo{l}_c{c}"), c, &format!("Wo{l}"), (ao, d), SliceAxis::Rows, o);
1448    }
1449
1450    /// Chip `c`'s slice of an attention layer's KV caches `Kc{l}{sfx}` / `Vc{l}{sfx}`: its KV heads' columns.
1451    #[allow(clippy::too_many_arguments)]
1452    fn decl_attn_cache_slices(
1453        &mut self,
1454        m: &mut TpManifest,
1455        a: &Attention,
1456        l: usize,
1457        c: usize,
1458        tp: usize,
1459        ctx: usize,
1460        sfx: &str,
1461    ) {
1462        let Dims { akv, avd, hd, .. } = attn_dims(self.spec, a);
1463        let (_, (kv0, hkv)) = attn_heads_of_chip(a, tp, c);
1464        let (k, v) = (vec![(kv0 * hd, hkv * hd)], vec![(kv0 * a.value_dim, hkv * a.value_dim)]);
1465        self.decl_slice(m, &format!("Kc{l}{sfx}_c{c}"), c, &format!("Kc{l}{sfx}"), (ctx, akv), SliceAxis::Cols, k);
1466        self.decl_slice(m, &format!("Vc{l}{sfx}_c{c}"), c, &format!("Vc{l}{sfx}"), (ctx, avd), SliceAxis::Cols, v);
1467    }
1468
1469    /// Chip `c`'s slices of a Gated-DeltaNet layer's weights: its key heads' q/k projection and conv columns, its
1470    /// value heads' v/z projection and conv columns, gate columns, decay parameters and output-projection rows.
1471    fn decl_gdn_weight_slices(&mut self, m: &mut TpManifest, g: &GatedDelta, l: usize, c: usize, tp: usize) {
1472        let d = self.spec.d;
1473        let (taps, ghd, nv) = (g.conv_taps, g.head_dim, g.v_heads);
1474        let (qk, vw) = (g.k_heads * ghd, nv * ghd);
1475        let (k, heads) = gdn_heads_of_chip(g, tp, c);
1476        let v = head_cols(&heads, ghd);
1477        let n = |base: &str| format!("{base}{l}_c{c}");
1478        let f = |base: &str| format!("{base}{l}");
1479        self.decl_q8_slice(m, &n("Wq"), c, &f("Wq"), (d, qk), SliceAxis::Cols, k.clone());
1480        self.decl_q8_slice(m, &n("Wk"), c, &f("Wk"), (d, qk), SliceAxis::Cols, k.clone());
1481        self.decl_q8_slice(m, &n("Wv"), c, &f("Wv"), (d, vw), SliceAxis::Cols, v.clone());
1482        self.decl_q8_slice(m, &n("Wz"), c, &f("Wz"), (d, vw), SliceAxis::Cols, v.clone());
1483        self.decl_slice(m, &n("Wcq"), c, &f("Wcq"), (taps, qk), SliceAxis::Cols, k.clone());
1484        self.decl_slice(m, &n("Wck"), c, &f("Wck"), (taps, qk), SliceAxis::Cols, k);
1485        self.decl_slice(m, &n("Wcv"), c, &f("Wcv"), (taps, vw), SliceAxis::Cols, v.clone());
1486        self.decl_q8_slice(m, &n("Wb"), c, &f("Wb"), (d, nv), SliceAxis::Cols, heads.clone());
1487        self.decl_q8_slice(m, &n("Wa"), c, &f("Wa"), (d, nv), SliceAxis::Cols, heads.clone());
1488        self.decl_slice(m, &n("Dt"), c, &f("Dt"), (1, nv), SliceAxis::Cols, heads.clone());
1489        self.decl_slice(m, &n("Al"), c, &f("Al"), (1, nv), SliceAxis::Cols, heads);
1490        self.decl_q8_slice(m, &n("Wo"), c, &f("Wo"), (vw, d), SliceAxis::Rows, v);
1491    }
1492
1493    /// Chip `c`'s slice of a Gated-DeltaNet layer's carried state `…{l}{sfx}`: the conv rings' columns and the
1494    /// memory's rows of its heads.
1495    #[allow(clippy::too_many_arguments)]
1496    fn decl_gdn_state_slices(&mut self, m: &mut TpManifest, g: &GatedDelta, l: usize, c: usize, tp: usize, sfx: &str) {
1497        let (taps, ghd) = (g.conv_taps, g.head_dim);
1498        let (qk, vw) = (g.k_heads * ghd, g.v_heads * ghd);
1499        let (k, heads) = gdn_heads_of_chip(g, tp, c);
1500        let v = head_cols(&heads, ghd);
1501        self.decl_slice(m, &format!("Csq{l}{sfx}_c{c}"), c, &format!("Csq{l}{sfx}"), (taps, qk), SliceAxis::Cols, k.clone());
1502        self.decl_slice(m, &format!("Csk{l}{sfx}_c{c}"), c, &format!("Csk{l}{sfx}"), (taps, qk), SliceAxis::Cols, k);
1503        self.decl_slice(m, &format!("Csv{l}{sfx}_c{c}"), c, &format!("Csv{l}{sfx}"), (taps, vw), SliceAxis::Cols, v.clone());
1504        self.decl_slice(m, &format!("St{l}{sfx}_c{c}"), c, &format!("St{l}{sfx}"), (vw, ghd), SliceAxis::Rows, v);
1505    }
1506
1507    /// Chip `c`'s slices of a layer's dense FFN: its gate and up columns and its down-projection rows.
1508    fn decl_ffn_slices(&mut self, m: &mut TpManifest, l: usize, dff: usize, c: usize, tp: usize) {
1509        let d = self.spec.d;
1510        let f = vec![run_of(dff, tp, c)];
1511        self.decl_q8_slice(m, &format!("Wg{l}_c{c}"), c, &format!("Wg{l}"), (d, dff), SliceAxis::Cols, f.clone());
1512        self.decl_q8_slice(m, &format!("Wu{l}_c{c}"), c, &format!("Wu{l}"), (d, dff), SliceAxis::Cols, f.clone());
1513        self.decl_q8_slice(m, &format!("Wd{l}_c{c}"), c, &format!("Wd{l}"), (dff, d), SliceAxis::Rows, f);
1514    }
1515
1516    /// Layer `l` of a decode step over `tp` chips.
1517    fn tp_layer(&mut self, m: &mut TpManifest, l: usize, cur: &str, tp: usize, ctx: usize) {
1518        let spec = self.spec;
1519        let d = spec.d;
1520        self.decl_f32(&format!("an{l}"), 1, d);
1521        self.s.push_str(&format!("Let xn{l} be rmsnorm of {cur} with weight an{l}.\n"));
1522        let mut ao = Vec::new();
1523        match &spec.layers[l].mixer {
1524            Mixer::Attention(a) => {
1525                if a.qk_norm {
1526                    self.decl_f32(&format!("Qn{l}"), 1, a.head_dim);
1527                    self.decl_f32(&format!("Kn{l}"), 1, a.head_dim);
1528                }
1529                for c in 0..tp {
1530                    let ((_, hq), (_, hkv)) = attn_heads_of_chip(a, tp, c);
1531                    if hq == 0 {
1532                        ao.push(self.zero_partial(m, &format!("ao{l}_c{c}"), &format!("xn{l}"), c));
1533                        continue;
1534                    }
1535                    self.decl_attn_weight_slices(m, a, l, c, tp);
1536                    self.decl_attn_cache_slices(m, a, l, c, tp, ctx, "");
1537                    let mut bases = vec!["qr", "kr", "vr", "ct", "ao"];
1538                    if a.output_gate {
1539                        bases.extend(["gr", "gs", "cg"]);
1540                    }
1541                    if a.qk_norm {
1542                        bases.extend(["qm", "km"]);
1543                    }
1544                    if a.rope.is_some() {
1545                        bases.extend(["qp", "kp"]);
1546                    }
1547                    if a.qk_unit_norm {
1548                        bases.extend(["qu", "ku"]);
1549                    }
1550                    if a.temperature.is_some() {
1551                        bases.push("qt");
1552                    }
1553                    for base in bases {
1554                        m.place(&format!("{base}{l}_c{c}"), c, None);
1555                    }
1556                    self.s.push_str(&format!("Let qr{l}_c{c} be xn{l} matmul Wq{l}_c{c}.\n"));
1557                    if a.output_gate {
1558                        self.s.push_str(&format!("Let gr{l}_c{c} be xn{l} matmul Wqg{l}_c{c}.\n"));
1559                    }
1560                    self.s.push_str(&format!(
1561                        "Let kr{l}_c{c} be xn{l} matmul Wk{l}_c{c}.\nLet vr{l}_c{c} be xn{l} matmul Wv{l}_c{c}.\n"
1562                    ));
1563                    let (mut q, mut k) = (format!("qr{l}_c{c}"), format!("kr{l}_c{c}"));
1564                    if a.qk_norm {
1565                        self.s.push_str(&format!(
1566                            "Let qm{l}_c{c} be rmsnorm of qr{l}_c{c} with weight Qn{l} across {hq} heads.\n\
1567                             Let km{l}_c{c} be rmsnorm of kr{l}_c{c} with weight Kn{l} across {hkv} heads.\n"
1568                        ));
1569                        (q, k) = (format!("qm{l}_c{c}"), format!("km{l}_c{c}"));
1570                    }
1571                    if a.rope.is_some() {
1572                        let angles = self.angles(l, AttnForm::Cached { ctx }, "pos");
1573                        self.s.push_str(&format!(
1574                            "Let qp{l}_c{c} be rope of {q} with {angles} across {hq} heads.\n\
1575                             Let kp{l}_c{c} be rope of {k} with {angles} across {hkv} heads.\n"
1576                        ));
1577                        (q, k) = (format!("qp{l}_c{c}"), format!("kp{l}_c{c}"));
1578                    }
1579                    (q, k) = self.llama4_qk(a, (q, k), (hq, hkv), hq, Some(("pos".to_string(), ctx)), &|base| format!("{base}{l}_c{c}"));
1580                    let w = score_clauses(a);
1581                    self.s.push_str(&format!(
1582                        "Set row pos of Kc{l}_c{c} to {k}.\n\
1583                         Set row pos of Vc{l}_c{c} to vr{l}_c{c}.\n\
1584                         Let ct{l}_c{c} be attention of {q} over Kc{l}_c{c} and Vc{l}_c{c} with {hq} heads {hkv} groups up to pos{w}.\n"
1585                    ));
1586                    if a.output_gate {
1587                        self.s.push_str(&format!(
1588                            "Let gs{l}_c{c} be sigmoid of gr{l}_c{c}.\n\
1589                             Let cg{l}_c{c} be ct{l}_c{c} hadamard gs{l}_c{c}.\n\
1590                             Let ao{l}_c{c} be cg{l}_c{c} matmul Wo{l}_c{c}.\n"
1591                        ));
1592                    } else {
1593                        self.s.push_str(&format!("Let ao{l}_c{c} be ct{l}_c{c} matmul Wo{l}_c{c}.\n"));
1594                    }
1595                    ao.push(format!("ao{l}_c{c}"));
1596                }
1597            }
1598            Mixer::GatedDelta(g) => {
1599                let gate = gate_clause(g);
1600                let (taps, ghd) = (g.conv_taps, g.head_dim);
1601                self.decl_f32(&format!("Gn{l}"), 1, ghd);
1602                for c in 0..tp {
1603                    let (k, heads) = gdn_heads_of_chip(g, tp, c);
1604                    let (nk_c, nv_c) = (k[0].1 / ghd, heads_in(&heads));
1605                    if nv_c == 0 {
1606                        ao.push(self.zero_partial(m, &format!("ao{l}_c{c}"), &format!("xn{l}"), c));
1607                        continue;
1608                    }
1609                    self.decl_gdn_weight_slices(m, g, l, c, tp);
1610                    self.decl_gdn_state_slices(m, g, l, c, tp, "");
1611                    for base in [
1612                        "qr", "kr", "vr", "zz", "qc", "kc", "vc", "qs", "ks", "vs", "qn", "kn", "br", "bt", "ar",
1613                        "dy", "od", "ao",
1614                    ] {
1615                        m.place(&format!("{base}{l}_c{c}"), c, None);
1616                    }
1617                    self.s.push_str(&format!(
1618                        "Let qr{l}_c{c} be xn{l} matmul Wq{l}_c{c}.\n\
1619                         Let kr{l}_c{c} be xn{l} matmul Wk{l}_c{c}.\n\
1620                         Let vr{l}_c{c} be xn{l} matmul Wv{l}_c{c}.\n\
1621                         Let zz{l}_c{c} be xn{l} matmul Wz{l}_c{c}.\n\
1622                         Let qc{l}_c{c} be causal conv of qr{l}_c{c} with weight Wcq{l}_c{c} state Csq{l}_c{c} over {taps} taps.\n\
1623                         Let kc{l}_c{c} be causal conv of kr{l}_c{c} with weight Wck{l}_c{c} state Csk{l}_c{c} over {taps} taps.\n\
1624                         Let vc{l}_c{c} be causal conv of vr{l}_c{c} with weight Wcv{l}_c{c} state Csv{l}_c{c} over {taps} taps.\n\
1625                         Let qs{l}_c{c} be silu of qc{l}_c{c}.\n\
1626                         Let ks{l}_c{c} be silu of kc{l}_c{c}.\n\
1627                         Let vs{l}_c{c} be silu of vc{l}_c{c}.\n\
1628                         Let qn{l}_c{c} be l2norm of qs{l}_c{c} across {nk_c} heads.\n\
1629                         Let kn{l}_c{c} be l2norm of ks{l}_c{c} across {nk_c} heads.\n\
1630                         Let br{l}_c{c} be xn{l} matmul Wb{l}_c{c}.\n\
1631                         Let bt{l}_c{c} be sigmoid of br{l}_c{c}.\n\
1632                         Let ar{l}_c{c} be xn{l} matmul Wa{l}_c{c}.\n\
1633                         Let dy{l}_c{c} be decay of ar{l}_c{c} with bias Dt{l}_c{c} rate Al{l}_c{c}.\n\
1634                         Let od{l}_c{c} be gated delta of qn{l}_c{c} over kn{l}_c{c} and vs{l}_c{c} with {gate} zz{l}_c{c} beta bt{l}_c{c} decay dy{l}_c{c} state St{l}_c{c} norm Gn{l} with {nv_c} heads {nk_c} groups.\n\
1635                         Let ao{l}_c{c} be od{l}_c{c} matmul Wo{l}_c{c}.\n"
1636                    ));
1637                    ao.push(format!("ao{l}_c{c}"));
1638                }
1639            }
1640            Mixer::Mla(_) => unreachable!("author::check_tp refuses latent attention"),
1641        }
1642        self.fold(m, &format!("ao{l}"), ao);
1643        self.decl_f32(&format!("fn{l}"), 1, d);
1644        let ao = self.post_norm(l, &format!("ao{l}"), true);
1645        self.s.push_str(&format!(
1646            "Let xr{l} be {cur} plus {ao}.\nLet x2n{l} be rmsnorm of xr{l} with weight fn{l}.\n"
1647        ));
1648        let Ffn::Dense { dff, .. } = spec.layers[l].ffn else {
1649            unreachable!("check_tp refuses a tensor-parallel expert mixture")
1650        };
1651        let mut dn = Vec::new();
1652        for c in 0..tp {
1653            if run_of(dff, tp, c).1 == 0 {
1654                dn.push(self.zero_partial(m, &format!("dn{l}_c{c}"), &format!("x2n{l}"), c));
1655                continue;
1656            }
1657            self.decl_ffn_slices(m, l, dff, c, tp);
1658            self.s.push_str(&format!(
1659                "Let gt{l}_c{c} be x2n{l} matmul Wg{l}_c{c}.\n\
1660                 Let up{l}_c{c} be x2n{l} matmul Wu{l}_c{c}.\n"
1661            ));
1662            let bound = self.glu(l, &format!("gt{l}_c{c}"), &format!("up{l}_c{c}"), &format!("hh{l}_c{c}"));
1663            self.s.push_str(&format!("Let dn{l}_c{c} be hh{l}_c{c} matmul Wd{l}_c{c}.\n"));
1664            for name in [format!("gt{l}_c{c}"), format!("up{l}_c{c}")].into_iter().chain(bound).chain([format!("dn{l}_c{c}")]) {
1665                m.place(&name, c, None);
1666            }
1667            dn.push(format!("dn{l}_c{c}"));
1668        }
1669        self.fold(m, &format!("dn{l}"), dn);
1670        let dn = self.post_norm(l, &format!("dn{l}"), false);
1671        self.s.push_str(&format!("Let xo{l} be xr{l} plus {dn}.\n"));
1672    }
1673
1674    /// Layer `l` of a BATCHED decode step over `tp` chips: the stack and its norms replicated; chip `c`'s
1675    /// column-parallel projections on the whole stack; each sequence's per-head work on its row of the chip's stack;
1676    /// the chip's row-parallel output projection a `bsz × d` partial; the partials summed by one all-reduce of the
1677    /// stack. Per-sequence chip tensors are `…{l}_s{b}_c{c}`; chip stacks are `b…{l}_c{c}`.
1678    #[allow(clippy::too_many_arguments)]
1679    fn stacked_tp_layer(&mut self, m: &mut TpManifest, l: usize, cur: &str, tp: usize, ctx: usize, bsz: usize) {
1680        let spec = self.spec;
1681        let d = spec.d;
1682        self.decl_f32(&format!("an{l}"), 1, d);
1683        self.s.push_str(&format!("Let bxn{l} be rmsnorm of {cur} with weight an{l}.\n"));
1684        let mut ao = Vec::new();
1685        match &spec.layers[l].mixer {
1686            Mixer::Attention(a) => {
1687                let hd = a.head_dim;
1688                if a.qk_norm {
1689                    self.decl_f32(&format!("Qn{l}"), 1, hd);
1690                    self.decl_f32(&format!("Kn{l}"), 1, hd);
1691                }
1692                for c in 0..tp {
1693                    let ((_, hq), (_, hkv)) = attn_heads_of_chip(a, tp, c);
1694                    if hq == 0 {
1695                        ao.push(self.zero_partial(m, &format!("bao{l}_c{c}"), &format!("bxn{l}"), c));
1696                        continue;
1697                    }
1698                    self.decl_attn_weight_slices(m, a, l, c, tp);
1699                    for b in 0..bsz {
1700                        self.decl_attn_cache_slices(m, a, l, c, tp, ctx, &format!("_s{b}"));
1701                    }
1702                    let mut bases = vec!["bqr", "bkr", "bvr", "bct", "bao"];
1703                    if a.output_gate {
1704                        bases.extend(["bgr", "bgs", "bcg"]);
1705                    }
1706                    for base in bases {
1707                        m.place(&format!("{base}{l}_c{c}"), c, None);
1708                    }
1709                    self.s.push_str(&format!("Let bqr{l}_c{c} be bxn{l} matmul Wq{l}_c{c}.\n"));
1710                    if a.output_gate {
1711                        self.s.push_str(&format!("Let bgr{l}_c{c} be bxn{l} matmul Wqg{l}_c{c}.\n"));
1712                    }
1713                    self.s.push_str(&format!(
1714                        "Let bkr{l}_c{c} be bxn{l} matmul Wk{l}_c{c}.\n\
1715                         Let bvr{l}_c{c} be bxn{l} matmul Wv{l}_c{c}.\n\
1716                         Let bct{l}_c{c} be a {bsz} by {} tensor of Real.\n",
1717                        hq * a.value_dim
1718                    ));
1719                    for b in 0..bsz {
1720                        let r = b + 1;
1721                        let mut bases = vec!["qr", "kr", "vr", "ct"];
1722                        if a.qk_norm {
1723                            bases.extend(["qm", "km"]);
1724                        }
1725                        if a.rope.is_some() {
1726                            bases.extend(["qp", "kp"]);
1727                        }
1728                        if a.qk_unit_norm {
1729                            bases.extend(["qu", "ku"]);
1730                        }
1731                        if a.temperature.is_some() {
1732                            bases.push("qt");
1733                        }
1734                        for base in bases {
1735                            m.place(&format!("{base}{l}_s{b}_c{c}"), c, None);
1736                        }
1737                        self.s.push_str(&format!(
1738                            "Let qr{l}_s{b}_c{c} be row {r} of bqr{l}_c{c}.\n\
1739                             Let kr{l}_s{b}_c{c} be row {r} of bkr{l}_c{c}.\n\
1740                             Let vr{l}_s{b}_c{c} be row {r} of bvr{l}_c{c}.\n"
1741                        ));
1742                        let (mut q, mut k) = (format!("qr{l}_s{b}_c{c}"), format!("kr{l}_s{b}_c{c}"));
1743                        if a.qk_norm {
1744                            self.s.push_str(&format!(
1745                                "Let qm{l}_s{b}_c{c} be rmsnorm of qr{l}_s{b}_c{c} with weight Qn{l} across {hq} heads.\n\
1746                                 Let km{l}_s{b}_c{c} be rmsnorm of kr{l}_s{b}_c{c} with weight Kn{l} across {hkv} heads.\n"
1747                            ));
1748                            (q, k) = (format!("qm{l}_s{b}_c{c}"), format!("km{l}_s{b}_c{c}"));
1749                        }
1750                        if a.rope.is_some() {
1751                            let angles = self.angles(l, AttnForm::Cached { ctx }, &format!("pos_s{b}"));
1752                            self.s.push_str(&format!(
1753                                "Let qp{l}_s{b}_c{c} be rope of {q} with {angles} across {hq} heads.\n\
1754                                 Let kp{l}_s{b}_c{c} be rope of {k} with {angles} across {hkv} heads.\n"
1755                            ));
1756                            (q, k) = (format!("qp{l}_s{b}_c{c}"), format!("kp{l}_s{b}_c{c}"));
1757                        }
1758                        (q, k) = self.llama4_qk(a, (q, k), (hq, hkv), hq, Some((format!("pos_s{b}"), ctx)), &|base| format!("{base}{l}_s{b}_c{c}"));
1759                        let w = score_clauses(a);
1760                        self.s.push_str(&format!(
1761                            "Set row pos_s{b} of Kc{l}_s{b}_c{c} to {k}.\n\
1762                             Set row pos_s{b} of Vc{l}_s{b}_c{c} to vr{l}_s{b}_c{c}.\n\
1763                             Let ct{l}_s{b}_c{c} be attention of {q} over Kc{l}_s{b}_c{c} and Vc{l}_s{b}_c{c} with {hq} heads {hkv} groups up to pos_s{b}{w}.\n\
1764                             Set row {r} of bct{l}_c{c} to ct{l}_s{b}_c{c}.\n"
1765                        ));
1766                    }
1767                    if a.output_gate {
1768                        self.s.push_str(&format!(
1769                            "Let bgs{l}_c{c} be sigmoid of bgr{l}_c{c}.\n\
1770                             Let bcg{l}_c{c} be bct{l}_c{c} hadamard bgs{l}_c{c}.\n\
1771                             Let bao{l}_c{c} be bcg{l}_c{c} matmul Wo{l}_c{c}.\n"
1772                        ));
1773                    } else {
1774                        self.s.push_str(&format!("Let bao{l}_c{c} be bct{l}_c{c} matmul Wo{l}_c{c}.\n"));
1775                    }
1776                    ao.push(format!("bao{l}_c{c}"));
1777                }
1778            }
1779            Mixer::GatedDelta(g) => {
1780                let gate = gate_clause(g);
1781                let (taps, ghd) = (g.conv_taps, g.head_dim);
1782                self.decl_f32(&format!("Gn{l}"), 1, ghd);
1783                for c in 0..tp {
1784                    let (k, heads) = gdn_heads_of_chip(g, tp, c);
1785                    let (nk_c, nv_c) = (k[0].1 / ghd, heads_in(&heads));
1786                    if nv_c == 0 {
1787                        ao.push(self.zero_partial(m, &format!("bao{l}_c{c}"), &format!("bxn{l}"), c));
1788                        continue;
1789                    }
1790                    self.decl_gdn_weight_slices(m, g, l, c, tp);
1791                    for b in 0..bsz {
1792                        self.decl_gdn_state_slices(m, g, l, c, tp, &format!("_s{b}"));
1793                    }
1794                    for base in ["bqr", "bkr", "bvr", "bzz", "bbr", "bar", "bod", "bao"] {
1795                        m.place(&format!("{base}{l}_c{c}"), c, None);
1796                    }
1797                    self.s.push_str(&format!(
1798                        "Let bqr{l}_c{c} be bxn{l} matmul Wq{l}_c{c}.\n\
1799                         Let bkr{l}_c{c} be bxn{l} matmul Wk{l}_c{c}.\n\
1800                         Let bvr{l}_c{c} be bxn{l} matmul Wv{l}_c{c}.\n\
1801                         Let bzz{l}_c{c} be bxn{l} matmul Wz{l}_c{c}.\n\
1802                         Let bbr{l}_c{c} be bxn{l} matmul Wb{l}_c{c}.\n\
1803                         Let bar{l}_c{c} be bxn{l} matmul Wa{l}_c{c}.\n\
1804                         Let bod{l}_c{c} be a {bsz} by {} tensor of Real.\n",
1805                        nv_c * ghd
1806                    ));
1807                    for b in 0..bsz {
1808                        let r = b + 1;
1809                        for base in [
1810                            "qr", "kr", "vr", "zz", "br", "ar", "qc", "kc", "vc", "qs", "ks", "vs", "qn", "kn", "bt",
1811                            "dy", "od",
1812                        ] {
1813                            m.place(&format!("{base}{l}_s{b}_c{c}"), c, None);
1814                        }
1815                        self.s.push_str(&format!(
1816                            "Let qr{l}_s{b}_c{c} be row {r} of bqr{l}_c{c}.\n\
1817                             Let kr{l}_s{b}_c{c} be row {r} of bkr{l}_c{c}.\n\
1818                             Let vr{l}_s{b}_c{c} be row {r} of bvr{l}_c{c}.\n\
1819                             Let zz{l}_s{b}_c{c} be row {r} of bzz{l}_c{c}.\n\
1820                             Let br{l}_s{b}_c{c} be row {r} of bbr{l}_c{c}.\n\
1821                             Let ar{l}_s{b}_c{c} be row {r} of bar{l}_c{c}.\n\
1822                             Let qc{l}_s{b}_c{c} be causal conv of qr{l}_s{b}_c{c} with weight Wcq{l}_c{c} state Csq{l}_s{b}_c{c} over {taps} taps.\n\
1823                             Let kc{l}_s{b}_c{c} be causal conv of kr{l}_s{b}_c{c} with weight Wck{l}_c{c} state Csk{l}_s{b}_c{c} over {taps} taps.\n\
1824                             Let vc{l}_s{b}_c{c} be causal conv of vr{l}_s{b}_c{c} with weight Wcv{l}_c{c} state Csv{l}_s{b}_c{c} over {taps} taps.\n\
1825                             Let qs{l}_s{b}_c{c} be silu of qc{l}_s{b}_c{c}.\n\
1826                             Let ks{l}_s{b}_c{c} be silu of kc{l}_s{b}_c{c}.\n\
1827                             Let vs{l}_s{b}_c{c} be silu of vc{l}_s{b}_c{c}.\n\
1828                             Let qn{l}_s{b}_c{c} be l2norm of qs{l}_s{b}_c{c} across {nk_c} heads.\n\
1829                             Let kn{l}_s{b}_c{c} be l2norm of ks{l}_s{b}_c{c} across {nk_c} heads.\n\
1830                             Let bt{l}_s{b}_c{c} be sigmoid of br{l}_s{b}_c{c}.\n\
1831                             Let dy{l}_s{b}_c{c} be decay of ar{l}_s{b}_c{c} with bias Dt{l}_c{c} rate Al{l}_c{c}.\n\
1832                             Let od{l}_s{b}_c{c} be gated delta of qn{l}_s{b}_c{c} over kn{l}_s{b}_c{c} and vs{l}_s{b}_c{c} with {gate} zz{l}_s{b}_c{c} beta bt{l}_s{b}_c{c} decay dy{l}_s{b}_c{c} state St{l}_s{b}_c{c} norm Gn{l} with {nv_c} heads {nk_c} groups.\n\
1833                             Set row {r} of bod{l}_c{c} to od{l}_s{b}_c{c}.\n"
1834                        ));
1835                    }
1836                    self.s.push_str(&format!("Let bao{l}_c{c} be bod{l}_c{c} matmul Wo{l}_c{c}.\n"));
1837                    ao.push(format!("bao{l}_c{c}"));
1838                }
1839            }
1840            Mixer::Mla(_) => unreachable!("author::check_tp refuses latent attention"),
1841        }
1842        self.fold(m, &format!("bao{l}"), ao);
1843        self.decl_f32(&format!("fn{l}"), 1, d);
1844        let ao = self.post_norm(l, &format!("bao{l}"), true);
1845        self.s.push_str(&format!(
1846            "Let bxr{l} be {cur} plus {ao}.\nLet bx2n{l} be rmsnorm of bxr{l} with weight fn{l}.\n"
1847        ));
1848        let Ffn::Dense { dff, .. } = spec.layers[l].ffn else {
1849            unreachable!("check_tp refuses a tensor-parallel expert mixture")
1850        };
1851        let mut dn = Vec::new();
1852        for c in 0..tp {
1853            if run_of(dff, tp, c).1 == 0 {
1854                dn.push(self.zero_partial(m, &format!("bdn{l}_c{c}"), &format!("bx2n{l}"), c));
1855                continue;
1856            }
1857            self.decl_ffn_slices(m, l, dff, c, tp);
1858            self.s.push_str(&format!(
1859                "Let bgt{l}_c{c} be bx2n{l} matmul Wg{l}_c{c}.\n\
1860                 Let bup{l}_c{c} be bx2n{l} matmul Wu{l}_c{c}.\n"
1861            ));
1862            let bound = self.glu(l, &format!("bgt{l}_c{c}"), &format!("bup{l}_c{c}"), &format!("bhh{l}_c{c}"));
1863            self.s.push_str(&format!("Let bdn{l}_c{c} be bhh{l}_c{c} matmul Wd{l}_c{c}.\n"));
1864            for name in [format!("bgt{l}_c{c}"), format!("bup{l}_c{c}")].into_iter().chain(bound).chain([format!("bdn{l}_c{c}")]) {
1865                m.place(&name, c, None);
1866            }
1867            dn.push(format!("bdn{l}_c{c}"));
1868        }
1869        self.fold(m, &format!("bdn{l}"), dn);
1870        let dn = self.post_norm(l, &format!("bdn{l}"), false);
1871        self.s.push_str(&format!("Let bxo{l} be bxr{l} plus {dn}.\n"));
1872    }
1873
1874    fn finish_tp(self, m: TpManifest) -> TpAuthored {
1875        let (s, f, q) = self.finish();
1876        (s, f, q, m)
1877    }
1878}
1879
1880/// A whole decode step over `tp` chips: the embedding lookup and the head replicated, every layer split.
1881pub fn tp_decode_step(spec: &ModelSpec, dir: &str, ctx: usize, tok: usize, pos: usize, tp: usize) -> Result<TpAuthored, NotYet> {
1882    check_tp(spec, tp)?;
1883    let mut p = Program::new(spec, dir);
1884    let mut m = TpManifest::new(tp);
1885    p.s.push_str(&format!("Let tok be {tok}.\nLet pos be {pos}.\n"));
1886    p.embed();
1887    p.rope_cache(ctx);
1888    let mut cur = "x".to_string();
1889    for l in 0..spec.layers.len() {
1890        p.tp_layer(&mut m, l, &cur, tp, ctx);
1891        cur = format!("xo{l}");
1892    }
1893    p.head(&cur);
1894    p.next_token();
1895    Ok(p.finish_tp(m))
1896}
1897
1898/// A BATCHED decode step over `tp` chips — the serving shape: the stacked sequences with every layer split, the
1899/// embedding and the head on the replicated spine.
1900pub fn tp_decode_batch(spec: &ModelSpec, dir: &str, ctx: usize, seqs: &[(usize, usize)], tp: usize) -> Result<TpAuthored, NotYet> {
1901    check_tp(spec, tp)?;
1902    let bsz = seqs.len();
1903    let mut p = Program::new(spec, dir);
1904    let mut m = TpManifest::new(tp);
1905    for (b, (_, pos)) in seqs.iter().enumerate() {
1906        p.s.push_str(&format!("Let pos_s{b} be {pos}.\n"));
1907    }
1908    p.batched_embed(&seqs.iter().map(|(tok, _)| *tok).collect::<Vec<_>>());
1909    p.rope_cache(ctx);
1910    let mut cur = stacked_layer_input(0);
1911    for l in 0..spec.layers.len() {
1912        p.stacked_tp_layer(&mut m, l, &cur, tp, ctx, bsz);
1913        cur = stacked_layer_input(l + 1);
1914    }
1915    p.batched_head(&cur, bsz);
1916    Ok(p.finish_tp(m))
1917}
1918
1919/// Layer `l` of a tensor-parallel decode step alone: its input and position declared, the rotary tables for an
1920/// attention layer, then the split layer.
1921pub fn tp_decode_layer(spec: &ModelSpec, l: usize, dir: &str, ctx: usize, pos: usize, tp: usize) -> Result<TpAuthored, NotYet> {
1922    check_tp(spec, tp)?;
1923    let mut p = Program::new(spec, dir);
1924    let mut m = TpManifest::new(tp);
1925    let input = layer_input(l);
1926    p.s.push_str(&format!("Let pos be {pos}.\n"));
1927    p.s.push_str(&format!("Let {input} be a 1 by {} tensor of Real.\n", spec.d));
1928    p.rotary_tables(Some(l), true, ctx);
1929    p.tp_layer(&mut m, l, &input, tp, ctx);
1930    Ok(p.finish_tp(m))
1931}
1932
1933/// Layer `l` of a batched tensor-parallel decode step alone.
1934pub fn tp_stacked_layer(spec: &ModelSpec, l: usize, dir: &str, ctx: usize, poss: &[usize], tp: usize) -> Result<TpAuthored, NotYet> {
1935    check_tp(spec, tp)?;
1936    let bsz = poss.len();
1937    let mut p = Program::new(spec, dir);
1938    let mut m = TpManifest::new(tp);
1939    for (b, pos) in poss.iter().enumerate() {
1940        p.s.push_str(&format!("Let pos_s{b} be {pos}.\n"));
1941    }
1942    let input = stacked_layer_input(l);
1943    p.s.push_str(&format!("Let {input} be a {bsz} by {} tensor of Real.\n", spec.d));
1944    p.rotary_tables(Some(l), true, ctx);
1945    p.stacked_tp_layer(&mut m, l, &input, tp, ctx, bsz);
1946    Ok(p.finish_tp(m))
1947}