Skip to main content

logicaffeine_compile/model/
reference.rs

1//! The reference forward: what a [`ModelSpec`] computes, evaluated in `f64` on the CPU over the checkpoint's own
2//! weights.
3//!
4//! This is the oracle every compiled lane and every competitor is measured against — the "same-weights" reference:
5//! the weights are exactly the checkpoint's (each dequantized as ggml defines its format), and everything after the
6//! weights is `f64`, so the only error left in a lane's logits is the lane's own. It runs one prompt as a batch per
7//! layer (each weight is read once per pass, not once per token) and then decodes with a KV cache.
8//!
9//! The operations follow llama.cpp's graph for each architecture (`src/models/<arch>.cpp` at the pinned commit).
10
11use std::collections::{BTreeMap, HashMap, HashSet};
12use std::sync::Arc;
13
14use super::gguf::Gguf;
15use super::quant::{f16_to_f32, f32_to_f16, GgmlType};
16use super::spec::{
17    Act, Attention, Ffn, GateActivation, GatedDelta, Gating, HyperConnections, Indexer, Layer, Mixer, Mla, Moe, ModelSpec,
18    Rope, RopeScaling,
19};
20
21/// Why the reference cannot run a checkpoint.
22#[derive(Debug)]
23pub enum ReferenceError {
24    Io(std::io::Error),
25    /// A part of the spec the reference does not evaluate yet, named.
26    NotYet(&'static str),
27}
28
29impl std::fmt::Display for ReferenceError {
30    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31        match self {
32            ReferenceError::Io(e) => write!(f, "{e}"),
33            ReferenceError::NotYet(what) => write!(f, "the reference does not evaluate {what} yet"),
34        }
35    }
36}
37
38impl From<std::io::Error> for ReferenceError {
39    fn from(e: std::io::Error) -> Self {
40        ReferenceError::Io(e)
41    }
42}
43
44type R<T> = Result<T, ReferenceError>;
45
46/// What one block carries from position to position.
47#[derive(Clone)]
48enum LayerState {
49    /// An attention block's cache: every position's keys and values so far, and its index key where the model selects
50    /// with QSA (unnormed: a block's keys are averaged before their norm).
51    Attention { k: Vec<Vec<f64>>, v: Vec<Vec<f64>>, ik: Vec<Vec<f64>> },
52    /// A gated-delta block's state: the last `taps − 1` convolution inputs, oldest first, and each value head's
53    /// `head_dim × head_dim` memory (row = value dimension, column = key dimension).
54    Delta { conv: Vec<Vec<f64>>, memory: Vec<f64> },
55}
56
57impl LayerState {
58    fn fresh(layer: &Layer) -> LayerState {
59        match &layer.mixer {
60            Mixer::Attention(_) | Mixer::Mla(_) => LayerState::Attention { k: Vec::new(), v: Vec::new(), ik: Vec::new() },
61            Mixer::GatedDelta(g) => {
62                let channels = 2 * g.k_heads * g.head_dim + g.v_heads * g.head_dim;
63                LayerState::Delta {
64                    conv: vec![vec![0.0; channels]; g.conv_taps.saturating_sub(1)],
65                    memory: vec![0.0; g.v_heads * g.head_dim * g.head_dim],
66                }
67            }
68        }
69    }
70}
71
72/// Where the reference reads a model's weights: a checkpoint, or tensors held in memory (a test's tiny model).
73/// Tensors are named and laid out as GGUF names and lays them out (`dims[0]` the fastest).
74pub trait WeightSource {
75    /// A tensor's format and dims.
76    fn describe(&self, name: &str) -> std::io::Result<(GgmlType, Vec<u64>)>;
77    /// The bytes of rows `[first, first + count)`, a row being the tensor's `dims[0]` elements.
78    fn row_bytes(&mut self, name: &str, first: usize, count: usize) -> std::io::Result<Vec<u8>>;
79    fn has(&self, name: &str) -> bool;
80}
81
82impl WeightSource for Gguf {
83    fn describe(&self, name: &str) -> std::io::Result<(GgmlType, Vec<u64>)> {
84        let ty = self.tensor_type(name)?;
85        Ok((ty, self.dims(name).unwrap_or_default().to_vec()))
86    }
87    fn row_bytes(&mut self, name: &str, first: usize, count: usize) -> std::io::Result<Vec<u8>> {
88        Gguf::row_bytes(self, name, first, count)
89    }
90    fn has(&self, name: &str) -> bool {
91        Gguf::has(self, name)
92    }
93}
94
95/// Tensors held in memory, each in a GGUF format.
96#[derive(Default, Clone)]
97pub struct Tensors {
98    map: BTreeMap<String, (GgmlType, Vec<u64>, Vec<u8>)>,
99}
100
101impl Tensors {
102    /// Add an `f32` tensor of `dims` (GGUF order) from its values.
103    pub fn f32(&mut self, name: &str, dims: &[u64], values: &[f32]) {
104        assert_eq!(dims.iter().product::<u64>() as usize, values.len(), "{name}: dims and values disagree");
105        let bytes = values.iter().flat_map(|v| v.to_le_bytes()).collect();
106        self.map.insert(name.to_string(), (GgmlType::F32, dims.to_vec(), bytes));
107    }
108
109    /// Add a tensor already encoded in `ty`.
110    pub fn encoded(&mut self, name: &str, ty: GgmlType, dims: &[u64], bytes: Vec<u8>) {
111        let n = dims.iter().product::<u64>() as usize;
112        assert_eq!(ty.bytes_for(n), bytes.len(), "{name}: {} bytes for {n} {} weights", bytes.len(), ty.name());
113        self.map.insert(name.to_string(), (ty, dims.to_vec(), bytes));
114    }
115
116    /// Every tensor, by name.
117    pub fn names(&self) -> impl Iterator<Item = &str> {
118        self.map.keys().map(String::as_str)
119    }
120
121    /// A tensor's values, dequantized.
122    pub fn values(&self, name: &str) -> Option<Vec<f32>> {
123        self.map.get(name).map(|(ty, _, bytes)| {
124            let mut out = Vec::new();
125            ty.dequantize(bytes, &mut out);
126            out
127        })
128    }
129}
130
131impl WeightSource for Tensors {
132    fn describe(&self, name: &str) -> std::io::Result<(GgmlType, Vec<u64>)> {
133        self.map
134            .get(name)
135            .map(|(ty, dims, _)| (*ty, dims.clone()))
136            .ok_or_else(|| std::io::Error::new(std::io::ErrorKind::NotFound, format!("no tensor {name}")))
137    }
138    fn row_bytes(&mut self, name: &str, first: usize, count: usize) -> std::io::Result<Vec<u8>> {
139        let (ty, dims, bytes) = self
140            .map
141            .get(name)
142            .ok_or_else(|| std::io::Error::new(std::io::ErrorKind::NotFound, format!("no tensor {name}")))?;
143        let row = ty.bytes_for(dims[0] as usize);
144        Ok(bytes[first * row..(first + count) * row].to_vec())
145    }
146    fn has(&self, name: &str) -> bool {
147        self.map.contains_key(name)
148    }
149}
150
151/// The bytes the reference keeps of a checkpoint's tensors by default: every tensor of a model up to this size is
152/// read from the file once.
153pub const DEFAULT_CACHE_BUDGET: usize = 16 << 30;
154
155/// How the reference's projections by quantized weights read their activations. Exact is the model's arithmetic;
156/// the others are the activations a quantized matmul reads under llama.cpp's rule — a quantized weight reads a
157/// quantized activation — computed as the GPU lane's kernels compute them, so a lane can be held to its own precision.
158#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
159pub enum Activations {
160    /// As computed, in `f64`.
161    #[default]
162    Exact,
163    /// Rounded to `f32`, then each 32 values one int8 word over a shared scale `max|v| / 127` (1 for a zero block),
164    /// rounded to the nearest, ties to even.
165    Int8,
166    /// The high word as `Int8` (the scale's floor 1e-30, clamped to −128..127) and a low int8 word holding the
167    /// remainder `v − hi·s` at a 128th of the scale.
168    Int8TwoPass,
169}
170
171/// How an attention block's cache keeps the rows it is given.
172#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
173pub enum KvStorage {
174    /// As computed, in `f64`.
175    #[default]
176    Exact,
177    /// Each element rounded to `f32` and then to binary16, as llama.cpp's default `f16` cache stores the `f32` rows
178    /// it computes; every read of the cache takes the rounded row.
179    F16,
180}
181
182/// `v` rounded to `f32` and then to binary16, to the nearest (ties to even) — or, `flipped`, to its other binary16
183/// neighbour — how far the `f32` value lies from the half-way point between the two neighbours (infinitely far for a
184/// value binary16 holds exactly, or one past its range), and how far apart the neighbours are.
185fn binary16(v: f64, flipped: bool) -> (f64, f64, f64) {
186    let f = v as f32;
187    let h = f32_to_f16(f);
188    let near = f16_to_f32(h);
189    if near == f || !near.is_finite() {
190        return (f64::from(near), f64::INFINITY, 0.0);
191    }
192    // The neighbour the other side of `f`: a step up in value or down, the sign bit deciding which way the bits go.
193    let up = near < f;
194    let other = match (h & 0x8000 != 0, h & 0x7fff, up) {
195        (false, _, true) | (true, _, false) => h.wrapping_add(1),
196        (false, 0, false) => 0x8001,
197        (true, 0, true) => 0x0001,
198        _ => h.wrapping_sub(1),
199    };
200    let far = f16_to_f32(other);
201    let (near, far, f) = (f64::from(near), f64::from(far), f64::from(f));
202    (if flipped { far } else { near }, (f - (near + far) / 2.0).abs(), (far - near).abs())
203}
204
205/// How a gated-delta layer keeps its recurrent memory between steps.
206#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
207pub enum StateStorage {
208    /// As computed, in `f64`.
209    #[default]
210    Exact,
211    /// Each element rounded to `f32` and then to bfloat16 (to the nearest, ties to even) once its step has read it, as a
212    /// lane storing its memory in bf16 keeps it.
213    Bf16,
214}
215
216impl StateStorage {
217    /// `v` as the memory keeps it.
218    fn keep(self, v: f64) -> f64 {
219        match self {
220            StateStorage::Exact => v,
221            StateStorage::Bf16 => {
222                let x = v as f32;
223                if x.is_nan() {
224                    return f64::from(x);
225                }
226                let bits = x.to_bits();
227                f64::from(f32::from_bits(bits.wrapping_add(0x7FFF + ((bits >> 16) & 1)) & 0xFFFF_0000))
228            }
229        }
230    }
231}
232
233/// `x` as a projection by a quantized weight reads it under `mode`, a block of 32 values at a time.
234pub fn quantize_activations(x: &[f64], mode: Activations) -> Vec<f64> {
235    quantize_deciding(x, mode, |_, _, q| q.round_ties_even())
236}
237
238/// [`quantize_activations`] with each word's whole number decided by `round(element, word, q)`: `q` the value in the
239/// word's own levels, `word` 0 for the int8 (or two-pass high) word and 1 for the two-pass low word.
240fn quantize_deciding(x: &[f64], mode: Activations, mut round: impl FnMut(usize, u8, f32) -> f32) -> Vec<f64> {
241    if mode == Activations::Exact {
242        return x.to_vec();
243    }
244    // An int8 word: the decided whole number within −128..127, with no sign on its zero.
245    let word = |q: f32| f32::from(q.clamp(-128.0, 127.0) as i8);
246    let mut out = Vec::with_capacity(x.len());
247    for (b, block) in x.chunks(32).enumerate() {
248        let v: Vec<f32> = block.iter().map(|&a| a as f32).collect();
249        let amax = v.iter().fold(0f32, |m, a| m.max(a.abs()));
250        match mode {
251            Activations::Int8 => {
252                let s = if amax > 0.0 { amax / 127.0 } else { 1.0 };
253                for (i, &a) in v.iter().enumerate() {
254                    out.push(f64::from(word(round(b * 32 + i, 0, a / s))) * f64::from(s));
255                }
256            }
257            _ => {
258                let s = amax.max(1e-30) / 127.0;
259                let sl = s * 0.0078125;
260                for (i, &a) in v.iter().enumerate() {
261                    let hi = word(round(b * 32 + i, 0, a / s));
262                    let lo = word(round(b * 32 + i, 1, (-hi).mul_add(s, a) / sl));
263                    out.push(f64::from(hi) * f64::from(s) + f64::from(lo) * f64::from(sl));
264                }
265            }
266        }
267    }
268    out
269}
270
271/// How near a half-way point between two levels a rounding the reference records lies, in levels: within it, a run
272/// whose activation differs from the reference's by its own `f32` rounding may take the other level.
273pub const NEAR_ROUNDING: f64 = 1e-3;
274
275/// How near a tie, as a fraction of the chosen score, a routing call the reference records lies.
276pub const NEAR_ROUTING: f64 = 1e-3;
277
278/// The word a cached value's binary16 rounding is recorded under ([`RoundingCall::word`]).
279pub const CACHE_WORD: u8 = 2;
280
281/// A rounding the reference made within [`NEAR_ROUNDING`] of a half-way point: value `element` of the activation whose
282/// `f32` values hash to `activation` (`word` 0 the int8 or two-pass high word, 1 the low word, [`CACHE_WORD`] a cached
283/// row's binary16), first made in the step ending at `position`, `margin` levels from the half-way point (a cached
284/// value's in levels of its row's scale, its largest magnitude over 127). An activation is one decision however many
285/// projections read it — the lane quantizes it once — so a call names the activation, not the read.
286#[derive(Clone, Copy, Debug, PartialEq)]
287pub struct RoundingCall {
288    pub activation: u64,
289    pub element: usize,
290    pub word: u8,
291    pub position: usize,
292    pub margin: f64,
293    /// How far the other outcome moves the value, in the levels `margin` is measured in: one for an int8 word, a
294    /// cached value's binary16 step for its rounding.
295    pub step: f64,
296}
297
298/// A decision the reference made near its other outcome — one a run in another precision may make the other way.
299#[derive(Clone, Copy, Debug, PartialEq)]
300pub enum NearCall {
301    Rounding(RoundingCall),
302    Routing(RoutingCall),
303}
304
305impl NearCall {
306    /// The position the call was made at (a prompt's last position for a call in its step).
307    pub fn position(&self) -> usize {
308        match self {
309            NearCall::Rounding(c) => c.position,
310            NearCall::Routing(c) => c.position,
311        }
312    }
313}
314
315/// The closest call a router made: at `position` (0-based) in layer `layer`, the last expert (or expert group) it
316/// chose scored `margin` above the first it passed over, on a selection score of `score`. A run in another precision
317/// may choose otherwise wherever `margin` is below what that precision resolves at `score`.
318#[derive(Clone, Copy, Debug, PartialEq)]
319pub struct RoutingCall {
320    pub layer: usize,
321    pub position: usize,
322    pub margin: f64,
323    pub score: f64,
324}
325
326/// The reference model over a checkpoint.
327pub struct Reference {
328    pub spec: ModelSpec,
329    g: Box<dyn WeightSource>,
330    states: Vec<LayerState>,
331    pos: usize,
332    threads: usize,
333    /// Whole tensors' bytes, kept while they fit `budget`; a tensor past it is read again each time it is used.
334    cache: HashMap<String, Arc<Vec<u8>>>,
335    cached: usize,
336    budget: usize,
337    closest: Option<RoutingCall>,
338    /// Every near call since the last reset, in the order first made, and the roundings among them.
339    near: Vec<NearCall>,
340    near_roundings: HashSet<(u64, usize, u8)>,
341    /// The last position of the step running.
342    at: usize,
343    /// The calls decided the other way at every run: roundings by (activation, element, word), routings by (layer,
344    /// position).
345    flipped_roundings: HashSet<(u64, usize, u8)>,
346    flipped_routings: HashSet<(usize, usize)>,
347    activations: Activations,
348    kv: KvStorage,
349    state: StateStorage,
350    /// The per-layer embedding's state: every token so far after `ngram - 1` ends of document, and the last
351    /// `(taps - 1)·ngram` normed gated values its dilated convolution reads, oldest first.
352    ple_tokens: Vec<u32>,
353    ple_conv: Vec<Vec<f64>>,
354}
355
356impl Reference {
357    pub fn new(spec: ModelSpec, g: impl WeightSource + 'static) -> R<Reference> {
358        for layer in &spec.layers {
359            if let Mixer::Attention(a) = &layer.mixer {
360                if a.output_gate && a.fused_qkv {
361                    return Err(ReferenceError::NotYet("an output gate on a fused query-key-value projection"));
362                }
363                if a.output_gate && a.value_dim != a.head_dim {
364                    return Err(ReferenceError::NotYet("an output gate over values narrower than the queries"));
365                }
366            }
367        }
368        let threads = std::thread::available_parallelism().map_or(4, |n| n.get());
369        let (ple_tokens, ple_conv) = Reference::fresh_ple(&spec);
370        Ok(Reference {
371            ple_tokens,
372            ple_conv,
373            states: spec.layers.iter().map(LayerState::fresh).collect(),
374            spec,
375            g: Box::new(g),
376            pos: 0,
377            threads,
378            cache: HashMap::new(),
379            cached: 0,
380            budget: DEFAULT_CACHE_BUDGET,
381            closest: None,
382            near: Vec::new(),
383            near_roundings: HashSet::new(),
384            at: 0,
385            flipped_roundings: HashSet::new(),
386            flipped_routings: HashSet::new(),
387            activations: Activations::Exact,
388            kv: KvStorage::Exact,
389            state: StateStorage::Exact,
390        })
391    }
392
393    /// The same reference with its quantized projections reading `mode`'s activations.
394    pub fn with_activations(mut self, mode: Activations) -> Reference {
395        self.activations = mode;
396        self
397    }
398
399    /// The same reference keeping its attention caches' rows as `kv` stores them.
400    pub fn with_kv_storage(mut self, kv: KvStorage) -> Reference {
401        self.kv = kv;
402        self
403    }
404
405    /// The same reference keeping its gated-delta memories as `state` stores them.
406    pub fn with_state_storage(mut self, state: StateStorage) -> Reference {
407        self.state = state;
408        self
409    }
410
411    /// The same reference keeping at most `bytes` of tensor data in memory.
412    pub fn with_cache_budget(mut self, bytes: usize) -> Reference {
413        self.budget = bytes;
414        self
415    }
416
417    /// A whole tensor's bytes, from the cache or the source (and cached when they fit the budget).
418    fn tensor_bytes(&mut self, name: &str) -> R<Arc<Vec<u8>>> {
419        if let Some(b) = self.cache.get(name) {
420            return Ok(b.clone());
421        }
422        let (_, dims) = self.g.describe(name)?;
423        let row = dims.first().copied().unwrap_or(1).max(1) as usize;
424        let rows = dims.iter().product::<u64>() as usize / row;
425        let bytes = Arc::new(self.g.row_bytes(name, 0, rows)?);
426        if self.cached + bytes.len() <= self.budget {
427            self.cached += bytes.len();
428            self.cache.insert(name.to_string(), bytes.clone());
429        }
430        Ok(bytes)
431    }
432
433    /// The number of positions run so far.
434    pub fn position(&self) -> usize {
435        self.pos
436    }
437
438    /// Layer `l`'s cached keys and values, one row per position (empty for a layer that is not attention).
439    pub fn cached(&self, l: usize) -> (&[Vec<f64>], &[Vec<f64>]) {
440        match &self.states[l] {
441            LayerState::Attention { k, v, .. } => (k, v),
442            LayerState::Delta { .. } => (&[], &[]),
443        }
444    }
445
446    /// Layer `l`'s gated-delta memory (empty for a layer that is not gated delta).
447    pub fn memory(&self, l: usize) -> &[f64] {
448        match &self.states[l] {
449            LayerState::Delta { memory, .. } => memory,
450            LayerState::Attention { .. } => &[],
451        }
452    }
453
454    /// Layer `l`'s convolution ring: its last `taps − 1` inputs, oldest first (empty for a layer that is not gated
455    /// delta).
456    pub fn conv(&self, l: usize) -> &[Vec<f64>] {
457        match &self.states[l] {
458            LayerState::Delta { conv, .. } => conv,
459            LayerState::Attention { .. } => &[],
460        }
461    }
462
463    /// Forget every position: empty caches, zero recurrent state, no routing or near calls. The calls decided the other
464    /// way stay decided so.
465    pub fn reset(&mut self) {
466        self.states = self.spec.layers.iter().map(LayerState::fresh).collect();
467        (self.ple_tokens, self.ple_conv) = Reference::fresh_ple(&self.spec);
468        self.pos = 0;
469        self.closest = None;
470        self.near.clear();
471        self.near_roundings.clear();
472    }
473
474    /// Every rounding and routing call since the last [`reset`](Self::reset) made near its other outcome, in order.
475    pub fn near_calls(&self) -> &[NearCall] {
476        &self.near
477    }
478
479    /// Decide a near call the other way at every run past it: a rounding takes the other level, a routing call keeps
480    /// the first expert it would pass over in place of the last it would keep.
481    pub fn flip(&mut self, call: NearCall) {
482        match call {
483            NearCall::Rounding(c) => {
484                self.flipped_roundings.insert((c.activation, c.element, c.word));
485            }
486            NearCall::Routing(c) => self.flip_routing(c),
487        }
488    }
489
490    /// The closest routing call since the last [`reset`](Self::reset) — `None` for a model without experts.
491    pub fn closest_routing(&self) -> Option<RoutingCall> {
492        self.closest
493    }
494
495    /// Decide one routing call the other way at every run past it: at `call`'s layer and position the router keeps
496    /// the first expert it would pass over in place of the last it would keep — how a run in another precision that
497    /// resolves the call the other way routes.
498    pub fn flip_routing(&mut self, call: RoutingCall) {
499        self.flipped_routings.insert((call.layer, call.position));
500    }
501
502    /// Note a routing decision: `chosen` scored `margin` above the first passed over.
503    fn routed(&mut self, layer: usize, position: usize, chosen: f64, passed: f64) {
504        if !passed.is_finite() {
505            return;
506        }
507        let call = RoutingCall { layer, position, margin: chosen - passed, score: chosen };
508        if self.closest.is_none_or(|c| call.margin < c.margin) {
509            self.closest = Some(call);
510        }
511        if call.margin <= NEAR_ROUTING * call.score.abs() {
512            self.near.push(NearCall::Routing(call));
513        }
514    }
515
516    /// Run `tokens` at the next positions, appending them to the state; returns the logits at the last one.
517    pub fn step(&mut self, tokens: &[u32]) -> R<Vec<f64>> {
518        let x = self.layers(tokens)?;
519        let last = x.last().ok_or(ReferenceError::NotYet("an empty step"))?;
520        Ok(self.head(std::slice::from_ref(last))?.remove(0))
521    }
522
523    /// Run `tokens` at the next positions, appending them to the state; returns the logits after every one of them —
524    /// the distributions a perplexity or a divergence over a text is taken from.
525    pub fn step_every(&mut self, tokens: &[u32]) -> R<Vec<Vec<f64>>> {
526        let x = self.layers(tokens)?;
527        self.head(&x)
528    }
529
530    /// The final hidden state of each of `tokens`, run at the next positions.
531    fn layers(&mut self, tokens: &[u32]) -> R<Vec<Vec<f64>>> {
532        let start = self.pos;
533        self.at = start + tokens.len().max(1) - 1;
534        let mut x: Vec<Vec<f64>> = Vec::with_capacity(tokens.len());
535        for &t in tokens {
536            let mut row = self.rows("token_embd.weight", t as usize, 1)?;
537            if let Some(scale) = self.spec.embedding_scale {
538                row.iter_mut().for_each(|v| *v *= scale);
539            }
540            x.push(row);
541        }
542        if let Some(hc) = self.spec.hyper {
543            let lanes = self.hyper_layers(tokens, &x, start, hc)?;
544            self.pos += tokens.len();
545            return Ok(lanes);
546        }
547        for l in 0..self.spec.layers.len() {
548            let layer = self.spec.layers[l].clone();
549            let xn = self.norm_rows(&x, &format!("blk.{l}.attn_norm.weight"))?;
550            let mut mixed = match &layer.mixer {
551                Mixer::Attention(a) => self.attention(l, a, &xn, start)?,
552                Mixer::GatedDelta(gd) => self.gated_delta(l, gd, &xn)?,
553                Mixer::Mla(m) => self.mla(l, m, &xn, start)?,
554            };
555            if layer.post_mixer_norm {
556                mixed = self.norm_rows(&mixed, &format!("blk.{l}.post_attention_norm.weight"))?;
557            }
558            add_rows(&mut x, &mixed);
559            let xn2 = self.norm_rows(&x, &format!("blk.{l}.{}.weight", self.spec.ffn_norm))?;
560            let mut ffn = self.ffn(l, &layer, &xn2)?;
561            if layer.post_ffn_norm {
562                ffn = self.norm_rows(&ffn, &format!("blk.{l}.post_ffw_norm.weight"))?;
563            }
564            add_rows(&mut x, &ffn);
565        }
566        self.pos += tokens.len();
567        Ok(x)
568    }
569
570    /// The logits of each final hidden state: the output norm, the LM head, the final softcap.
571    fn head(&mut self, x: &[Vec<f64>]) -> R<Vec<Vec<f64>>> {
572        let xf = match self.spec.hyper {
573            // Hyper-connections end in a last mix of the lanes, in place of the output norm.
574            Some(hc) => self.mix_lanes(x, "output_hc", hc, false)?.0,
575            None => self.norm_rows(x, "output_norm.weight")?,
576        };
577        let head = if self.spec.tied_output {
578            "token_embd.weight"
579        } else {
580            "output.weight"
581        };
582        let mut logits = self.project(head, &xf)?;
583        if let Some(cap) = self.spec.final_logit_softcap {
584            logits.iter_mut().flatten().for_each(|v| *v = cap * (*v / cap).tanh());
585        }
586        Ok(logits)
587    }
588
589    /// Greedy continuation: the prompt in one step, then `n` tokens one step each.
590    pub fn generate(&mut self, prompt: &[u32], n: usize) -> R<Vec<u32>> {
591        let mut logits = self.step(prompt)?;
592        let mut out = Vec::with_capacity(n);
593        for i in 0..n {
594            let t = argmax(&logits);
595            out.push(t);
596            if i + 1 < n {
597                logits = self.step(&[t])?;
598            }
599        }
600        Ok(out)
601    }
602
603    /// A whole tensor's values.
604    fn tensor(&mut self, name: &str) -> R<Vec<f64>> {
605        let (ty, _) = self.g.describe(name)?;
606        let raw = self.tensor_bytes(name)?;
607        let mut out = Vec::new();
608        ty.dequantize(&raw, &mut out);
609        Ok(out.into_iter().map(f64::from).collect())
610    }
611
612    /// Rows `[first, first + count)` of a tensor.
613    fn rows(&mut self, name: &str, first: usize, count: usize) -> R<Vec<f64>> {
614        let (ty, dims) = self.g.describe(name)?;
615        let raw = match self.cache.get(name) {
616            Some(b) => {
617                let row = ty.bytes_for(dims.first().copied().unwrap_or(1) as usize);
618                b[first * row..(first + count) * row].to_vec()
619            }
620            None => self.g.row_bytes(name, first, count)?,
621        };
622        let mut out = Vec::new();
623        ty.dequantize(&raw, &mut out);
624        Ok(out.into_iter().map(f64::from).collect())
625    }
626
627    fn norm_rows(&mut self, x: &[Vec<f64>], weight: &str) -> R<Vec<Vec<f64>>> {
628        let w = self.tensor(weight)?;
629        Ok(x.iter().map(|r| rms_norm(r, &w, self.spec.rms_eps)).collect())
630    }
631
632    /// `y = W·x` for every row of `xs`: the weight's bytes read once, each output row dequantized as ggml defines
633    /// its format and contracted in `f64`, the rows split across threads.
634    fn project(&mut self, name: &str, xs: &[Vec<f64>]) -> R<Vec<Vec<f64>>> {
635        let (ty, dims) = self.g.describe(name)?;
636        let [in_f, out_f] = dims[..] else {
637            return Err(ReferenceError::NotYet("a projection that is not a matrix"));
638        };
639        let (in_f, out_f) = (in_f as usize, out_f as usize);
640        let raw = self.tensor_bytes(name)?;
641        let xs = self.read_by(ty, xs);
642        Ok(products(&[Product { raw, from: 0, ty, in_f, out_f, xs }], self.threads).pop().expect("the product"))
643    }
644
645    /// The activations a projection by weights of type `ty` reads: quantized when the weights are.
646    fn read_by(&mut self, ty: GgmlType, xs: &[Vec<f64>]) -> Vec<Vec<f64>> {
647        match ty {
648            GgmlType::F32 | GgmlType::F16 | GgmlType::Bf16 => xs.to_vec(),
649            _ => xs.iter().map(|x| self.quantize_row(x)).collect(),
650        }
651    }
652
653    /// `row` as the cache keeps it: as computed, or each value rounded to `f32` and then to binary16, its near roundings
654    /// recorded (once a row, word [`CACHE_WORD`]) and the flipped ones taken to the other neighbour. A value's margin is
655    /// its distance from the half-way point in levels of its row's scale — the row's largest magnitude over 127, the
656    /// yardstick an int8 rounding of the row is measured by — since a run's `f32` arithmetic errs by a share of the
657    /// scale it computes at, whatever the value: a small value its rotation left after cancelling errs by more of its
658    /// own binary16 step than a large one.
659    fn kept(&mut self, row: Vec<f64>) -> Vec<f64> {
660        if self.kv == KvStorage::Exact {
661            return row;
662        }
663        let activation = row.iter().fold(0xcbf2_9ce4_8422_2325u64, |h, &a| {
664            (a as f32).to_bits().to_le_bytes().iter().fold(h, |h, &b| (h ^ u64::from(b)).wrapping_mul(0x0100_0000_01b3))
665        });
666        let position = self.at;
667        let level = row.iter().fold(0f64, |m, &v| m.max(f64::from((v as f32).abs()))) / 127.0;
668        let mut out = Vec::with_capacity(row.len());
669        for (element, &v) in row.iter().enumerate() {
670            let key = (activation, element, CACHE_WORD);
671            let (kept, distance, apart) = binary16(v, !self.flipped_roundings.is_empty() && self.flipped_roundings.contains(&key));
672            let margin = distance / level;
673            if margin <= NEAR_ROUNDING && self.near_roundings.insert(key) {
674                let step = apart / level;
675                self.near.push(NearCall::Rounding(RoundingCall { activation, element, word: CACHE_WORD, position, margin, step }));
676            }
677            out.push(kept);
678        }
679        out
680    }
681
682    /// One row quantized as [`quantize_activations`] does, its near roundings recorded (once an activation) and the
683    /// flipped ones taken the other way.
684    fn quantize_row(&mut self, x: &[f64]) -> Vec<f64> {
685        if self.activations == Activations::Exact {
686            return x.to_vec();
687        }
688        let activation = x.iter().fold(0xcbf2_9ce4_8422_2325u64, |h, &a| {
689            (a as f32).to_bits().to_le_bytes().iter().fold(h, |h, &b| (h ^ u64::from(b)).wrapping_mul(0x0100_0000_01b3))
690        });
691        let position = self.at;
692        let (flipped, recorded) = (&self.flipped_roundings, &mut self.near_roundings);
693        let mut near = Vec::new();
694        let out = quantize_deciding(x, self.activations, |element, word, q| {
695            let r = q.round_ties_even();
696            let margin = f64::from(((q - q.floor()) - 0.5).abs());
697            if margin <= NEAR_ROUNDING && recorded.insert((activation, element, word)) {
698                near.push(NearCall::Rounding(RoundingCall { activation, element, word, position, margin, step: 1.0 }));
699            }
700            match !flipped.is_empty() && flipped.contains(&(activation, element, word)) {
701                true if r > q => r - 1.0,
702                true => r + 1.0,
703                false => r,
704            }
705        });
706        self.near.extend(near);
707        out
708    }
709
710    fn attention(&mut self, l: usize, a: &Attention, xn: &[Vec<f64>], start: usize) -> R<Vec<Vec<f64>>> {
711        let (hd, vd) = (a.head_dim, a.value_dim);
712        let (aq, akv, avd) = (a.heads * hd, a.kv_heads * hd, a.kv_heads * vd);
713        // A fused projection holds the queries, keys and values one after another in each output row.
714        let fused = if a.fused_qkv {
715            let mut qkv = self.project(&format!("blk.{l}.attn_qkv.weight"), xn)?;
716            if a.bias {
717                let b = self.tensor(&format!("blk.{l}.attn_qkv.bias"))?;
718                add_bias(&mut qkv, &b);
719            }
720            Some(qkv)
721        } else {
722            None
723        };
724        let part = |rows: &Option<Vec<Vec<f64>>>, from: usize, n: usize| -> Option<Vec<Vec<f64>>> {
725            rows.as_ref().map(|r| r.iter().map(|row| row[from..from + n].to_vec()).collect())
726        };
727        let projected = match part(&fused, 0, aq) {
728            Some(q) => q,
729            None => self.project(&format!("blk.{l}.attn_q.weight"), xn)?,
730        };
731        // With an output gate the query projection holds, per head, the head's queries then its gate.
732        let (mut q, gate): (Vec<Vec<f64>>, Option<Vec<Vec<f64>>>) = if a.output_gate {
733            let part = |r: &Vec<f64>, at: usize| -> Vec<f64> {
734                (0..a.heads).flat_map(|h| r[h * 2 * hd + at..h * 2 * hd + at + hd].to_vec()).collect()
735            };
736            (projected.iter().map(|r| part(r, 0)).collect(), Some(projected.iter().map(|r| part(r, hd)).collect()))
737        } else {
738            (projected, None)
739        };
740        let (mut k, mut v) = match (part(&fused, aq, akv), part(&fused, aq + akv, avd)) {
741            (Some(k), Some(v)) => (k, v),
742            _ => (
743                self.project(&format!("blk.{l}.attn_k.weight"), xn)?,
744                self.project(&format!("blk.{l}.attn_v.weight"), xn)?,
745            ),
746        };
747        if a.bias && !a.fused_qkv {
748            for (rows, which) in [(&mut q, "attn_q"), (&mut k, "attn_k"), (&mut v, "attn_v")] {
749                let b = self.tensor(&format!("blk.{l}.{which}.bias"))?;
750                add_bias(rows, &b);
751            }
752        }
753        let (qn, kn) = if a.qk_norm {
754            let qw = self.tensor(&format!("blk.{l}.attn_q_norm.weight"))?;
755            let kw = self.tensor(&format!("blk.{l}.attn_k_norm.weight"))?;
756            (Some(qw), Some(kw))
757        } else {
758            (None, None)
759        };
760        let factors = match a.rope.as_ref().map(|r| &r.scaling) {
761            Some(RopeScaling::Factors) => Some(self.tensor("rope_freqs.weight")?),
762            _ => None,
763        };
764        let sinks = if a.sinks { Some(self.tensor(&format!("blk.{l}.attn_sinks.weight"))?) } else { None };
765        // QSA's index queries, normed and rotated head by head, and this step's index keys (transformers
766        // `Qwen4ExpTextQSAIndexer`, llama.cpp `qwen4exp`).
767        let index = match self.spec.indexer.clone() {
768            Some(ix) if ix.layers.contains(&l) => {
769                let iq = self.project(&format!("blk.{l}.indexer.q_proj.weight"), xn)?;
770                let ik = self.project(&format!("blk.{l}.indexer.k_proj.weight"), xn)?;
771                let qw = self.tensor(&format!("blk.{l}.indexer.q_norm.weight"))?;
772                let kw = self.tensor(&format!("blk.{l}.indexer.k_norm.weight"))?;
773                let eps = self.spec.rms_eps;
774                let queries: Vec<Vec<Vec<f64>>> = iq
775                    .iter()
776                    .enumerate()
777                    .map(|(i, row)| {
778                        (0..ix.heads)
779                            .map(|h| {
780                                let mut q = rms_norm(&row[h * ix.head_dim..(h + 1) * ix.head_dim], &qw, eps);
781                                if let Some(r) = &a.rope {
782                                    rotate(&mut q, start + i, r, factors.as_deref());
783                                }
784                                q
785                            })
786                            .collect()
787                    })
788                    .collect();
789                Some((ix, queries, ik, kw))
790            }
791            _ => None,
792        };
793        // Llama 4's weightless norm follows the rotation (`Llama4TextL2Norm`), and its temperature follows the norm.
794        let ones = vec![1.0; hd];
795        // A norm across every head at once (MiniMax-M2) runs over the whole projection, before the rotation.
796        let (whole, per_head) = if a.qk_norm_whole { ((qn, kn), (None, None)) } else { ((None, None), (qn, kn)) };
797        let (qn, kn) = per_head;
798        for (i, (qr, kr)) in q.iter_mut().zip(k.iter_mut()).enumerate() {
799            let pos = start + i;
800            if let (Some(qw), Some(kw)) = &whole {
801                *qr = rms_norm(qr, qw, self.spec.rms_eps);
802                *kr = rms_norm(kr, kw, self.spec.rms_eps);
803            }
804            for h in 0..a.heads {
805                let s = &mut qr[h * hd..(h + 1) * hd];
806                if let Some(w) = &qn {
807                    let n = rms_norm(s, w, self.spec.rms_eps);
808                    s.copy_from_slice(&n);
809                }
810                if let Some(r) = &a.rope {
811                    rotate(s, pos, r, factors.as_deref());
812                }
813                if a.qk_unit_norm {
814                    let n = rms_norm(s, &ones, self.spec.rms_eps);
815                    s.copy_from_slice(&n);
816                }
817                if let Some(t) = a.temperature {
818                    let f = t.at(pos);
819                    s.iter_mut().for_each(|v| *v *= f);
820                }
821            }
822            for h in 0..a.kv_heads {
823                let s = &mut kr[h * hd..(h + 1) * hd];
824                if let Some(w) = &kn {
825                    let n = rms_norm(s, w, self.spec.rms_eps);
826                    s.copy_from_slice(&n);
827                }
828                if let Some(r) = &a.rope {
829                    rotate(s, pos, r, factors.as_deref());
830                }
831                if a.qk_unit_norm {
832                    let n = rms_norm(s, &ones, self.spec.rms_eps);
833                    s.copy_from_slice(&n);
834                }
835            }
836        }
837        let k: Vec<Vec<f64>> = k.into_iter().map(|r| self.kept(r)).collect();
838        let v: Vec<Vec<f64>> = v.into_iter().map(|r| self.kept(r)).collect();
839        let eps = self.spec.rms_eps;
840        let LayerState::Attention { k: kc, v: vc, ik: ikc } = &mut self.states[l] else {
841            unreachable!("an attention layer holds an attention cache")
842        };
843        kc.extend(k);
844        vc.extend(v);
845        let (kc, vc) = (&*kc, &*vc);
846        // Each query's positions: QSA's selection where the model indexes, else every visible one.
847        let kept: Option<Vec<Vec<usize>>> = match index {
848            Some((ix, queries, keys, kw)) => {
849                ikc.extend(keys);
850                let ikc = &*ikc;
851                Some(
852                    queries
853                        .iter()
854                        .enumerate()
855                        .map(|(i, q)| qsa_positions(&ix, q, ikc, &kw, a.rope.as_ref(), factors.as_deref(), eps, start + i))
856                        .collect(),
857                )
858            }
859            None => None,
860        };
861        let group = a.heads / a.kv_heads;
862        let mut out = vec![vec![0f64; a.heads * vd]; xn.len()];
863        for (i, o) in out.iter_mut().enumerate() {
864            let pos = start + i;
865            // A sliding window hides every key `window` or more positions back (llama.cpp's standard SWA mask); a chunk keeps
866            // the keys of the query's own chunk (Llama 4's chunked mask, `q / C == k / C`).
867            let first = a.window.map_or(0, |w| w.first(pos + 1) - 1);
868            let positions: Vec<usize> = match &kept {
869                Some(kept) => kept[i].clone(),
870                None => (first..=pos).collect(),
871            };
872            for h in 0..a.heads {
873                let g = h / group;
874                let qh = &q[i][h * hd..(h + 1) * hd];
875                let mut scores: Vec<f64> = positions
876                    .iter()
877                    .map(|&j| {
878                        let kj = &kc[j][g * hd..(g + 1) * hd];
879                        let s = qh.iter().zip(kj).map(|(x, y)| x * y).sum::<f64>() * a.scale;
880                        match a.softcap {
881                            Some(cap) => cap * (s / cap).tanh(),
882                            None => s,
883                        }
884                    })
885                    .collect();
886                match &sinks {
887                    // A sink joins the softmax's denominator and takes no value (ggml's `soft_max_ext` with sinks).
888                    Some(sk) => {
889                        let m = scores.iter().cloned().fold(sk[h], f64::max);
890                        let total = scores.iter().map(|s| (s - m).exp()).sum::<f64>() + (sk[h] - m).exp();
891                        scores.iter_mut().for_each(|s| *s = (*s - m).exp() / total);
892                    }
893                    None => softmax(&mut scores),
894                }
895                let oh = &mut o[h * vd..(h + 1) * vd];
896                for (&j, w) in positions.iter().zip(&scores) {
897                    for (e, slot) in oh.iter_mut().enumerate() {
898                        *slot += w * vc[j][g * vd + e];
899                    }
900                }
901            }
902        }
903        if let Some(gate) = gate {
904            for (o, g) in out.iter_mut().zip(&gate) {
905                for (v, &g) in o.iter_mut().zip(g) {
906                    *v *= sigmoid(g);
907                }
908            }
909        }
910        let mut projected = self.project(&format!("blk.{l}.attn_output.weight"), &out)?;
911        if a.output_bias {
912            let b = self.tensor(&format!("blk.{l}.attn_output.bias"))?;
913            add_bias(&mut projected, &b);
914        }
915        Ok(projected)
916    }
917
918    /// Multi-head latent attention (llama.cpp `models/deepseek2.cpp`), computed absorbed: each position's cache row is
919    /// its RMS-normed `kv_lora_rank` latent and the shared rotated key; each head's unrotated query reaches the latent's
920    /// space through the key half of the latent's expansion, attends every cached row with its rotated part at the
921    /// model's scale, takes the rows' latents as its values, and leaves through the value half of the expansion. The
922    /// halves read their activations unquantized under every precision, so these are the scores and values the
923    /// expanded attention takes — each cached latent through both halves, each head attending its own keys and values —
924    /// and a lane computes either.
925    fn mla(&mut self, l: usize, m: &Mla, xn: &[Vec<f64>], start: usize) -> R<Vec<Vec<f64>>> {
926        let (h, nope, rope, vd, lora) = (m.heads, m.qk_nope, m.qk_rope, m.v_dim, m.kv_lora_rank);
927        let (qk, kw) = (nope + rope, lora + rope);
928        let q = match m.q_lora_rank {
929            None => self.project(&format!("blk.{l}.attn_q.weight"), xn)?,
930            Some(_) => {
931                let qa = self.project(&format!("blk.{l}.attn_q_a.weight"), xn)?;
932                let qa = self.norm_rows(&qa, &format!("blk.{l}.attn_q_a_norm.weight"))?;
933                self.project(&format!("blk.{l}.attn_q_b.weight"), &qa)?
934            }
935        };
936        let kva = self.project(&format!("blk.{l}.attn_kv_a_mqa.weight"), xn)?;
937        let latent: Vec<Vec<f64>> = kva.iter().map(|r| r[..lora].to_vec()).collect();
938        let latent = self.norm_rows(&latent, &format!("blk.{l}.attn_kv_a_norm.weight"))?;
939        // The expansion's halves, each head's block of rows: `(tensor, first row of head 0, rows a head)`, its rows the
940        // head's outputs or its inputs.
941        let (key_half, value_half) = if m.kv_b_split {
942            ((format!("blk.{l}.attn_k_b.weight"), 0, lora, true), (format!("blk.{l}.attn_v_b.weight"), 0, vd, true))
943        } else {
944            let kv = format!("blk.{l}.attn_kv_b.weight");
945            ((kv.clone(), 0, nope, false), (kv, nope, vd, true))
946        };
947        let head_stride = |half: &(String, usize, usize, bool)| if m.kv_b_split { half.2 } else { nope + vd };
948        let (ks, vs) = (head_stride(&key_half), head_stride(&value_half));
949        let mut out = Vec::with_capacity(xn.len());
950        for (i, (qr, (kr, c))) in q.iter().zip(kva.iter().zip(&latent)).enumerate() {
951            let pos = start + i;
952            let mut pe = kr[lora..kw].to_vec();
953            rotate(&mut pe, pos, &m.rope, None);
954            let row = self.kept(c.iter().chain(&pe).copied().collect());
955            let LayerState::Attention { k: cache, .. } = &mut self.states[l] else {
956                unreachable!("a latent-attention layer holds an attention cache")
957            };
958            cache.push(row);
959            // Each head's unrotated query, absorbed.
960            let qn: Vec<f64> = (0..h).flat_map(|hh| qr[hh * qk..hh * qk + nope].to_vec()).collect();
961            let mut ol = vec![0f64; h * lora];
962            for hh in 0..h {
963                let (name, first, count, rows_out) = &key_half;
964                let x = &qn[hh * nope..(hh + 1) * nope];
965                let absorbed = self.head_product(name, hh * ks + first, *count, *rows_out, x)?;
966                let mut qe = qr[hh * qk + nope..(hh + 1) * qk].to_vec();
967                rotate(&mut qe, pos, &m.rope, None);
968                let LayerState::Attention { k: cache, .. } = &self.states[l] else { unreachable!() };
969                let mut scores: Vec<f64> = cache
970                    .iter()
971                    .map(|row| {
972                        let s = absorbed.iter().zip(&row[..lora]).map(|(a, b)| a * b).sum::<f64>()
973                            + qe.iter().zip(&row[lora..]).map(|(a, b)| a * b).sum::<f64>();
974                        s * m.scale
975                    })
976                    .collect();
977                softmax(&mut scores);
978                for (w, row) in scores.iter().zip(cache) {
979                    for (slot, v) in ol[hh * lora..(hh + 1) * lora].iter_mut().zip(&row[..lora]) {
980                        *slot += w * v;
981                    }
982                }
983            }
984            // Each head's attended latent through the value half.
985            let mut ct = Vec::with_capacity(h * vd);
986            for hh in 0..h {
987                let (name, first, count, rows_out) = &value_half;
988                ct.extend(self.head_product(name, hh * vs + first, *count, *rows_out, &ol[hh * lora..(hh + 1) * lora])?);
989            }
990            out.push(ct);
991        }
992        self.project(&format!("blk.{l}.attn_output.weight"), &out)
993    }
994
995    /// One head's product with its block of `count` rows of `name` from `first`: each row dotted with `x` when the rows
996    /// are the head's outputs, the rows weighed by `x` and summed when they are its inputs — in `f64`.
997    fn head_product(&mut self, name: &str, first: usize, count: usize, rows_out: bool, x: &[f64]) -> R<Vec<f64>> {
998        let w = self.rows(name, first, count)?;
999        let width = w.len() / count.max(1);
1000        Ok(if rows_out {
1001            w.chunks(width).map(|row| row.iter().zip(x).map(|(a, b)| a * b).sum()).collect()
1002        } else {
1003            let mut y = vec![0f64; width];
1004            for (row, xi) in w.chunks(width).zip(x) {
1005                for (slot, v) in y.iter_mut().zip(row) {
1006                    *slot += xi * v;
1007                }
1008            }
1009            y
1010        })
1011    }
1012
1013    /// One Gated DeltaNet block over the rows of `xn` in order (llama.cpp `models/qwen35.cpp`
1014    /// `build_layer_attn_linear`): the fused `q|k|v` projection through a depthwise causal convolution and SiLU, q
1015    /// and k L2-normalized per key head, then per value head the delta rule — decay the memory by
1016    /// `exp(softplus(α + dt)·a)`, write `β·(v − decayed memory·k)` along `k`, read with `q/√head_dim` — and the
1017    /// read normalized and gated by `silu(z)`.
1018    /// The per-layer embedding's fresh state: `ngram - 1` ends of document before the first token, and a convolution
1019    /// that has read only zeros.
1020    fn fresh_ple(spec: &ModelSpec) -> (Vec<u32>, Vec<Vec<f64>>) {
1021        match (&spec.ple, spec.hyper) {
1022            (Some(p), Some(hc)) => {
1023                (vec![p.eos; p.ngram - 1], vec![vec![0.0; hc.lanes * spec.d]; (p.conv_taps - 1) * p.ngram])
1024            }
1025            _ => (Vec::new(), Vec::new()),
1026        }
1027    }
1028
1029    /// The stack over hyper-connection lanes (transformers `Qwen4ExpTextDecoderLayer`): `lanes` copies of each
1030    /// embedding; at its layer the per-layer embedding joins the lanes; each sublayer reads the lanes' mix and its output
1031    /// joins every lane, weighted. Each position's lanes, `lanes·d` wide.
1032    fn hyper_layers(&mut self, tokens: &[u32], x: &[Vec<f64>], start: usize, hc: HyperConnections) -> R<Vec<Vec<f64>>> {
1033        let mut h: Vec<Vec<f64>> = x.iter().map(|r| r.repeat(hc.lanes)).collect();
1034        for l in 0..self.spec.layers.len() {
1035            let layer = self.spec.layers[l].clone();
1036            if self.spec.ple.as_ref().is_some_and(|p| p.layer == l) {
1037                let added = self.ple(l, tokens, &h, hc)?;
1038                add_rows(&mut h, &added);
1039            }
1040            let (input, inject) = self.mix_lanes(&h, &format!("blk.{l}.hc_attn"), hc, true)?;
1041            let out = match &layer.mixer {
1042                Mixer::Attention(a) => self.attention(l, a, &input, start)?,
1043                Mixer::GatedDelta(gd) => self.gated_delta(l, gd, &input)?,
1044                Mixer::Mla(m) => self.mla(l, m, &input, start)?,
1045            };
1046            inject_lanes(&mut h, &out, &inject, self.spec.d);
1047            let (input, inject) = self.mix_lanes(&h, &format!("blk.{l}.hc_ffn"), hc, true)?;
1048            let out = self.ffn(l, &layer, &input)?;
1049            inject_lanes(&mut h, &out, &inject, self.spec.d);
1050        }
1051        Ok(h)
1052    }
1053
1054    /// A hyper-connection's mix of each position's lanes (transformers `Qwen4ExpTextGatedResidual`): the lanes normed
1055    /// each on its own (`<stem>_norm`, one weight across all of them), weighted by `σ(up·silu(down·x̂ / lanes))` and
1056    /// averaged into one input; with `inject`, each lane's share of the sublayer's output, `2σ(inject·x̂ / lanes)`.
1057    fn mix_lanes(&mut self, h: &[Vec<f64>], stem: &str, hc: HyperConnections, inject: bool) -> R<(Vec<Vec<f64>>, Vec<Vec<f64>>)> {
1058        let (d, lanes) = (self.spec.d, hc.lanes as f64);
1059        let norm = self.tensor(&format!("{stem}_norm.weight"))?;
1060        let normed: Vec<Vec<f64>> = h.iter().map(|r| lane_norm(r, &norm, d, self.spec.rms_eps)).collect();
1061        let down = self.project(&format!("{stem}_down.weight"), &normed)?;
1062        let mid: Vec<Vec<f64>> = down.iter().map(|r| r.iter().map(|v| silu(v / lanes)).collect()).collect();
1063        let up = self.project(&format!("{stem}_up.weight"), &mid)?;
1064        let inputs = normed
1065            .iter()
1066            .zip(&up)
1067            .map(|(x, w)| (0..d).map(|j| (0..hc.lanes).map(|s| sigmoid(w[s * d + j]) * x[s * d + j]).sum::<f64>() / lanes).collect())
1068            .collect();
1069        let shares = if inject {
1070            let raw = self.project(&format!("{stem}_inject.weight"), &normed)?;
1071            raw.iter().map(|r| r.iter().map(|v| 2.0 * sigmoid(v / lanes)).collect()).collect()
1072        } else {
1073            Vec::new()
1074        };
1075        Ok((inputs, shares))
1076    }
1077
1078    /// The per-layer embedding of `tokens` (transformers `Qwen4ExpTextPLELayer`), added to layer `l`'s lanes `h`: each
1079    /// position's n-grams hashed into the table, the rows a value and a key for each lane, the lane's normed state gating
1080    /// the value, and the dilated depthwise convolution of the normed gated values after it.
1081    fn ple(&mut self, l: usize, tokens: &[u32], h: &[Vec<f64>], hc: HyperConnections) -> R<Vec<Vec<f64>>> {
1082        let p = self.spec.ple.clone().expect("a per-layer embedding");
1083        let (d, lanes) = (self.spec.d, hc.lanes);
1084        let width = lanes * d;
1085        let mut rows = Vec::with_capacity(tokens.len());
1086        for &t in tokens {
1087            self.ple_tokens.push(t);
1088            let w = &self.ple_tokens[self.ple_tokens.len() - p.ngram..];
1089            let mut emb = Vec::with_capacity((p.ngram - 1) * p.heads_per_ngram * p.head_dim);
1090            for id in ngram_rows(&p, w) {
1091                emb.extend(self.rows("per_layer_token_embd.weight", id as usize, 1)?);
1092            }
1093            rows.push(emb);
1094        }
1095        let key = self.project(&format!("blk.{l}.ple_key.weight"), &rows)?;
1096        let value = self.project(&format!("blk.{l}.ple_value.weight"), &rows)?;
1097        let eps = self.spec.rms_eps;
1098        let (nk, nq, nc) = (
1099            self.tensor(&format!("blk.{l}.ple_norm_key.weight"))?,
1100            self.tensor(&format!("blk.{l}.ple_norm_query.weight"))?,
1101            self.tensor(&format!("blk.{l}.ple_norm_conv.weight"))?,
1102        );
1103        let kernel = self.tensor(&format!("blk.{l}.ple_conv1d.weight"))?;
1104        let mut out = Vec::with_capacity(tokens.len());
1105        for (i, x) in h.iter().enumerate() {
1106            let key = lane_norm(&key[i], &nk, d, eps);
1107            let query = lane_norm(x, &nq, d, eps);
1108            let mut gated = vec![0.0; width];
1109            for s in 0..lanes {
1110                let g = (0..d).map(|j| key[s * d + j] * query[s * d + j]).sum::<f64>() / (d as f64).sqrt();
1111                let sign = if g > 0.0 { 1.0 } else if g < 0.0 { -1.0 } else { 0.0 };
1112                let gate = sigmoid(sign * g.abs().max(1e-6).sqrt());
1113                for j in 0..d {
1114                    gated[s * d + j] = gate * value[i][j];
1115                }
1116            }
1117            let normed = lane_norm(&gated, &nc, d, eps);
1118            // Tap `k` of `taps` reads the normed values `(taps - 1 - k)·ngram` positions back.
1119            self.ple_conv.push(normed);
1120            let history = &self.ple_conv;
1121            let last = history.len() - 1;
1122            let row: Vec<f64> = (0..width)
1123                .map(|c| {
1124                    let conv = (0..p.conv_taps)
1125                        .map(|k| kernel[c * p.conv_taps + k] * history[last - (p.conv_taps - 1 - k) * p.ngram][c])
1126                        .sum::<f64>();
1127                    gated[c] + silu(conv)
1128                })
1129                .collect();
1130            self.ple_conv.remove(0);
1131            out.push(row);
1132        }
1133        Ok(out)
1134    }
1135
1136    fn gated_delta(&mut self, l: usize, gd: &GatedDelta, xn: &[Vec<f64>]) -> R<Vec<Vec<f64>>> {
1137        let (nk, nv, hd, taps) = (gd.k_heads, gd.v_heads, gd.head_dim, gd.conv_taps);
1138        let (qk, vw) = (nk * hd, nv * hd);
1139        let channels = 2 * qk + vw;
1140        let qkv = self.project(&format!("blk.{l}.attn_qkv.weight"), xn)?;
1141        let z = self.project(&format!("blk.{l}.attn_gate.weight"), xn)?;
1142        let beta = self.project(&format!("blk.{l}.ssm_beta.weight"), xn)?;
1143        let alpha = self.project(&format!("blk.{l}.ssm_alpha.weight"), xn)?;
1144        let kernel = self.tensor(&format!("blk.{l}.ssm_conv1d.weight"))?;
1145        let dt = self.tensor(&format!("blk.{l}.ssm_dt.bias"))?;
1146        let a = self.tensor(&format!("blk.{l}.ssm_a"))?;
1147        let norm = self.tensor(&format!("blk.{l}.ssm_norm.weight"))?;
1148        let eps = self.spec.rms_eps;
1149        let keep_state = self.state;
1150        let LayerState::Delta { conv, memory } = &mut self.states[l] else {
1151            unreachable!("a gated-delta layer holds a recurrent state")
1152        };
1153        let l2 = |x: &[f64]| -> Vec<f64> {
1154            let den = (x.iter().map(|v| v * v).sum::<f64>() + eps).sqrt();
1155            x.iter().map(|v| v / den).collect()
1156        };
1157        let mut reads = Vec::with_capacity(xn.len());
1158        for t in 0..xn.len() {
1159            let c: Vec<f64> = (0..channels)
1160                .map(|ch| {
1161                    let older = conv.iter().enumerate().map(|(j, row)| row[ch] * kernel[ch * taps + j]).sum::<f64>();
1162                    silu(older + qkv[t][ch] * kernel[ch * taps + taps - 1])
1163                })
1164                .collect();
1165            if taps > 1 {
1166                conv.remove(0);
1167                conv.push(qkv[t].clone());
1168            }
1169            let q: Vec<f64> = (0..nk).flat_map(|h| l2(&c[h * hd..(h + 1) * hd])).collect();
1170            let k: Vec<f64> = (0..nk).flat_map(|h| l2(&c[qk + h * hd..qk + (h + 1) * hd])).collect();
1171            let v = &c[2 * qk..];
1172            let mut read = vec![0.0; vw];
1173            let scale = 1.0 / (hd as f64).sqrt();
1174            for h in 0..nv {
1175                let (kq, kk) = (&q[(h % nk) * hd..(h % nk + 1) * hd], &k[(h % nk) * hd..(h % nk + 1) * hd]);
1176                let decay = (softplus(alpha[t][h] + dt[h]) * a[h]).exp();
1177                let b = sigmoid(beta[t][h]);
1178                let s = &mut memory[h * hd * hd..(h + 1) * hd * hd];
1179                for r in 0..hd {
1180                    let row = &mut s[r * hd..(r + 1) * hd];
1181                    let u = decay * row.iter().zip(kk).map(|(m, k)| m * k).sum::<f64>();
1182                    let coef = b * (v[h * hd + r] - u);
1183                    for (m, &kc) in row.iter_mut().zip(kk) {
1184                        *m = decay * *m + coef * kc;
1185                    }
1186                }
1187                let o: Vec<f64> =
1188                    (0..hd).map(|r| s[r * hd..(r + 1) * hd].iter().zip(kq).map(|(m, q)| m * q).sum::<f64>() * scale).collect();
1189                for m in s.iter_mut() {
1190                    *m = keep_state.keep(*m);
1191                }
1192                let on = rms_norm(&o, &norm, eps);
1193                for r in 0..hd {
1194                    let g = z[t][h * hd + r];
1195                    read[h * hd + r] = on[r]
1196                        * match gd.gate {
1197                            GateActivation::Silu => silu(g),
1198                            GateActivation::Sigmoid => sigmoid(g),
1199                        };
1200                }
1201            }
1202            reads.push(read);
1203        }
1204        self.project(&format!("blk.{l}.ssm_out.weight"), &reads)
1205    }
1206
1207    fn ffn(&mut self, l: usize, layer: &Layer, xn: &[Vec<f64>]) -> R<Vec<Vec<f64>>> {
1208        match &layer.ffn {
1209            Ffn::Dense { act, .. } => {
1210                let g = self.project(&format!("blk.{l}.ffn_gate.weight"), xn)?;
1211                let u = self.project(&format!("blk.{l}.ffn_up.weight"), xn)?;
1212                let h: Vec<Vec<f64>> = g.iter().zip(&u).map(|(g, u)| gated(act, g, u)).collect();
1213                self.project(&format!("blk.{l}.ffn_down.weight"), &h)
1214            }
1215            Ffn::Moe(m) => self.moe(l, m, xn),
1216        }
1217    }
1218
1219    /// A mixture of experts as llama.cpp's `build_moe_ffn` computes it: router logits (plus a router bias), turned
1220    /// into probabilities by the spec's gating, the top `k` chosen, their weights renormalized (the sum clamped as
1221    /// llama.cpp clamps it) and scaled, each chosen expert's gated FFN (with its biases) summed by its weight.
1222    fn moe(&mut self, l: usize, m: &Moe, xn: &[Vec<f64>]) -> R<Vec<Vec<f64>>> {
1223        // A router ranks scores largest first, a NaN below every number and two NaNs alike: the chip's order, so a NaN
1224        // score is chosen only when no number remains.
1225        fn descending(a: f64, b: f64) -> std::cmp::Ordering {
1226            match (a.is_nan(), b.is_nan()) {
1227                (false, false) => b.partial_cmp(&a).expect("two numbers compare"),
1228                (true, true) => std::cmp::Ordering::Equal,
1229                (true, false) => std::cmp::Ordering::Greater,
1230                (false, true) => std::cmp::Ordering::Less,
1231            }
1232        }
1233        let selection_bias = match m.gating {
1234            Gating::Sigmoid { bias: true } => Some(self.tensor(&format!("blk.{l}.exp_probs_b.bias"))?),
1235            _ => None,
1236        };
1237        let mut logits = self.project(&format!("blk.{l}.ffn_gate_inp.weight"), xn)?;
1238        let bias = |me: &mut Self, which: &str| -> R<Option<Vec<f64>>> {
1239            if m.biases {
1240                Ok(Some(me.tensor(&format!("blk.{l}.{which}.bias"))?))
1241            } else {
1242                Ok(None)
1243            }
1244        };
1245        if let Some(b) = bias(self, "ffn_gate_inp")? {
1246            add_bias(&mut logits, &b);
1247        }
1248        let (bg, bu, bd) = (bias(self, "ffn_gate_exps")?, bias(self, "ffn_up_exps")?, bias(self, "ffn_down_exps")?);
1249        let d = self.spec.d;
1250        let f = m.expert_dff;
1251        // Each row's experts and their weights, in the order the row sums them.
1252        let mut routes: Vec<Vec<(usize, f64)>> = Vec::with_capacity(xn.len());
1253        for (t, lg) in logits.iter().enumerate() {
1254            let mut p = lg.clone();
1255            match m.gating {
1256                Gating::Softmax => softmax(&mut p),
1257                Gating::Sigmoid { .. } | Gating::SigmoidScaledInput => p.iter_mut().for_each(|v| *v = sigmoid(*v)),
1258                Gating::SoftmaxOfTopK => {}
1259            }
1260            // Selection may read biased scores; the weights read the unbiased ones.
1261            let mut sel: Vec<f64> = match &selection_bias {
1262                Some(b) => p.iter().zip(b).map(|(v, b)| v + b).collect(),
1263                None => p.clone(),
1264            };
1265            if let Some((groups, used)) = m.groups {
1266                let per = p.len() / groups;
1267                let score = |g: usize| {
1268                    let mut v: Vec<f64> = sel[g * per..(g + 1) * per].to_vec();
1269                    v.sort_by(|a, b| descending(*a, *b));
1270                    v[0] + v.get(1).copied().unwrap_or(0.0)
1271                };
1272                let mut ranked: Vec<usize> = (0..groups).collect();
1273                ranked.sort_by(|&a, &b| descending(score(a), score(b)).then(a.cmp(&b)));
1274                if used < groups {
1275                    let (kept, dropped) = (score(ranked[used - 1]), score(ranked[used]));
1276                    self.routed(l, self.pos + t, kept, dropped);
1277                }
1278                for &g in &ranked[used..] {
1279                    sel[g * per..(g + 1) * per].iter_mut().for_each(|v| *v = f64::NEG_INFINITY);
1280                }
1281            }
1282            let mut order: Vec<usize> = (0..p.len()).collect();
1283            order.sort_by(|&a, &b| descending(sel[a], sel[b]).then(a.cmp(&b)));
1284            if let Some(&passed) = order.get(m.top_k) {
1285                self.routed(l, self.pos + t, sel[order[m.top_k - 1]], sel[passed]);
1286                if self.flipped_routings.contains(&(l, self.pos + t)) {
1287                    order.swap(m.top_k - 1, m.top_k);
1288                }
1289            }
1290            let chosen = &order[..m.top_k];
1291            let mut w: Vec<f64> = chosen.iter().map(|&e| p[e]).collect();
1292            if matches!(m.gating, Gating::SoftmaxOfTopK) {
1293                softmax(&mut w);
1294            }
1295            if m.norm_top_k {
1296                let total = w.iter().sum::<f64>().max(6.103515625e-5);
1297                w.iter_mut().for_each(|v| *v /= total);
1298            }
1299            if m.weights_scale != 0.0 && m.weights_scale != 1.0 {
1300                w.iter_mut().for_each(|v| *v *= m.weights_scale);
1301            }
1302            routes.push(chosen.iter().copied().zip(w).collect());
1303        }
1304        // Every expert runs once, on all the rows that chose it: its weights are read once for the block.
1305        let mut readers: BTreeMap<usize, Vec<usize>> = BTreeMap::new();
1306        for (t, route) in routes.iter().enumerate() {
1307            for &(e, _) in route {
1308                readers.entry(e).or_default().push(t);
1309            }
1310        }
1311        // A gating that scales the input weighs each row's input to an expert, not the expert's output.
1312        let scaled_input = m.gating == Gating::SigmoidScaledInput;
1313        let weight = |t: usize, e: usize| routes[t].iter().find(|(x, _)| *x == e).map(|(_, w)| *w).expect("a chosen expert");
1314        // Every expert's gate and up in one pass over the threads, then every expert's down in another.
1315        let mut ups = Vec::new();
1316        for (&e, rows) in &readers {
1317            let xs: Vec<Vec<f64>> = rows
1318                .iter()
1319                .map(|&t| if scaled_input { xn[t].iter().map(|v| v * weight(t, e)).collect() } else { xn[t].clone() })
1320                .collect();
1321            ups.push(self.expert(l, "ffn_gate_exps", e, f, &xs)?);
1322            ups.push(self.expert(l, "ffn_up_exps", e, f, &xs)?);
1323        }
1324        let gu = products(&ups, self.threads);
1325        let mut downs = Vec::new();
1326        for ((&e, _), pair) in readers.iter().zip(gu.chunks_exact(2)) {
1327            let (mut g, mut u) = (pair[0].clone(), pair[1].clone());
1328            if let (Some(bg), Some(bu)) = (&bg, &bu) {
1329                g.iter_mut().for_each(|g| g.iter_mut().zip(&bg[e * f..(e + 1) * f]).for_each(|(v, b)| *v += b));
1330                u.iter_mut().for_each(|u| u.iter_mut().zip(&bu[e * f..(e + 1) * f]).for_each(|(v, b)| *v += b));
1331            }
1332            let h: Vec<Vec<f64>> = g.iter().zip(&u).map(|(g, u)| gated(&m.act, g, u)).collect();
1333            downs.push(self.expert(l, "ffn_down_exps", e, d, &h)?);
1334        }
1335        let mut ys: HashMap<(usize, usize), Vec<f64>> = HashMap::new();
1336        for ((&e, rows), y) in readers.iter().zip(products(&downs, self.threads)) {
1337            for (&t, mut y) in rows.iter().zip(y) {
1338                if let Some(bd) = &bd {
1339                    y.iter_mut().zip(&bd[e * d..(e + 1) * d]).for_each(|(v, b)| *v += b);
1340                }
1341                ys.insert((t, e), y);
1342            }
1343        }
1344        let mut out = vec![vec![0f64; d]; xn.len()];
1345        for (t, route) in routes.iter().enumerate() {
1346            for &(e, we) in route {
1347                let we = if scaled_input { 1.0 } else { we };
1348                for (slot, v) in out[t].iter_mut().zip(&ys[&(t, e)]) {
1349                    *slot += we * v;
1350                }
1351            }
1352        }
1353        if m.shared_experts > 0 {
1354            let g = self.project(&format!("blk.{l}.ffn_gate_shexp.weight"), xn)?;
1355            let u = self.project(&format!("blk.{l}.ffn_up_shexp.weight"), xn)?;
1356            let h: Vec<Vec<f64>> = g.iter().zip(&u).map(|(g, u)| gated(&m.act, g, u)).collect();
1357            let mut y = self.project(&format!("blk.{l}.ffn_down_shexp.weight"), &h)?;
1358            // Qwen's shared experts are scaled by `σ(x·g)`, the gate a vector over the input.
1359            if m.shared_gate {
1360                let g = self.tensor(&format!("blk.{l}.ffn_gate_inp_shexp.weight"))?;
1361                for (row, x) in y.iter_mut().zip(xn) {
1362                    let gate = sigmoid(x.iter().zip(&g).map(|(a, b)| a * b).sum());
1363                    row.iter_mut().for_each(|v| *v *= gate);
1364                }
1365            }
1366            add_rows(&mut out, &y);
1367        }
1368        Ok(out)
1369    }
1370
1371    /// Expert `e`'s projection of every row of `xs`, out of a stacked `[in, out, experts]` tensor, as a product to run.
1372    fn expert(&mut self, l: usize, which: &str, e: usize, out_f: usize, xs: &[Vec<f64>]) -> R<Product> {
1373        let name = format!("blk.{l}.{which}.weight");
1374        let (ty, _) = self.g.describe(&name)?;
1375        let in_f = xs[0].len();
1376        let row = ty.bytes_for(in_f);
1377        let raw = self.tensor_bytes(&name)?;
1378        let xs = self.read_by(ty, xs);
1379        Ok(Product { raw, from: e * out_f * row, ty, in_f, out_f, xs })
1380    }
1381}
1382
1383/// The multiply-adds one thread of [`products`] is given at least: a smaller pass runs on fewer threads (one, below
1384/// this), so a thread is never started for less work than starting it costs.
1385const MATVEC_GRAIN: usize = 1 << 20;
1386
1387/// `y_b = W·x_b` for each `x_b`, `W` the `out_f` rows of `ty` bytes from byte `from` of `raw`.
1388struct Product {
1389    raw: Arc<Vec<u8>>,
1390    from: usize,
1391    ty: GgmlType,
1392    in_f: usize,
1393    out_f: usize,
1394    xs: Vec<Vec<f64>>,
1395}
1396
1397/// Every product's `y_b`, the products' rows split across threads together as the work warrants: each thread takes a
1398/// run of the rows of the products in turn, decodes them one at a time into one reused row and contracts it with every
1399/// `x_b` of its product, so no more than a row of a weight is ever decoded at once. A row's sums are its own, however
1400/// the rows are split.
1401fn products(ps: &[Product], threads: usize) -> Vec<Vec<Vec<f64>>> {
1402    let work = |p: &Product| p.in_f * p.xs.len().max(1);
1403    let total: usize = ps.iter().map(|p| p.out_f * work(p)).sum();
1404    let tasks = threads.min(total.div_ceil(MATVEC_GRAIN)).max(1);
1405    // Each task's runs of rows, `(product, first, rows)`, cut so the tasks' work is even.
1406    let share = total.div_ceil(tasks);
1407    let mut runs: Vec<Vec<(usize, usize, usize)>> = vec![Vec::new()];
1408    let mut load = 0;
1409    for (i, p) in ps.iter().enumerate() {
1410        let mut first = 0;
1411        while first < p.out_f {
1412            if load >= share && runs.len() < tasks {
1413                runs.push(Vec::new());
1414                load = 0;
1415            }
1416            let rows = if runs.len() == tasks {
1417                p.out_f - first
1418            } else {
1419                (share - load.min(share)).div_ceil(work(p)).clamp(1, p.out_f - first)
1420            };
1421            runs.last_mut().expect("a task").push((i, first, rows));
1422            load += rows * work(p);
1423            first += rows;
1424        }
1425    }
1426    let run = |task: &[(usize, usize, usize)]| -> Vec<(usize, usize, Vec<Vec<f64>>)> {
1427        task.iter()
1428            .map(|&(i, first, rows)| {
1429                let p = &ps[i];
1430                let row_bytes = p.ty.bytes_for(p.in_f);
1431                let mut w: Vec<f32> = Vec::with_capacity(p.in_f);
1432                let mut ys: Vec<Vec<f64>> = p.xs.iter().map(|_| Vec::with_capacity(rows)).collect();
1433                for r in first..first + rows {
1434                    let at = p.from + r * row_bytes;
1435                    w.clear();
1436                    p.ty.dequantize(&p.raw[at..at + row_bytes], &mut w);
1437                    for (y, x) in ys.iter_mut().zip(&p.xs) {
1438                        y.push(w.iter().zip(x).map(|(&a, b)| a as f64 * b).sum());
1439                    }
1440                }
1441                (i, first, ys)
1442            })
1443            .collect()
1444    };
1445    let parts: Vec<(usize, usize, Vec<Vec<f64>>)> = if runs.len() == 1 {
1446        run(&runs[0])
1447    } else {
1448        std::thread::scope(|s| {
1449            let handles: Vec<_> = runs.iter().map(|task| s.spawn(move || run(task))).collect();
1450            handles.into_iter().flat_map(|h| h.join().expect("product thread")).collect()
1451        })
1452    };
1453    let mut out: Vec<Vec<Vec<f64>>> = ps.iter().map(|p| vec![vec![0f64; p.out_f]; p.xs.len()]).collect();
1454    for (i, first, ys) in parts {
1455        for (col, y) in out[i].iter_mut().zip(ys) {
1456            col[first..first + y.len()].copy_from_slice(&y);
1457        }
1458    }
1459    out
1460}
1461
1462fn add_rows(x: &mut [Vec<f64>], y: &[Vec<f64>]) {
1463    for (a, b) in x.iter_mut().zip(y) {
1464        for (u, v) in a.iter_mut().zip(b) {
1465            *u += v;
1466        }
1467    }
1468}
1469
1470/// Each lane's share of a sublayer's output joins it: `h[s·d + j] += out[j]·share[s]`.
1471fn inject_lanes(h: &mut [Vec<f64>], out: &[Vec<f64>], shares: &[Vec<f64>], d: usize) {
1472    for ((row, o), share) in h.iter_mut().zip(out).zip(shares) {
1473        for (s, &w) in share.iter().enumerate() {
1474            for j in 0..d {
1475                row[s * d + j] += o[j] * w;
1476            }
1477        }
1478    }
1479}
1480
1481/// An RMSNorm of each `d`-wide lane of `x` on its own, by one weight as wide as every lane.
1482fn lane_norm(x: &[f64], w: &[f64], d: usize, eps: f64) -> Vec<f64> {
1483    x.chunks(d).zip(w.chunks(d)).flat_map(|(lane, w)| rms_norm(lane, w, eps)).collect()
1484}
1485
1486/// The table rows of the n-grams ending at the last of `w` (the last `ngram` tokens, oldest first): for each order `n`
1487/// from 2, `t₀·m₀ ⊕ t₁·m₁ ⊕ … ⊕ t₍ₙ₋₁₎·m₍ₙ₋₁₎` (`t_k` the token `k` back, the end of document where an end of
1488/// document lies between, in two's-complement 64-bit arithmetic as the reference implementation's `long`s) modulo each
1489/// of its heads' primes, from the head's offset.
1490fn ngram_rows(p: &super::spec::Ple, w: &[u32]) -> Vec<u64> {
1491    let last = w.len() - 1;
1492    let back = |k: usize| -> i64 {
1493        if w[last - k..last].contains(&p.eos) {
1494            i64::from(p.eos)
1495        } else {
1496            i64::from(w[last - k])
1497        }
1498    };
1499    let mut rows = Vec::with_capacity((p.ngram - 1) * p.heads_per_ngram);
1500    for n in 2..=p.ngram {
1501        let mixed = (0..n).fold(0i64, |acc, k| {
1502            let t = if k == 0 { i64::from(w[last]) } else { back(k) };
1503            acc ^ t.wrapping_mul(p.multipliers[k] as i64)
1504        });
1505        for j in 0..p.heads_per_ngram {
1506            let head = (n - 2) * p.heads_per_ngram + j;
1507            rows.push(mixed.rem_euclid(p.head_vocab[head] as i64) as u64 + p.head_offsets[head]);
1508        }
1509    }
1510    rows
1511}
1512
1513/// The positions a query at `pos` attends under QSA: every visible one while the complete blocks of `ix.block` fit the
1514/// budget; past it the best `budget / block` blocks by `Σ_h relu(q_h·k̄) / √head_dim` — a block's index keys averaged,
1515/// normed and rotated at its first position — the lower block first between equal scores, and every position after the
1516/// last complete block.
1517#[allow(clippy::too_many_arguments)]
1518fn qsa_positions(
1519    ix: &Indexer,
1520    queries: &[Vec<f64>],
1521    keys: &[Vec<f64>],
1522    norm: &[f64],
1523    rope: Option<&Rope>,
1524    factors: Option<&[f64]>,
1525    eps: f64,
1526    pos: usize,
1527) -> Vec<usize> {
1528    let blocks = (pos + 1) / ix.block;
1529    let keep = ix.budget / ix.block;
1530    if blocks <= keep {
1531        return (0..=pos).collect();
1532    }
1533    let mut scored: Vec<(f64, usize)> = (0..blocks)
1534        .map(|b| {
1535            let first = b * ix.block;
1536            let mean: Vec<f64> = (0..ix.head_dim)
1537                .map(|e| keys[first..first + ix.block].iter().map(|k| k[e]).sum::<f64>() / ix.block as f64)
1538                .collect();
1539            let mut k = rms_norm(&mean, norm, eps);
1540            if let Some(r) = rope {
1541                rotate(&mut k, first, r, factors);
1542            }
1543            let score = queries.iter().map(|q| q.iter().zip(&k).map(|(a, b)| a * b).sum::<f64>().max(0.0)).sum::<f64>()
1544                / (ix.head_dim as f64).sqrt();
1545            (score, b)
1546        })
1547        .collect();
1548    scored.sort_by(|a, b| b.0.total_cmp(&a.0).then(a.1.cmp(&b.1)));
1549    let mut chosen: Vec<usize> = scored[..keep].iter().map(|&(_, b)| b).collect();
1550    chosen.sort_unstable();
1551    chosen.into_iter().flat_map(|b| b * ix.block..(b + 1) * ix.block).chain(blocks * ix.block..=pos).collect()
1552}
1553
1554fn add_bias(rows: &mut [Vec<f64>], b: &[f64]) {
1555    for r in rows {
1556        r.iter_mut().zip(b).for_each(|(v, b)| *v += b);
1557    }
1558}
1559
1560fn rms_norm(x: &[f64], w: &[f64], eps: f64) -> Vec<f64> {
1561    let ms = x.iter().map(|v| v * v).sum::<f64>() / x.len() as f64;
1562    let scale = 1.0 / (ms + eps).sqrt();
1563    x.iter().zip(w).map(|(v, w)| v * scale * w).collect()
1564}
1565
1566fn softmax(xs: &mut [f64]) {
1567    let m = xs.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
1568    let mut sum = 0.0;
1569    for v in xs.iter_mut() {
1570        *v = (*v - m).exp();
1571        sum += *v;
1572    }
1573    for v in xs.iter_mut() {
1574        *v /= sum;
1575    }
1576}
1577
1578fn sigmoid(x: f64) -> f64 {
1579    1.0 / (1.0 + (-x).exp())
1580}
1581
1582fn silu(x: f64) -> f64 {
1583    x * sigmoid(x)
1584}
1585
1586/// `ln(1 + eˣ)`, without overflowing for large `x`.
1587fn softplus(x: f64) -> f64 {
1588    if x > 0.0 {
1589        x + (-x).exp().ln_1p()
1590    } else {
1591        x.exp().ln_1p()
1592    }
1593}
1594
1595fn gated(act: &Act, g: &[f64], u: &[f64]) -> Vec<f64> {
1596    g.iter()
1597        .zip(u)
1598        .map(|(&g, &u)| match act {
1599            Act::Silu => g / (1.0 + (-g).exp()) * u,
1600            Act::GeluTanh => {
1601                let c = (2.0 / std::f64::consts::PI).sqrt();
1602                0.5 * g * (1.0 + (c * (g + 0.044715 * g * g * g)).tanh()) * u
1603            }
1604            Act::SwigluOai { alpha, limit } => {
1605                let gc = g.min(*limit);
1606                let uc = u.clamp(-limit, *limit);
1607                gc / (1.0 + (-alpha * gc).exp()) * (uc + 1.0)
1608            }
1609        })
1610        .collect()
1611}
1612
1613/// Rotate one head vector at position `pos`: the first `rope.dims` dimensions in pairs (NEOX: `i` with
1614/// `i + dims/2`; otherwise `2i` with `2i+1`) by [`Rope::rotation`], the rest untouched.
1615fn rotate(v: &mut [f64], pos: usize, rope: &Rope, factors: Option<&[f64]>) {
1616    let half = rope.dims / 2;
1617    for i in 0..half {
1618        let (c, s) = rope.rotation(i, pos, factors.map(|f| f[i]));
1619        let (a, b) = if rope.neox { (i, i + half) } else { (2 * i, 2 * i + 1) };
1620        let (x0, x1) = (v[a], v[b]);
1621        v[a] = x0 * c - x1 * s;
1622        v[b] = x0 * s + x1 * c;
1623    }
1624}
1625
1626/// The index of the largest logit (the first of equals).
1627pub fn argmax(logits: &[f64]) -> u32 {
1628    let mut best = 0;
1629    for (i, &v) in logits.iter().enumerate() {
1630        if v > logits[best] {
1631            best = i;
1632        }
1633    }
1634    best as u32
1635}