Skip to main content

logicaffeine_compile/spatial/lower/
sambaflow.rs

1//! `largo emit rdu --format sambaflow` — the authored tensor program as the PyTorch module SambaFlow ingests.
2//!
3//! SambaFlow's front end takes PyTorch, so the vendor-format artifact for that front door is a
4//! `torch.nn.Module` whose `forward` mirrors the program's tensor statements ONE OP PER STATEMENT, in dataflow
5//! order, plus a weights manifest (variable → shape, role, checkpoint tensor name where the naming convention
6//! knows it) and a `compile.py` scaffold marked TEMPLATE where it calls the vendor API. It is an emitted
7//! vendor-ingestion artifact — like an emitted `.cu` — and never our compute path: nothing of ours runs from
8//! the Python, and the header says so.
9//!
10//! The reader ([`read_tensor_sentences`]) walks the program's sentences in the tensor sugar the parser
11//! defines (`Let Y be rmsnorm of X with weight W across H heads.` and its siblings); the real parser is asked
12//! to accept the program first, and the one IR's lift of it (`TensorGraph::lift_source`) is asked to agree on the ops
13//! they both know, so the sentence reader can never drift silently from the language. Every
14//! spelling mirrors the parser's DESUGAR — the rmsnorm eps, the NEOX rope pairs with the partial-rotary
15//! pass-through, attention's `1/√hd` with `kvh = (head-1)/(H/KV)`, decay's `(1+e^u)^{alog}`, the conv ring
16//! shift, the Gated DeltaNet recurrence with `kb = ((h-1) mod hk)·d` — and `rdu_sambaflow_emit_lock` checks
17//! the module against the VM's logits when torch is present. An op without a spelling is refused BY NAME.
18
19use std::collections::{BTreeMap, BTreeSet};
20
21use crate::tensor_graph::graph::{Storage, TensorGraph};
22
23/// The first line of every emitted file.
24pub const VENDOR_HEADER: &str =
25    "# vendor-ingestion artifact emitted by LOGOS — not our compute path";
26/// The mark on every line of `compile.py` that calls an API nobody here has run.
27pub const TEMPLATE_MARK: &str = "# TEMPLATE — SambaFlow API unverified";
28/// The ops the authored Qwen3.8 decode step needs; every one has a spelling in [`torch_spelling`].
29pub const QWEN38_OPS: &[&str] = &[
30    "rmsnorm",
31    "rope",
32    "attention",
33    "sigmoid",
34    "hadamard",
35    "causal conv",
36    "silu",
37    "l2norm",
38    "decay",
39    "gated delta",
40    "swiglu",
41    "matmul",
42    "argmax",
43    "embedding",
44];
45
46pub struct TorchArtifact {
47    pub model_py: String,
48    pub compile_py: String,
49    pub manifest_json: String,
50}
51
52/// One sentence of a tensor program.
53#[derive(Clone, Debug, PartialEq)]
54pub enum TensorSentence {
55    /// `Let V be a R by C tensor of Int|Real.`
56    Decl {
57        var: String,
58        rows: usize,
59        cols: usize,
60        real: bool,
61    },
62    /// `Set item N of V to VALUE.`
63    Fill {
64        var: String,
65        index: usize,
66        value: String,
67    },
68    /// `Let OUT be <op> …`, or `Set row P of T to R.`
69    Op { out: String, kind: OpKind },
70    /// `Show …` — host output, nothing for the module.
71    Show,
72}
73
74#[derive(Clone, Debug, PartialEq)]
75pub enum OpKind {
76    Matmul {
77        a: String,
78        b: String,
79    },
80    Plus {
81        a: String,
82        b: String,
83    },
84    Hadamard {
85        a: String,
86        b: String,
87    },
88    Rmsnorm {
89        x: String,
90        residual: Option<String>,
91        weight: Option<String>,
92        heads: Option<usize>,
93    },
94    Rope {
95        q: String,
96        rc: String,
97        rs: String,
98        heads: Option<usize>,
99    },
100    Attention {
101        q: String,
102        k: String,
103        v: String,
104        heads: usize,
105        groups: usize,
106    },
107    FullAttention {
108        q: String,
109        k: String,
110        v: String,
111        heads: usize,
112    },
113    Sigmoid {
114        x: String,
115    },
116    Silu {
117        x: String,
118    },
119    Gelu {
120        x: String,
121    },
122    Softmax {
123        x: String,
124    },
125    Transpose {
126        x: String,
127    },
128    Layernorm {
129        x: String,
130        weight: String,
131        bias: String,
132    },
133    CausalConv {
134        x: String,
135        weight: String,
136        state: String,
137        taps: usize,
138    },
139    L2norm {
140        x: String,
141        heads: Option<usize>,
142    },
143    Decay {
144        ar: String,
145        dt: String,
146        alog: String,
147    },
148    GatedDelta {
149        q: String,
150        k: String,
151        v: String,
152        gate: String,
153        beta: String,
154        decay: String,
155        state: String,
156        norm: String,
157        hv: usize,
158        hk: usize,
159    },
160    Swiglu {
161        gate: String,
162        up: String,
163    },
164    Moe {
165        x: String,
166    },
167    Argmax {
168        x: String,
169    },
170    /// `Let V be row TOK of TABLE.` — one row of a table by a data index (the embedding lookup).
171    RowOf {
172        table: String,
173        tok: String,
174    },
175    /// `Set row P of TABLE to ROW.` — a scatter into a table (the KV-cache append).
176    SetRow {
177        table: String,
178        pos: String,
179        row: String,
180    },
181}
182
183impl OpKind {
184    /// The op's name — the key of [`torch_spelling`].
185    pub fn name(&self) -> &'static str {
186        match self {
187            OpKind::Matmul { .. } => "matmul",
188            OpKind::Plus { .. } => "plus",
189            OpKind::Hadamard { .. } => "hadamard",
190            OpKind::Rmsnorm { .. } => "rmsnorm",
191            OpKind::Rope { .. } => "rope",
192            OpKind::Attention { .. } => "attention",
193            OpKind::FullAttention { .. } => "full attention",
194            OpKind::Sigmoid { .. } => "sigmoid",
195            OpKind::Silu { .. } => "silu",
196            OpKind::Gelu { .. } => "gelu",
197            OpKind::Softmax { .. } => "softmax",
198            OpKind::Transpose { .. } => "transpose",
199            OpKind::Layernorm { .. } => "layernorm",
200            OpKind::CausalConv { .. } => "causal conv",
201            OpKind::L2norm { .. } => "l2norm",
202            OpKind::Decay { .. } => "decay",
203            OpKind::GatedDelta { .. } => "gated delta",
204            OpKind::Swiglu { .. } => "swiglu",
205            OpKind::Moe { .. } => "moe",
206            OpKind::Argmax { .. } => "argmax",
207            OpKind::RowOf { .. } => "embedding",
208            OpKind::SetRow { .. } => "set row",
209        }
210    }
211
212    /// The variables the op reads.
213    pub fn inputs(&self) -> Vec<&str> {
214        match self {
215            OpKind::Matmul { a, b } | OpKind::Plus { a, b } | OpKind::Hadamard { a, b } => {
216                vec![a, b]
217            }
218            OpKind::Rmsnorm {
219                x,
220                residual,
221                weight,
222                ..
223            } => {
224                let mut v = vec![x.as_str()];
225                v.extend(residual.as_deref());
226                v.extend(weight.as_deref());
227                v
228            }
229            OpKind::Rope { q, rc, rs, .. } => vec![q, rc, rs],
230            OpKind::Attention { q, k, v, .. } | OpKind::FullAttention { q, k, v, .. } => {
231                vec![q, k, v]
232            }
233            OpKind::Sigmoid { x }
234            | OpKind::Silu { x }
235            | OpKind::Gelu { x }
236            | OpKind::Softmax { x }
237            | OpKind::Transpose { x }
238            | OpKind::L2norm { x, .. }
239            | OpKind::Moe { x }
240            | OpKind::Argmax { x } => vec![x],
241            OpKind::Layernorm { x, weight, bias } => vec![x, weight, bias],
242            OpKind::CausalConv {
243                x, weight, state, ..
244            } => vec![x, weight, state],
245            OpKind::Decay { ar, dt, alog } => vec![ar, dt, alog],
246            OpKind::GatedDelta {
247                q,
248                k,
249                v,
250                gate,
251                beta,
252                decay,
253                state,
254                norm,
255                ..
256            } => vec![q, k, v, gate, beta, decay, state, norm],
257            OpKind::Swiglu { gate, up } => vec![gate, up],
258            OpKind::RowOf { table, tok } => vec![table, tok],
259            OpKind::SetRow { table, pos, row } => vec![table, pos, row],
260        }
261    }
262
263    /// The carried state the op writes back (a conv ring, a GDN memory, a KV table), if any.
264    pub fn writes(&self) -> Option<&str> {
265        match self {
266            OpKind::CausalConv { state, .. } | OpKind::GatedDelta { state, .. } => Some(state),
267            OpKind::SetRow { table, .. } => Some(table),
268            _ => None,
269        }
270    }
271}
272
273// ── The sentence reader ──────────────────────────────────────────────────────────────────────────
274
275fn num(w: &str, what: &str, line: &str) -> Result<usize, String> {
276    w.parse::<usize>()
277        .map_err(|_| format!("`{line}`: {what} must be an integer literal, got `{w}`"))
278}
279
280/// Read one sentence of tensor sugar. `None` when the line is not a sentence at all (a heading, a blank).
281fn read_sentence(line: &str) -> Result<Option<TensorSentence>, String> {
282    let t = line.trim();
283    if t.is_empty() || t.starts_with('#') {
284        return Ok(None);
285    }
286    let Some(body) = t.strip_suffix('.') else {
287        return Err(format!("`{t}`: a sentence ends with a period"));
288    };
289    let w: Vec<&str> = body.split_whitespace().collect();
290    let s = |i: usize| w.get(i).copied().unwrap_or("");
291    let own = |i: usize| s(i).to_string();
292    let unknown = || {
293        Err(format!("`{t}`: not a tensor sentence the SambaFlow reader knows (a declaration, a fill, a tensor op, or a Show)"))
294    };
295    if s(0) == "Show" {
296        return Ok(Some(TensorSentence::Show));
297    }
298    if s(0) == "Set" && s(1) == "item" && s(3) == "of" && s(5) == "to" && w.len() == 7 {
299        return Ok(Some(TensorSentence::Fill {
300            var: own(4),
301            index: num(s(2), "the item index", t)?,
302            value: own(6),
303        }));
304    }
305    if s(0) == "Set" && s(1) == "row" && s(3) == "of" && s(5) == "to" && w.len() == 7 {
306        return Ok(Some(TensorSentence::Op {
307            out: own(4),
308            kind: OpKind::SetRow {
309                table: own(4),
310                pos: own(2),
311                row: own(6),
312            },
313        }));
314    }
315    if s(0) != "Let" || s(2) != "be" {
316        return unknown();
317    }
318    let out = own(1);
319    let rest = &w[3..];
320    let r = |i: usize| rest.get(i).copied().unwrap_or("");
321    let ro = |i: usize| r(i).to_string();
322    let n = rest.len();
323    // `a R by C tensor of T`
324    if r(0) == "a" && r(2) == "by" && r(4) == "tensor" && r(5) == "of" && n == 7 {
325        let real = match r(6) {
326            "Real" => true,
327            "Int" => false,
328            other => return Err(format!("`{t}`: a tensor is of Int or Real, not `{other}`")),
329        };
330        return Ok(Some(TensorSentence::Decl {
331            var: out,
332            rows: num(r(1), "the row count", t)?,
333            cols: num(r(3), "the column count", t)?,
334            real,
335        }));
336    }
337    // `A matmul B` / `A plus B` / `A hadamard B` — three words with the operator in the middle.
338    if n == 3 && matches!(r(1), "matmul" | "plus" | "hadamard") {
339        let (a, b) = (ro(0), ro(2));
340        let kind = match r(1) {
341            "matmul" => OpKind::Matmul { a, b },
342            "plus" => OpKind::Plus { a, b },
343            _ => OpKind::Hadamard { a, b },
344        };
345        return Ok(Some(TensorSentence::Op { out, kind }));
346    }
347    let heads_at = |i: usize| -> Result<Option<usize>, String> {
348        if r(i) == "across" && r(i + 2) == "heads" {
349            Ok(Some(num(r(i + 1), "the head count", t)?))
350        } else if r(i).is_empty() {
351            Ok(None)
352        } else {
353            Err(format!(
354                "`{t}`: expected `across H heads` or the end of the sentence, got `{}`",
355                r(i)
356            ))
357        }
358    };
359    let kind = match (r(0), r(1)) {
360        ("rmsnorm", "of") => {
361            let x = ro(2);
362            let mut i = 3;
363            let residual = if r(i) == "plus" {
364                i += 2;
365                Some(ro(i - 1))
366            } else {
367                None
368            };
369            let weight = if r(i) == "with" && r(i + 1) == "weight" {
370                i += 3;
371                Some(ro(i - 1))
372            } else {
373                None
374            };
375            let heads = heads_at(i)?;
376            if residual.is_some() && weight.is_none() {
377                return Err(format!("`{t}`: a fused-add rmsnorm carries a weight"));
378            }
379            OpKind::Rmsnorm {
380                x,
381                residual,
382                weight,
383                heads,
384            }
385        }
386        ("rope", "of") => {
387            if !(r(3) == "with" && r(4) == "cos" && r(6) == "and" && r(7) == "sin") {
388                return Err(format!(
389                    "`{t}`: `rope of Q with cos RC and sin RS [across H heads]`"
390                ));
391            }
392            OpKind::Rope {
393                q: ro(2),
394                rc: ro(5),
395                rs: ro(8),
396                heads: heads_at(9)?,
397            }
398        }
399        ("attention", "of") => {
400            if !(r(3) == "over"
401                && r(5) == "and"
402                && r(7) == "with"
403                && r(9) == "heads"
404                && r(11) == "groups"
405                && n == 12)
406            {
407                return Err(format!(
408                    "`{t}`: `attention of Q over K and V with H heads KV groups`"
409                ));
410            }
411            OpKind::Attention {
412                q: ro(2),
413                k: ro(4),
414                v: ro(6),
415                heads: num(r(8), "H", t)?,
416                groups: num(r(10), "KV", t)?,
417            }
418        }
419        ("full", "attention") => {
420            if !(r(2) == "of"
421                && r(4) == "over"
422                && r(6) == "and"
423                && r(8) == "with"
424                && r(10) == "heads"
425                && n == 11)
426            {
427                return Err(format!(
428                    "`{t}`: `full attention of Q over K and V with H heads`"
429                ));
430            }
431            OpKind::FullAttention {
432                q: ro(3),
433                k: ro(5),
434                v: ro(7),
435                heads: num(r(9), "H", t)?,
436            }
437        }
438        ("sigmoid", "of") if n == 3 => OpKind::Sigmoid { x: ro(2) },
439        ("silu", "of") if n == 3 => OpKind::Silu { x: ro(2) },
440        ("gelu", "of") if n == 3 => OpKind::Gelu { x: ro(2) },
441        ("softmax", "of") if n == 3 => OpKind::Softmax { x: ro(2) },
442        ("transpose", "of") if n == 3 => OpKind::Transpose { x: ro(2) },
443        ("argmax", "of") if n == 3 => OpKind::Argmax { x: ro(2) },
444        ("row", _) if r(2) == "of" && n == 4 => OpKind::RowOf {
445            table: ro(3),
446            tok: ro(1),
447        },
448        ("layernorm", "of") => {
449            if !(r(3) == "with" && r(4) == "weight" && r(6) == "and" && r(7) == "bias" && n == 9) {
450                return Err(format!("`{t}`: `layernorm of X with weight W and bias B`"));
451            }
452            OpKind::Layernorm {
453                x: ro(2),
454                weight: ro(5),
455                bias: ro(8),
456            }
457        }
458        ("causal", "conv") => {
459            if !(r(2) == "of"
460                && r(4) == "with"
461                && r(5) == "weight"
462                && r(7) == "state"
463                && r(9) == "over"
464                && r(11) == "taps"
465                && n == 12)
466            {
467                return Err(format!(
468                    "`{t}`: `causal conv of X with weight WC state CS over T taps`"
469                ));
470            }
471            OpKind::CausalConv {
472                x: ro(3),
473                weight: ro(6),
474                state: ro(8),
475                taps: num(r(10), "T", t)?,
476            }
477        }
478        ("l2norm", "of") => OpKind::L2norm {
479            x: ro(2),
480            heads: heads_at(3)?,
481        },
482        ("decay", "of") => {
483            if !(r(3) == "with" && r(4) == "bias" && r(6) == "rate" && n == 8) {
484                return Err(format!("`{t}`: `decay of Ar with bias Dt rate Alog`"));
485            }
486            OpKind::Decay {
487                ar: ro(2),
488                dt: ro(5),
489                alog: ro(7),
490            }
491        }
492        ("gated", "delta") => {
493            let shape = [
494                "gated", "delta", "of", "Q", "over", "K", "and", "V", "with", "gate", "Z", "beta",
495                "B", "decay", "A", "state", "S", "norm", "GN", "with", "HV", "heads", "HK",
496                "groups",
497            ];
498            let fixed = |i: usize| {
499                shape[i]
500                    .chars()
501                    .next()
502                    .map(|c| c.is_ascii_lowercase())
503                    .unwrap_or(false)
504            };
505            if n != shape.len() || (0..n).any(|i| fixed(i) && r(i) != shape[i]) {
506                return Err(format!("`{t}`: `gated delta of Q over K and V with gate Z beta B decay A state S norm GN with HV heads HK groups`"));
507            }
508            OpKind::GatedDelta {
509                q: ro(3),
510                k: ro(5),
511                v: ro(7),
512                gate: ro(10),
513                beta: ro(12),
514                decay: ro(14),
515                state: ro(16),
516                norm: ro(18),
517                hv: num(r(20), "HV", t)?,
518                hk: num(r(22), "HK", t)?,
519            }
520        }
521        ("swiglu", "of") => {
522            if !(r(3) == "and" && n == 5) {
523                return Err(format!("`{t}`: `swiglu of Gate and Up`"));
524            }
525            OpKind::Swiglu {
526                gate: ro(2),
527                up: ro(4),
528            }
529        }
530        ("moe", "of") => OpKind::Moe { x: ro(2) },
531        _ => return unknown(),
532    };
533    Ok(Some(TensorSentence::Op { out, kind }))
534}
535
536/// Every sentence of a tensor program, in order. A sentence outside the tensor sugar is an error naming it.
537pub fn read_tensor_sentences(source: &str) -> Result<Vec<TensorSentence>, String> {
538    let mut out = Vec::new();
539    for line in source.lines() {
540        if let Some(s) = read_sentence(line)? {
541            out.push(s);
542        }
543    }
544    Ok(out)
545}
546
547// ── The spellings ────────────────────────────────────────────────────────────────────────────────
548
549/// The torch expression an op is spelled with (its helper's call shape), or a refusal naming the op.
550pub fn torch_spelling(op: &str) -> Result<&'static str, String> {
551    Ok(match op {
552        "matmul" => "a @ b",
553        "plus" => "a + b",
554        "hadamard" => "a * b",
555        "rmsnorm" => "rmsnorm(x, w, nr, nc)",
556        "rope" => "rope(q, rc, rs, heads, hd, half)",
557        "attention" => "attention(q, k, v, heads, groups, hd)",
558        "full attention" => "full_attention(q, k, v, heads, hd)",
559        "sigmoid" => "torch.sigmoid(x)",
560        "silu" => "F.silu(x)",
561        "gelu" => "gelu_tanh(x)",
562        "softmax" => "softmax_rows(x)",
563        "transpose" => "x.transpose(0, 1)",
564        "layernorm" => "layernorm(x, w, b)",
565        "causal conv" => "causal_conv(x, wc, cs)",
566        "l2norm" => "l2norm(x, nr, nc)",
567        "decay" => "decay(ar, dt, alog)",
568        "gated delta" => "gated_delta(q, k, v, z, b, a, s, gn, hv, hk, d)",
569        "swiglu" => "swiglu(g, u)",
570        "argmax" => "torch.argmax(x).reshape(1, 1).to(x.dtype)",
571        "embedding" => "table[int(tok):int(tok) + 1]",
572        "set row" => "table[int(pos)] = row.reshape(-1)",
573        other => return Err(format!("`{other}` has no torch spelling in the SambaFlow emitter — the routed expert FFN (moe) and anything outside the tensor sugar are refused, never dropped")),
574    })
575}
576
577/// The checkpoint tensor a LOGOS weight variable comes from, by the extractor's naming convention
578/// (`examples/extract_qwen38.rs`): `Wq3` → `blk.3.attn_q.weight` on an attention layer, `Wq0` →
579/// `blk.0.attn_qkv.weight` on a Gated DeltaNet layer. `None` for a name the convention does not cover.
580pub fn gguf_name(var: &str, attention_layers: &BTreeSet<usize>) -> Option<String> {
581    match var {
582        "on" => return Some("output_norm.weight".into()),
583        "Wout" => return Some("output.weight".into()),
584        "emb" | "Emb" => return Some("token_embd.weight".into()),
585        _ => {}
586    }
587    let digits: String = var
588        .chars()
589        .rev()
590        .take_while(|c| c.is_ascii_digit())
591        .collect::<Vec<_>>()
592        .into_iter()
593        .rev()
594        .collect();
595    if digits.is_empty() {
596        return None;
597    }
598    let stem = &var[..var.len() - digits.len()];
599    let l: usize = digits.parse().ok()?;
600    let attn = attention_layers.contains(&l);
601    let name = match (stem, attn) {
602        ("an", _) => "attn_norm.weight",
603        ("fn", _) => "post_attention_norm.weight",
604        ("Qn", _) => "attn_q_norm.weight",
605        ("Kn", _) => "attn_k_norm.weight",
606        ("Wq", true) | ("Wqg", true) => "attn_q.weight",
607        ("Wk", true) => "attn_k.weight",
608        ("Wv", true) => "attn_v.weight",
609        ("Wo", true) => "attn_output.weight",
610        ("Wq", false) | ("Wk", false) | ("Wv", false) => "attn_qkv.weight",
611        ("Wz", false) => "attn_gate.weight",
612        ("Wo", false) => "ssm_out.weight",
613        ("Wcq", _) | ("Wck", _) | ("Wcv", _) => "ssm_conv1d.weight",
614        ("Wb", _) => "ssm_beta.weight",
615        ("Wa", _) => "ssm_alpha.weight",
616        ("Dt", _) => "ssm_dt.bias",
617        ("Al", _) => "ssm_a",
618        ("Gn", _) => "ssm_norm.weight",
619        ("Wg", _) => "ffn_gate.weight",
620        ("Wu", _) => "ffn_up.weight",
621        ("Wd", _) => "ffn_down.weight",
622        _ => return None,
623    };
624    Some(format!("blk.{l}.{name}"))
625}
626
627// ── Emission ─────────────────────────────────────────────────────────────────────────────────────
628
629const PY_HELPERS: &str = r#"
630EPS = 1e-6
631
632
633def rmsnorm(x, w, nr, nc):
634    """Per-row RMSNorm over an (nr, nc) view: y = x / sqrt(mean(x^2) + eps) * w."""
635    v = x.reshape(nr, nc)
636    y = v * torch.rsqrt((v * v).mean(-1, keepdim=True) + EPS) * w.reshape(1, nc)
637    return y.reshape(x.shape)
638
639
640def rope(q, rc, rs, heads, hd, half):
641    """NEOX rotary on the leading 2*half dims of each head (pairs (i, i+half)); the rest passes through."""
642    v = q.reshape(heads, hd)
643    a, b = v[:, :half], v[:, half:2 * half]
644    c, s = rc.reshape(1, half), rs.reshape(1, half)
645    return torch.cat([a * c - b * s, a * s + b * c, v[:, 2 * half:]], dim=1).reshape(q.shape)
646
647
648def attention(q, k, v, heads, groups, hd):
649    """Single-query GQA decode attention: query head h reads kv head h // (heads // groups)."""
650    L = k.shape[0]
651    qh, kh, vh = q.reshape(heads, hd), k.reshape(L, groups, hd), v.reshape(L, groups, hd)
652    out = []
653    for h in range(heads):
654        g = h // (heads // groups)
655        scores = (kh[:, g, :] @ qh[h]) / math.sqrt(hd)
656        out.append(torch.softmax(scores, dim=0) @ vh[:, g, :])
657    return torch.stack(out).reshape(1, heads * hd)
658
659
660def full_attention(q, k, v, heads, hd):
661    """Bidirectional T x T self-attention per head, no mask."""
662    T = q.shape[0]
663    qh, kh, vh = q.reshape(T, heads, hd), k.reshape(T, heads, hd), v.reshape(T, heads, hd)
664    out = []
665    for h in range(heads):
666        scores = (qh[:, h, :] @ kh[:, h, :].transpose(0, 1)) / math.sqrt(hd)
667        out.append(torch.softmax(scores, dim=1) @ vh[:, h, :])
668    return torch.stack(out, dim=1).reshape(T, heads * hd)
669
670
671def gelu_tanh(x):
672    """GELU, ggml's tanh approximation, in its one-exponential arrangement x / (1 + e^-2z)."""
673    z = math.sqrt(2.0 / math.pi) * (x + 0.044715 * x * x * x)
674    return x / (1.0 + torch.exp(-2.0 * z))
675
676
677def softmax_rows(x):
678    return torch.softmax(x, dim=1)
679
680
681def layernorm(x, w, b):
682    mean = x.mean(-1, keepdim=True)
683    var = ((x - mean) * (x - mean)).mean(-1, keepdim=True)
684    return (x - mean) / torch.sqrt(var + EPS) * w.reshape(1, -1) + b.reshape(1, -1)
685
686
687def causal_conv(x, wc, cs):
688    """Depthwise causal conv1d over the decode ring: shift the ring up, append this token, reduce over taps.
689    Returns (y, new ring)."""
690    ring = torch.cat([cs[1:], x.reshape(1, -1)], dim=0)
691    return (ring * wc).sum(dim=0, keepdim=True), ring
692
693
694def l2norm(x, nr, nc):
695    v = x.reshape(nr, nc)
696    y = v / torch.sqrt((v * v).sum(-1, keepdim=True) + EPS)
697    return y.reshape(x.shape)
698
699
700def decay(ar, dt, alog):
701    """Gated DeltaNet's forget gate: (1 + e^(ar + dt)) ^ alog, as the LOGOS desugar computes it."""
702    return torch.pow(1.0 + torch.exp(ar + dt), alog)
703
704
705def gated_delta(q, k, v, z, b, a, s, gn, hv, hk, d):
706    """One Gated DeltaNet step over hv value heads sharing hk key heads (head h reads key head h mod hk):
707    u = S k;  S = alpha S + beta (v - alpha u) k^T;  o = (S q) / sqrt(d);  out = gn * rmsnorm(o) * silu(z).
708    Returns (out, new memory)."""
709    S = s.reshape(hv, d, d)
710    idx = torch.tensor([h % hk for h in range(hv)])
711    qh, kh = q.reshape(hk, d)[idx], k.reshape(hk, d)[idx]
712    vh, zh = v.reshape(hv, d), z.reshape(hv, d)
713    alpha, beta = a.reshape(hv, 1), b.reshape(hv, 1)
714    u = torch.einsum('hab,hb->ha', S, kh)
715    coef = beta * (vh - alpha * u)
716    S = alpha.reshape(hv, 1, 1) * S + coef.reshape(hv, d, 1) * kh.reshape(hv, 1, d)
717    o = torch.einsum('hab,hb->ha', S, qh) / math.sqrt(d)
718    den = torch.sqrt((o * o).mean(-1, keepdim=True) + EPS)
719    out = gn.reshape(1, d) * (o / den) * F.silu(zh)
720    return out.reshape(1, hv * d), S.reshape(s.shape)
721
722
723def swiglu(g, u):
724    return F.silu(g) * u
725"#;
726
727struct Program {
728    sentences: Vec<TensorSentence>,
729    shapes: BTreeMap<String, (usize, usize)>,
730    real: BTreeMap<String, bool>,
731    /// Declared tensors no op produces, in declaration order.
732    leaves: Vec<String>,
733    /// Leaves an op writes back.
734    states: BTreeSet<String>,
735    /// The layers whose projections feed an `attention` op (the naming convention's layer index).
736    attention_layers: BTreeSet<usize>,
737    ops: Vec<(String, OpKind)>,
738    output: String,
739}
740
741fn layer_of(var: &str) -> Option<usize> {
742    let digits: String = var
743        .chars()
744        .rev()
745        .take_while(|c| c.is_ascii_digit())
746        .collect::<Vec<_>>()
747        .into_iter()
748        .rev()
749        .collect();
750    digits.parse().ok()
751}
752
753fn read_program(source: &str) -> Result<Program, String> {
754    let sentences = read_tensor_sentences(source)?;
755    let mut shapes: BTreeMap<String, (usize, usize)> = BTreeMap::new();
756    let mut real: BTreeMap<String, bool> = BTreeMap::new();
757    let mut leaves = Vec::new();
758    let mut produced: BTreeSet<String> = BTreeSet::new();
759    let mut states = BTreeSet::new();
760    let mut attention_layers = BTreeSet::new();
761    let mut ops = Vec::new();
762    let shape = |shapes: &BTreeMap<String, (usize, usize)>,
763                 v: &str,
764                 op: &str|
765     -> Result<(usize, usize), String> {
766        shapes.get(v).copied().ok_or_else(|| {
767            format!("`{op}` reads `{v}`, which is not a declared or computed tensor")
768        })
769    };
770    for s in &sentences {
771        match s {
772            TensorSentence::Decl {
773                var,
774                rows,
775                cols,
776                real: is_real,
777            } => {
778                shapes.insert(var.clone(), (*rows, *cols));
779                real.insert(var.clone(), *is_real);
780                leaves.push(var.clone());
781            }
782            TensorSentence::Fill { var, .. } => {
783                if !shapes.contains_key(var) {
784                    return Err(format!("`Set item … of {var}` fills an undeclared tensor"));
785                }
786            }
787            TensorSentence::Show => {}
788            TensorSentence::Op { out, kind } => {
789                torch_spelling(kind.name())?;
790                for input in kind.inputs() {
791                    if !matches!(kind, OpKind::RowOf { .. } | OpKind::SetRow { .. })
792                        || shapes.contains_key(input)
793                    {
794                        shape(&shapes, input, kind.name())?;
795                    }
796                }
797                let out_shape = match kind {
798                    OpKind::Matmul { a, b } => {
799                        let ((m, ka), (kb, n)) =
800                            (shape(&shapes, a, "matmul")?, shape(&shapes, b, "matmul")?);
801                        if ka != kb {
802                            return Err(format!(
803                                "`{out} = {a} matmul {b}`: inner dimensions {ka} and {kb} disagree"
804                            ));
805                        }
806                        (m, n)
807                    }
808                    OpKind::Plus { a, .. } | OpKind::Hadamard { a, .. } => {
809                        shape(&shapes, a, kind.name())?
810                    }
811                    OpKind::Rmsnorm { x, .. }
812                    | OpKind::Rope { q: x, .. }
813                    | OpKind::Attention { q: x, .. }
814                    | OpKind::FullAttention { q: x, .. }
815                    | OpKind::Sigmoid { x }
816                    | OpKind::Silu { x }
817                    | OpKind::Gelu { x }
818                    | OpKind::Softmax { x }
819                    | OpKind::Layernorm { x, .. }
820                    | OpKind::L2norm { x, .. }
821                    | OpKind::Moe { x } => shape(&shapes, x, kind.name())?,
822                    OpKind::Transpose { x } => {
823                        let (r, c) = shape(&shapes, x, "transpose")?;
824                        (c, r)
825                    }
826                    OpKind::CausalConv { x, .. } => shape(&shapes, x, "causal conv")?,
827                    OpKind::Decay { ar, .. } => shape(&shapes, ar, "decay")?,
828                    OpKind::GatedDelta { q, hv, hk, .. } => {
829                        let (_, qc) = shape(&shapes, q, "gated delta")?;
830                        (1, hv * (qc / hk.max(&1)))
831                    }
832                    OpKind::Swiglu { gate, .. } => shape(&shapes, gate, "swiglu")?,
833                    OpKind::Argmax { .. } => (1, 1),
834                    OpKind::RowOf { table, .. } => (1, shape(&shapes, table, "embedding")?.1),
835                    OpKind::SetRow { table, .. } => shape(&shapes, table, "set row")?,
836                };
837                if let OpKind::Attention { q, .. } = kind {
838                    if let Some(l) = layer_of(q) {
839                        attention_layers.insert(l);
840                    }
841                }
842                if let Some(w) = kind.writes() {
843                    states.insert(w.to_string());
844                }
845                if !matches!(kind, OpKind::SetRow { .. }) {
846                    let is_real = kind
847                        .inputs()
848                        .first()
849                        .and_then(|i| real.get(*i).copied())
850                        .unwrap_or(true);
851                    shapes.insert(out.clone(), out_shape);
852                    real.insert(out.clone(), is_real);
853                    produced.insert(out.clone());
854                }
855                ops.push((out.clone(), kind.clone()));
856            }
857        }
858    }
859    let leaves: Vec<String> = leaves
860        .into_iter()
861        .filter(|l| !produced.contains(l))
862        .collect();
863    let output = ops
864        .iter()
865        .rev()
866        .find(|(_, k)| !matches!(k, OpKind::SetRow { .. }))
867        .map(|(o, _)| o.clone())
868        .ok_or("a tensor program with no op has nothing to emit")?;
869    Ok(Program {
870        sentences,
871        shapes,
872        real,
873        leaves,
874        states,
875        attention_layers,
876        ops,
877        output,
878    })
879}
880
881/// The real parser must accept the program, and the one IR's lift of it must agree on the ops they both know — so the
882/// sentence reader cannot drift from the language unnoticed.
883fn cross_check(source: &str, p: &Program) -> Result<(), String> {
884    crate::ui_bridge::with_parsed_program(source, |parsed, _| parsed.map(|_| ()).map_err(|e| format!("the program does not parse: {e}")))?;
885    let lifted = TensorGraph::lift_source(source, &|_| Storage::Values).map_err(|e| format!("the front end does not walk the program: {e:?}"))?;
886    let count = |kind: &str| lifted.graph.ops.iter().filter(|op| op.kind() == kind).count();
887    let counted = (count("Matmul"), count("Rope"), count("Attention"));
888    let mine = |name: &str| p.ops.iter().filter(|(_, k)| k.name() == name).count();
889    let mine_counts = (mine("matmul"), mine("rope"), mine("attention"));
890    if counted != mine_counts {
891        return Err(format!("the sentence reader and the one IR disagree on (matmul, rope, attention) counts: the IR {counted:?}, sentences {mine_counts:?}"));
892    }
893    Ok(())
894}
895
896fn fnv(s: &str) -> u64 {
897    let mut h: u64 = 0xcbf29ce484222325;
898    for b in s.bytes() {
899        h ^= b as u64;
900        h = h.wrapping_mul(0x100000001b3);
901    }
902    h
903}
904
905fn py_call(p: &Program, kind: &OpKind) -> Result<String, String> {
906    let sh = |v: &str| p.shapes.get(v).copied().unwrap_or((1, 1));
907    Ok(match kind {
908        OpKind::Matmul { a, b } => format!("{a} @ {b}"),
909        OpKind::Plus { a, b } => format!("{a} + {b}"),
910        OpKind::Hadamard { a, b } => format!("{a} * {b}"),
911        OpKind::Rmsnorm {
912            x,
913            residual,
914            weight,
915            heads,
916        } => {
917            let (r, c) = sh(x);
918            let (nr, nc) = match heads {
919                Some(h) => (*h, (r * c) / h.max(&1)),
920                None => (r, c),
921            };
922            let src = match residual {
923                Some(res) => format!("({x} + {res})"),
924                None => x.clone(),
925            };
926            match weight {
927                Some(w) => format!("rmsnorm({src}, {w}, {nr}, {nc})"),
928                None => format!("rmsnorm({src}, torch.ones({nc}, dtype={src}.dtype), {nr}, {nc})"),
929            }
930        }
931        OpKind::Rope { q, rc, rs, heads } => {
932            let (_, qc) = sh(q);
933            let (_, half) = sh(rc);
934            let hd = match heads {
935                Some(h) => qc / h.max(&1),
936                None => 2 * half,
937            };
938            let heads = if hd > 0 { qc / hd } else { 1 };
939            format!("rope({q}, {rc}, {rs}, {heads}, {hd}, {half})")
940        }
941        OpKind::Attention {
942            q,
943            k,
944            v,
945            heads,
946            groups,
947        } => {
948            let (_, qc) = sh(q);
949            format!(
950                "attention({q}, {k}, {v}, {heads}, {groups}, {})",
951                qc / heads.max(&1)
952            )
953        }
954        OpKind::FullAttention { q, k, v, heads } => {
955            let (_, qc) = sh(q);
956            format!(
957                "full_attention({q}, {k}, {v}, {heads}, {})",
958                qc / heads.max(&1)
959            )
960        }
961        OpKind::Sigmoid { x } => format!("torch.sigmoid({x})"),
962        OpKind::Silu { x } => format!("F.silu({x})"),
963        OpKind::Gelu { x } => format!("gelu_tanh({x})"),
964        OpKind::Softmax { x } => format!("softmax_rows({x})"),
965        OpKind::Transpose { x } => format!("{x}.transpose(0, 1)"),
966        OpKind::Layernorm { x, weight, bias } => format!("layernorm({x}, {weight}, {bias})"),
967        OpKind::CausalConv {
968            x, weight, state, ..
969        } => format!("causal_conv({x}, {weight}, {state})"),
970        OpKind::L2norm { x, heads } => {
971            let (r, c) = sh(x);
972            let (nr, nc) = match heads {
973                Some(h) => (*h, (r * c) / h.max(&1)),
974                None => (r, c),
975            };
976            format!("l2norm({x}, {nr}, {nc})")
977        }
978        OpKind::Decay { ar, dt, alog } => format!("decay({ar}, {dt}, {alog})"),
979        OpKind::GatedDelta {
980            q,
981            k,
982            v,
983            gate,
984            beta,
985            decay,
986            state,
987            norm,
988            hv,
989            hk,
990        } => {
991            let (_, qc) = sh(q);
992            format!("gated_delta({q}, {k}, {v}, {gate}, {beta}, {decay}, {state}, {norm}, {hv}, {hk}, {})", qc / hk.max(&1))
993        }
994        OpKind::Swiglu { gate, up } => format!("swiglu({gate}, {up})"),
995        OpKind::Argmax { x } => format!("torch.argmax({x}).reshape(1, 1).to({x}.dtype)"),
996        OpKind::RowOf { table, tok } => format!("{table}[int({tok}):int({tok}) + 1]"),
997        OpKind::SetRow { .. } => String::new(),
998        OpKind::Moe { .. } => return Err(torch_spelling("moe").unwrap_err()),
999    })
1000}
1001
1002/// The program as a PyTorch module, its weights manifest and a SambaFlow compile scaffold, or a refusal
1003/// naming what has no spelling.
1004pub fn emit_torch_module(source: &str) -> Result<TorchArtifact, String> {
1005    let p = read_program(source)?;
1006    cross_check(source, &p)?;
1007    let name = format!("logos_{:016x}", fnv(source));
1008    let leaf_role = |v: &str| -> &'static str {
1009        if p.states.contains(v) {
1010            "state"
1011        } else if gguf_name(v, &p.attention_layers).is_some() {
1012            "weight"
1013        } else {
1014            "input"
1015        }
1016    };
1017
1018    // ── model.py ──
1019    let mut m = String::new();
1020    m.push_str(VENDOR_HEADER);
1021    m.push('\n');
1022    m.push_str(&format!(
1023        "# Generated by LOGOS (logicaffeine_compile::spatial::lower::sambaflow) from the tensor program `{name}`:\n# {} tensors, {} ops, output `{}`. The forward mirrors the program one op per statement, in dataflow order;\n# every helper spells the LOGOS desugar of its op. Weights are raw little-endian files named by variable\n# (`<var>.f64` or `<var>.f32`, row-major, shape from MANIFEST) — see `load_weights`.\n",
1024        p.leaves.len(),
1025        p.ops.len(),
1026        p.output
1027    ));
1028    m.push_str("import argparse\nimport json\nimport math\nimport os\nimport sys\n\nimport numpy as np\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n");
1029    m.push_str(PY_HELPERS);
1030    m.push_str("\n\nLEAVES = {\n");
1031    for l in &p.leaves {
1032        let (r, c) = p.shapes[l];
1033        m.push_str(&format!(
1034            "    \"{l}\": (({r}, {c}), \"{}\", {}),\n",
1035            leaf_role(l),
1036            if p.real[l] { "\"real\"" } else { "\"int\"" }
1037        ));
1038    }
1039    m.push_str("}\n");
1040    m.push_str(&format!("OUTPUT = \"{}\"\n", p.output));
1041    m.push_str("\n\nclass LogosModule(nn.Module):\n");
1042    m.push_str("    \"\"\"The tensor program. Leaves present in `weights` become buffers; the rest are forward inputs.\"\"\"\n\n");
1043    m.push_str("    def __init__(self, weights):\n        super().__init__()\n        self.free = []\n        for name, (shape, role, kind) in LEAVES.items():\n            if name in weights:\n                self.register_buffer(name, weights[name].reshape(shape))\n            else:\n                self.free.append(name)\n\n");
1044    m.push_str("    def _write_state(self, name, value, inputs):\n        if name not in inputs:\n            with torch.no_grad():\n                getattr(self, name).copy_(value)\n\n");
1045    m.push_str("    def forward(self, **inputs):\n");
1046    m.push_str("        for name in self.free:\n            if name not in inputs:\n                raise KeyError(f\"forward needs `{name}` (not among the weights)\")\n");
1047    for l in &p.leaves {
1048        m.push_str(&format!(
1049            "        {l} = inputs[\"{l}\"] if \"{l}\" in inputs else self.{l}\n"
1050        ));
1051    }
1052    for (i, (out, kind)) in p.ops.iter().enumerate() {
1053        m.push_str(&format!("        # stage {i}: {out} = {}\n", kind.name()));
1054        let call = py_call(&p, kind)?;
1055        match kind {
1056            OpKind::CausalConv { state, .. } | OpKind::GatedDelta { state, .. } => {
1057                m.push_str(&format!("        {out}, {state} = {call}\n"));
1058                m.push_str(&format!(
1059                    "        self._write_state(\"{state}\", {state}, inputs)\n"
1060                ));
1061            }
1062            OpKind::SetRow { table, pos, row } => {
1063                m.push_str(&format!("        {table} = {table}.clone()\n        {table}[int({pos})] = {row}.reshape(-1)\n"));
1064                m.push_str(&format!(
1065                    "        self._write_state(\"{table}\", {table}, inputs)\n"
1066                ));
1067            }
1068            _ => m.push_str(&format!("        {out} = {call}\n")),
1069        }
1070    }
1071    m.push_str(&format!("        return {}\n", p.output));
1072    m.push_str("\n\ndef load_weights(directory, dtype):\n    \"\"\"Every leaf with a `<var>.f64` / `<var>.f32` file in `directory`, as tensors of `dtype`.\"\"\"\n    weights = {}\n    for name, (shape, role, kind) in LEAVES.items():\n        for ext, np_dtype in ((\".f64\", np.float64), (\".f32\", np.float32)):\n            path = os.path.join(directory, name + ext)\n            if os.path.exists(path):\n                arr = np.fromfile(path, dtype=np_dtype).reshape(shape)\n                weights[name] = torch.from_numpy(arr.copy()).to(dtype)\n                break\n    return weights\n");
1073    m.push_str("\n\ndef main():\n    ap = argparse.ArgumentParser(description=\"run the LOGOS tensor program in torch\")\n    ap.add_argument(\"--weights\", required=True, help=\"directory of <var>.f64/<var>.f32 files\")\n    ap.add_argument(\"--dtype\", default=\"float32\", choices=[\"float32\", \"float64\"])\n    ap.add_argument(\"--out\", default=None, help=\"write the output tensor as raw little-endian values of --dtype\")\n    args = ap.parse_args()\n    dtype = torch.float64 if args.dtype == \"float64\" else torch.float32\n    torch.set_default_dtype(dtype)\n    model = LogosModule(load_weights(args.weights, dtype))\n    if model.free:\n        raise SystemExit(f\"missing inputs: {model.free}\")\n    with torch.no_grad():\n        out = model()\n    flat = out.detach().to(dtype).reshape(-1).cpu().numpy()\n    if args.out:\n        flat.astype(np.float64 if args.dtype == \"float64\" else np.float32).tofile(args.out)\n    print(json.dumps({\"output\": OUTPUT, \"shape\": list(out.shape), \"first\": float(flat[0]), \"last\": float(flat[-1])}))\n\n\nif __name__ == \"__main__\":\n    main()\n");
1074
1075    // ── manifest.json ──
1076    let tensors: Vec<serde_json::Value> = p
1077        .sentences
1078        .iter()
1079        .filter_map(|s| match s {
1080            TensorSentence::Decl {
1081                var,
1082                rows,
1083                cols,
1084                real,
1085            } => Some(serde_json::json!({
1086                "var": var,
1087                "shape": [rows, cols],
1088                "dtype": if *real { "Real" } else { "Int" },
1089                "role": if p.leaves.contains(var) { leaf_role(var) } else { "computed" },
1090                "gguf": gguf_name(var, &p.attention_layers),
1091                "file": format!("{var}.f64"),
1092            })),
1093            _ => None,
1094        })
1095        .collect();
1096    let ops: Vec<serde_json::Value> = p
1097        .ops
1098        .iter()
1099        .enumerate()
1100        .map(|(i, (out, kind))| serde_json::json!({ "index": i, "out": out, "op": kind.name(), "inputs": kind.inputs(), "writes": kind.writes(), "torch": torch_spelling(kind.name()).unwrap_or("") }))
1101        .collect();
1102    let manifest = serde_json::json!({
1103        "schema": "logos.sambaflow.manifest",
1104        "version": 1,
1105        "provenance": "vendor-ingestion artifact emitted by LOGOS — not our compute path",
1106        "program": name,
1107        "inputs": p.leaves.iter().filter(|l| leaf_role(l) == "input").collect::<Vec<_>>(),
1108        "states": p.leaves.iter().filter(|l| leaf_role(l) == "state").collect::<Vec<_>>(),
1109        "output": p.output,
1110        "tensors": tensors,
1111        "ops": ops,
1112    });
1113    let manifest_json = serde_json::to_string_pretty(&manifest).expect("the manifest serializes");
1114
1115    // ── compile.py ──
1116    let mut c = String::new();
1117    c.push_str(VENDOR_HEADER);
1118    c.push('\n');
1119    c.push_str(&format!("{TEMPLATE_MARK}\n"));
1120    c.push_str(&format!(
1121        "# Compile `model.py` (the LOGOS tensor program `{name}`) for the RDU through SambaFlow, then run it.\n# Every call into the vendor SDK below is a TEMPLATE: the documented shape of the SambaFlow front end as\n# last publicly described, to be replaced by the actual entry points the day the SDK is in hand.\nimport argparse\nimport json\n\nimport torch\n\nfrom model import LogosModule, load_weights, LEAVES, OUTPUT\n\n\ndef main():\n    ap = argparse.ArgumentParser(description=\"SambaFlow compile/run scaffold for a LOGOS tensor program\")\n    ap.add_argument(\"command\", choices=[\"compile\", \"run\"])\n    ap.add_argument(\"--weights\", required=True)\n    ap.add_argument(\"--pef\", default=\"{name}.pef\")\n    args = ap.parse_args()\n    weights = load_weights(args.weights, torch.float32)\n    model = LogosModule(weights)\n    inputs = {{name: torch.zeros(LEAVES[name][0]) for name in model.free}}\n    {TEMPLATE_MARK}\n    from sambaflow import samba  # noqa: E402\n    {TEMPLATE_MARK}\n    samba.from_torch_model_(model)\n    if args.command == \"compile\":\n        {TEMPLATE_MARK}\n        samba.session.compile(model, inputs=list(inputs.values()), pef_name=args.pef)\n        print(json.dumps({{\"pef\": args.pef, \"output\": OUTPUT}}))\n    else:\n        {TEMPLATE_MARK}\n        out = samba.session.run(input_tensors=list(inputs.values()), output_tensors=[model(**inputs)], pef=args.pef)\n        print(json.dumps({{\"output\": OUTPUT, \"shape\": list(out[0].shape)}}))\n\n\nif __name__ == \"__main__\":\n    main()\n"
1122    ));
1123
1124    Ok(TorchArtifact {
1125        model_py: m,
1126        compile_py: c,
1127        manifest_json,
1128    })
1129}