diff --git a/acpu/bench/common.rs b/acpu/bench/common.rs
index f7ea3ef..c4dd470 100644
--- a/acpu/bench/common.rs
+++ b/acpu/bench/common.rs
@@ -179,59 +179,59 @@ extern "C" {
     pub fn vvtanhf(result: *mut f32, src: *const f32, n: *const i32);
 
     // vDSP
-    pub fn vDSP_sve(a: *const f32, stride: i32, result: *mut f32, n: u64);
-    pub fn vDSP_svesq(a: *const f32, stride: i32, result: *mut f32, n: u64);
-    pub fn vDSP_maxv(a: *const f32, stride: i32, result: *mut f32, n: u64);
-    pub fn vDSP_minv(a: *const f32, stride: i32, result: *mut f32, n: u64);
-    pub fn vDSP_vneg(a: *const f32, stride_a: i32, c: *mut f32, stride_c: i32, n: u64);
+    pub fn vDSP_sve(a: *const f32, stride: i64, result: *mut f32, n: u64);
+    pub fn vDSP_svesq(a: *const f32, stride: i64, result: *mut f32, n: u64);
+    pub fn vDSP_maxv(a: *const f32, stride: i64, result: *mut f32, n: u64);
+    pub fn vDSP_minv(a: *const f32, stride: i64, result: *mut f32, n: u64);
+    pub fn vDSP_vneg(a: *const f32, stride_a: i64, c: *mut f32, stride_c: i64, n: u64);
     pub fn vDSP_vadd(
         a: *const f32,
-        stride_a: i32,
+        stride_a: i64,
         b: *const f32,
-        stride_b: i32,
+        stride_b: i64,
         c: *mut f32,
-        stride_c: i32,
+        stride_c: i64,
         n: u64,
     );
     pub fn vDSP_vmul(
         a: *const f32,
-        stride_a: i32,
+        stride_a: i64,
         b: *const f32,
-        stride_b: i32,
+        stride_b: i64,
         c: *mut f32,
-        stride_c: i32,
+        stride_c: i64,
         n: u64,
     );
     pub fn vDSP_vsadd(
         a: *const f32,
-        stride_a: i32,
+        stride_a: i64,
         b: *const f32,
         c: *mut f32,
-        stride_c: i32,
+        stride_c: i64,
         n: u64,
     );
     pub fn vDSP_vsmul(
         a: *const f32,
-        stride_a: i32,
+        stride_a: i64,
         b: *const f32,
         c: *mut f32,
-        stride_c: i32,
+        stride_c: i64,
         n: u64,
     );
     pub fn vDSP_vsdiv(
         a: *const f32,
-        stride_a: i32,
+        stride_a: i64,
         b: *const f32,
         c: *mut f32,
-        stride_c: i32,
+        stride_c: i64,
         n: u64,
     );
     pub fn vDSP_svdiv(
         a: *const f32,
         b: *const f32,
-        stride_b: i32,
+        stride_b: i64,
         c: *mut f32,
-        stride_c: i32,
+        stride_c: i64,
         n: u64,
     );
 }
diff --git a/acpu/bench/crypto.rs b/acpu/bench/crypto.rs
index 7e5136d..0844334 100644
--- a/acpu/bench/crypto.rs
+++ b/acpu/bench/crypto.rs
@@ -4,7 +4,6 @@
 #[path = "common.rs"]
 mod common;
 use common::*;
-use std::time::Instant;
 
 #[link(name = "System", kind = "dylib")]
 extern "C" {
diff --git a/acpu/bench/integer.rs b/acpu/bench/integer.rs
index 1adf813..af1868b 100644
--- a/acpu/bench/integer.rs
+++ b/acpu/bench/integer.rs
@@ -4,7 +4,6 @@
 #[path = "common.rs"]
 mod common;
 use common::*;
-use std::time::Instant;
 
 const N: usize = 4096;
 
@@ -59,12 +58,12 @@ fn main() {
     let mut score = Score::vs("scalar");
 
     // ── test data ───────────────────────────────────────────────────────
-    let i32_a: Vec<i32> = (0..N).map(|i| (i as i32 * 7 - 2000)).collect();
-    let i32_b: Vec<i32> = (0..N).map(|i| (i as i32 * 3 + 500)).collect();
+    let i32_a: Vec<i32> = (0..N).map(|i| i as i32 * 7 - 2000).collect();
+    let i32_b: Vec<i32> = (0..N).map(|i| i as i32 * 3 + 500).collect();
     let i8_a: Vec<i8> = (0..N).map(|i| ((i * 7) % 255) as i8).collect();
     let i8_b: Vec<i8> = (0..N).map(|i| ((i * 13) % 255) as i8).collect();
-    let i16_a: Vec<i16> = (0..N).map(|i| (i as i16 * 5 - 2000)).collect();
-    let i16_b: Vec<i16> = (0..N).map(|i| (i as i16 * 3 + 1000)).collect();
+    let i16_a: Vec<i16> = (0..N).map(|i| i as i16 * 5 - 2000).collect();
+    let i16_b: Vec<i16> = (0..N).map(|i| i as i16 * 3 + 1000).collect();
     let mut dst_i32 = vec![0i32; N];
     let mut acc_i32 = vec![0i32; N];
 
diff --git a/acpu/bench/numeric.rs b/acpu/bench/numeric.rs
index faf0f8d..b1f83c4 100644
--- a/acpu/bench/numeric.rs
+++ b/acpu/bench/numeric.rs
@@ -7,10 +7,7 @@ use common::*;
 
 #[link(name = "Accelerate", kind = "framework")]
 extern "C" {
-    // vDSP element-wise multiply (used as baseline for complex)
-    fn vDSP_vmul(a: *const f32, ia: i64, b: *const f32, ib: i64, c: *mut f32, ic: i64, n: u64);
     fn vDSP_vsub(b: *const f32, ib: i64, a: *const f32, ia: i64, c: *mut f32, ic: i64, n: u64);
-    fn vDSP_vadd(a: *const f32, ia: i64, b: *const f32, ib: i64, c: *mut f32, ic: i64, n: u64);
 }
 
 const N: usize = 4096;
diff --git a/acpu/bench/summary.rs b/acpu/bench/summary.rs
index 3f8307a..51f1465 100644
--- a/acpu/bench/summary.rs
+++ b/acpu/bench/summary.rs
@@ -5,7 +5,6 @@
 #[path = "common.rs"]
 mod common;
 use common::*;
-use std::time::Instant;
 
 // ── Pure Rust Goldilocks (nebu cross-platform baseline, no acpu asm) ──
 mod gl_pure {
@@ -2051,7 +2050,7 @@ fn main() {
 
     // PMULL (hardware vs scalar carry-less multiply)
     let pmull_iters = 1_000_000u64;
-    let mut pmull_a = 0xDEADBEEFCAFEBABEu64;
+    let pmull_a = 0xDEADBEEFCAFEBABEu64;
     let pmull_b = 0x1234567890ABCDEFu64;
     let t_a = best_of(
         || {
diff --git a/acpu/bench/zk.rs b/acpu/bench/zk.rs
index 2ee00e0..4dc1175 100644
--- a/acpu/bench/zk.rs
+++ b/acpu/bench/zk.rs
@@ -19,7 +19,7 @@ fn main() {
     println!("Goldilocks p = 2^64 - 2^32 + 1");
     println!();
 
-    let mut score = Score::new();
+    let score = Score::new();
     let a: Vec<u64> = (0..N)
         .map(|i| (i as u64).wrapping_mul(0x9E3779B97F4A7C15) | 1)
         .collect();
diff --git a/acpu/examples/amx_reverse.rs b/acpu/examples/amx_reverse.rs
index fef15d2..17ceda2 100644
--- a/acpu/examples/amx_reverse.rs
+++ b/acpu/examples/amx_reverse.rs
@@ -56,41 +56,6 @@ impl Snapshot {
         s
     }
 
-    fn diff(&self, other: &Snapshot) -> Vec<String> {
-        let mut diffs = Vec::new();
-        for r in 0..8 {
-            for i in 0..16 {
-                if self.x[r][i] != other.x[r][i] {
-                    diffs.push(format!(
-                        "X[{}][{}]: {:08x}→{:08x}",
-                        r, i, other.x[r][i], self.x[r][i]
-                    ));
-                }
-            }
-        }
-        for r in 0..8 {
-            for i in 0..16 {
-                if self.y[r][i] != other.y[r][i] {
-                    diffs.push(format!(
-                        "Y[{}][{}]: {:08x}→{:08x}",
-                        r, i, other.y[r][i], self.y[r][i]
-                    ));
-                }
-            }
-        }
-        for r in 0..64 {
-            for i in 0..16 {
-                if self.z[r][i] != other.z[r][i] {
-                    diffs.push(format!(
-                        "Z[{}][{}]: {:08x}→{:08x}",
-                        r, i, other.z[r][i], self.z[r][i]
-                    ));
-                }
-            }
-        }
-        diffs
-    }
-
     fn changed_regs(&self, other: &Snapshot) -> (bool, bool, bool) {
         let mut x_changed = false;
         let mut y_changed = false;
diff --git a/acpu/examples/pair_test.rs b/acpu/examples/pair_test.rs
index 77a97c8..0686fcd 100644
--- a/acpu/examples/pair_test.rs
+++ b/acpu/examples/pair_test.rs
@@ -7,7 +7,6 @@ fn main() {
         amx_set();
 
         const PAIR: u64 = 1u64 << 62;
-        let fma_first: u64 = 1 << 27; // skip_z, X[0], Y[0], tile 0
         let fma_x1: u64 = (1 << 27) | (64 << 10); // X[1], Y[0], tile 0
 
         #[repr(align(128))]
diff --git a/acpu/examples/trace64.rs b/acpu/examples/trace64.rs
index a521f77..29e340e 100644
--- a/acpu/examples/trace64.rs
+++ b/acpu/examples/trace64.rs
@@ -286,7 +286,6 @@ fn main() {
             }
 
             // Direct B loads with stride=N*4, no packing
-            let b_stride = N * 4; // bytes
             for p in 0..N {
                 // LDY: packed A column
                 amx_op::<OP_LDY>(ap.add(p * 64) as u64);
diff --git a/acpu/src/crypto/mod.rs b/acpu/src/crypto/mod.rs
index 0aefa1e..e1e7a34 100644
--- a/acpu/src/crypto/mod.rs
+++ b/acpu/src/crypto/mod.rs
@@ -359,7 +359,7 @@ mod tests {
     fn aes128_key_expand(key: &[u8; 16]) -> Vec<[u8; 16]> {
         let rcon: [u8; 10] = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36];
 
-        let mut w = vec![0u32; 44];
+        let mut w = [0u32; 44];
         for i in 0..4 {
             w[i] = u32::from_be_bytes([key[4 * i], key[4 * i + 1], key[4 * i + 2], key[4 * i + 3]]);
         }
diff --git a/acpu/src/field/goldilocks.rs b/acpu/src/field/goldilocks.rs
index 6530221..a083023 100644
--- a/acpu/src/field/goldilocks.rs
+++ b/acpu/src/field/goldilocks.rs
@@ -153,7 +153,7 @@ pub fn gl_inv(x: u64) -> u64 {
 
 // ── batched operations (interleaved for latency hiding) ──────────────────
 
-/// Batch field multiply: dst[i] = a[i] * b[i] mod p.
+/// Batch field multiply: `dst[i] = a[i] * b[i] mod p`.
 ///
 /// Hand-scheduled asm interleaves 4 independent mul+umulh chains
 /// to hide the 4-cycle multiply latency on M1 P-cores.
@@ -296,12 +296,12 @@ mod tests {
     #[test]
     fn test_pow7_x16() {
         let mut state = [0u64; 16];
-        for i in 0..16 {
-            state[i] = (i as u64 + 1) * 3;
+        for (i, value) in state.iter_mut().enumerate() {
+            *value = (i as u64 + 1) * 3;
         }
         let mut expected = state;
-        for i in 0..16 {
-            expected[i] = gl_pow7(expected[i]);
+        for value in &mut expected {
+            *value = gl_pow7(*value);
         }
         gl_pow7_x16(&mut state);
         assert_eq!(state, expected);
diff --git a/acpu/src/field/permute.rs b/acpu/src/field/permute.rs
index dbc95f3..c1a75c1 100644
--- a/acpu/src/field/permute.rs
+++ b/acpu/src/field/permute.rs
@@ -143,16 +143,16 @@ mod tests {
 
     fn test_rc() -> [u64; 144] {
         let mut rc = [0u64; 144];
-        for i in 0..144 {
-            rc[i] = (i as u64 + 1).wrapping_mul(0x9E3779B97F4A7C15);
+        for (i, value) in rc.iter_mut().enumerate() {
+            *value = (i as u64 + 1).wrapping_mul(0x9E3779B97F4A7C15);
         }
         rc
     }
 
     fn test_diag() -> [u64; 16] {
         let mut d = [0u64; 16];
-        for i in 0..16 {
-            d[i] = (i as u64 + 2).wrapping_mul(0x517CC1B727220A95);
+        for (i, value) in d.iter_mut().enumerate() {
+            *value = (i as u64 + 2).wrapping_mul(0x517CC1B727220A95);
         }
         d
     }
diff --git a/acpu/src/gemm/matvec.rs b/acpu/src/gemm/matvec.rs
index cd12e6d..2503bdd 100644
--- a/acpu/src/gemm/matvec.rs
+++ b/acpu/src/gemm/matvec.rs
@@ -7,7 +7,7 @@
 #[cfg(target_arch = "aarch64")]
 use core::arch::aarch64::*;
 
-/// Matrix-vector multiply: c[n] += a[k] * b[k][n], row-major B.
+/// Matrix-vector multiply: `c[n] += a[k] * b[k][n]`, row-major B.
 #[cfg(target_arch = "aarch64")]
 pub fn matvec_f32(a: &[f32], b: &[f32], c: &mut [f32], n: usize, k: usize) {
     debug_assert_eq!(a.len(), k);
diff --git a/acpu/src/gemm/mod.rs b/acpu/src/gemm/mod.rs
index 8faa097..ccf8665 100644
--- a/acpu/src/gemm/mod.rs
+++ b/acpu/src/gemm/mod.rs
@@ -1091,7 +1091,6 @@ fn pack_b_32(b: &[f32], ldb: usize, pc: usize, jc: usize, kc: usize, nc: usize,
 /// Odd/rem A × 32-wide B → two 16×16 kernels per B strip.
 #[cfg(target_arch = "aarch64")]
 #[allow(clippy::too_many_arguments)]
-#[allow(clippy::too_many_arguments)]
 pub(super) fn gebp_kernel(
     a_pack: &[f32],
     b_pack: &[f32],
diff --git a/acpu/src/matrix/fma.rs b/acpu/src/matrix/fma.rs
index 144c326..8ec1d59 100644
--- a/acpu/src/matrix/fma.rs
+++ b/acpu/src/matrix/fma.rs
@@ -98,7 +98,7 @@ impl Default for FmaOp {
 // Convenience constructors for common GEMM patterns
 // ---------------------------------------------------------------------------
 
-/// First rank-1 update: Z[tile] = X[xr] × Y[yr] (no accumulate).
+/// First rank-1 update: `Z[tile] = X[xr] × Y[yr]` (no accumulate).
 #[inline]
 pub const fn fma_first(xr: XRow, yr: YRow, tile: u8) -> u64 {
     FmaOp::new()
@@ -109,7 +109,7 @@ pub const fn fma_first(xr: XRow, yr: YRow, tile: u8) -> u64 {
         .build()
 }
 
-/// Subsequent rank-1 update: Z[tile] += X[xr] × Y[yr].
+/// Subsequent rank-1 update: `Z[tile] += X[xr] × Y[yr]`.
 #[inline]
 pub const fn fma_acc(xr: XRow, yr: YRow, tile: u8) -> u64 {
     FmaOp::new().x(xr).y(yr).z_tile(tile).build()
diff --git a/acpu/src/matrix/mod.rs b/acpu/src/matrix/mod.rs
index bdee3d5..501f04e 100644
--- a/acpu/src/matrix/mod.rs
+++ b/acpu/src/matrix/mod.rs
@@ -36,11 +36,9 @@ pub struct Matrix {
 impl Matrix {
     /// Activate the AMX coprocessor on the current thread.
     ///
-    /// # Errors
-    ///
-    /// Returns [`CpuError::AmxSetFailed`] if the current hardware does
-    /// not support AMX (non-Apple-Silicon or virtualised without AMX
-    /// passthrough).
+    /// The current implementation returns `Ok` after executing AMX_SET.
+    /// The caller must establish AMX availability with the hardware probe first;
+    /// unsupported hardware can trap instead of returning an error.
     ///
     /// # Safety
     ///
diff --git a/acpu/src/matrix/tile.rs b/acpu/src/matrix/tile.rs
index e4e38b5..9d6730f 100644
--- a/acpu/src/matrix/tile.rs
+++ b/acpu/src/matrix/tile.rs
@@ -818,10 +818,10 @@ pub unsafe fn microkernel_32x32_gebp(
 /// 2×2 Z tile layout. AMX pair loads (bit 62): 128 bytes → 2 registers.
 /// **6 ops per k-step**: 1 LDX(pair) + 1 LDY(pair) + 4 FMA.
 ///
-/// `a_pair`: interleaved A pack — for column p: strip0[p] at offset p*128,
-///   strip1[p] at p*128+64. Must be 128-byte aligned.
+/// `a_pair`: interleaved A pack — for column p: `strip0[p]` at offset p*128,
+///   `strip1[p]` at p*128+64. Must be 128-byte aligned.
 /// `b0`: B row-major (columns 0:32 contiguous). Must be 64-byte aligned.
-///   Pair LDX loads cols 0:16 → X[0], cols 16:32 → X[1].
+///   Pair LDX loads cols 0:16 → `X[0]`, cols 16:32 → `X[1]`.
 /// `bs`: B row stride in bytes.
 ///
 /// # Safety
diff --git a/acpu/src/matrix/tile_f16.rs b/acpu/src/matrix/tile_f16.rs
index ebbd04c..4918fa1 100644
--- a/acpu/src/matrix/tile_f16.rs
+++ b/acpu/src/matrix/tile_f16.rs
@@ -70,7 +70,7 @@ pub unsafe fn store_c_f16(c: *mut u16, ldc: usize, tile: u8) {
 /// a_panel: packed fp16 [k × 32] (each k-step = 64 bytes = 32 fp16)
 /// b_panel: packed fp16 [k × 32] (each k-step = 64 bytes = 32 fp16)
 ///
-/// Computes: Z[32×32] += sum_p( A[p] ⊗ B[p] )
+/// Computes: `Z[32×32] += sum_p( A[p] ⊗ B[p] )`
 ///
 /// # Safety
 /// AMX must be active. Panels must be 64-byte aligned with `k*64` readable bytes.
diff --git a/acpu/src/numeric/bf16.rs b/acpu/src/numeric/bf16.rs
index 4fcc3e4..1ed610c 100644
--- a/acpu/src/numeric/bf16.rs
+++ b/acpu/src/numeric/bf16.rs
@@ -164,7 +164,7 @@ mod tests {
             0.0f32,
             1.0,
             -1.0,
-            3.14,
+            f32::from_bits(0x4048_f5c3), // original decimal 3.14 test input
             -100.0,
             f32::INFINITY,
             f32::NEG_INFINITY,
diff --git a/acpu/src/sparse/chebyshev.rs b/acpu/src/sparse/chebyshev.rs
index 163e437..23048e7 100644
--- a/acpu/src/sparse/chebyshev.rs
+++ b/acpu/src/sparse/chebyshev.rs
@@ -18,7 +18,7 @@ use super::admission::Csr;
 /// Modified Bessel function I_k(τ) via Miller's backward recurrence.
 ///
 /// Uses the identity: I_0(τ) + 2 * Σ_{j=1}^∞ I_j(τ) = exp(τ).
-/// In Miller's method we compute un-normalized ratios f[j] ∝ I_j(τ) by
+/// In Miller's method we compute un-normalized ratios `f[j] ∝ I_j(τ)` by
 /// backward recurrence from k_max, then normalize so the above sum holds.
 pub fn bessel_i(k: usize, tau: f32) -> f32 {
     if tau == 0.0 {
@@ -183,7 +183,8 @@ pub fn chebyshev_matvec(
     csr.set(&az, t1);
     // Step 3: t1[i] = −d_inv_sqrt[i] * t1[i]
     for i in 0..n {
-        t1[i] = -d_inv_sqrt[i] * t1[i];
+        let scaled = -d_inv_sqrt[i] * t1[i];
+        t1[i] = scaled;
     }
 
     // Accumulate y = c_0 T_0 + c_1 T_1
@@ -204,8 +205,7 @@ pub fn chebyshev_matvec(
     //
     // (k starts at 2, so k==2 is even: T_0 in t0, T_1 in t1 → write T_2 into t0)
 
-    for k in 2..=order {
-        let ck = coeffs[k];
+    for (k, &ck) in coeffs.iter().enumerate().skip(2) {
         if k % 2 == 0 {
             // T_{k-2} in t0, T_{k-1} in t1. Compute T_k into t0.
             // az = D^{-½} t1
@@ -259,7 +259,7 @@ mod tests {
         assert!((bessel_i(0, 0.0) - 1.0).abs() < 1e-5, "I_0(0)");
         // I_0(1) ≈ 1.2660658777520082
         assert!(
-            (bessel_i(0, 1.0) - 1.266_065_9).abs() < 1e-4,
+            (bessel_i(0, 1.0) - 1.266_066).abs() < 1e-4,
             "I_0(1) = {}",
             bessel_i(0, 1.0)
         );
diff --git a/acpu/src/sparse/mod.rs b/acpu/src/sparse/mod.rs
index 15118d9..7654cd6 100644
--- a/acpu/src/sparse/mod.rs
+++ b/acpu/src/sparse/mod.rs
@@ -2,7 +2,7 @@
 //!
 //! CSR matvec: y = A·x where A is sparse CSR. For the bostrom graph (avg
 //! degree ~1.85) most rows are 1–3 entries — AMX offers no advantage here.
-//! NEON prefetch hides gather latency from the scattered x[col_idx[j]] loads.
+//! NEON prefetch hides gather latency from the scattered `x[col_idx[j]]` loads.
 
 mod admission;
 pub mod chebyshev;
@@ -12,7 +12,7 @@ use core::arch::aarch64::*;
 
 /// y += A·x  (accumulate into y).
 ///
-/// A in CSR format: row i spans col_idx[row_ptr[i]..row_ptr[i+1]]
+/// A in CSR format: row i spans `col_idx[row_ptr[i]..row_ptr[i+1]]`.
 /// with corresponding weights values[...].
 ///
 /// # Panics
@@ -53,8 +53,8 @@ fn inner(row_ptr: &[u32], col_idx: &[u32], values: &[f32], x: &[f32], y: &mut [f
             let mut acc = 0.0f32;
 
             // Prefetch the x entries we'll need for this row.
-            for pf in 0..len.min(PF) {
-                let ptr = x.as_ptr().add(cols[pf] as usize);
+            for &column in cols.iter().take(PF) {
+                let ptr = x.as_ptr().add(column as usize);
                 // PRFM PLDL1KEEP — bring into L1 dcache.
                 core::arch::asm!(
                     "prfm pldl1keep, [{ptr}]",
@@ -189,8 +189,8 @@ mod tests {
             expected0
         );
         // y[i] = x[0] = 0 for i in 1..n
-        for i in 1..n {
-            assert!(y[i].abs() < 1e-5, "y[{i}]={}", y[i]);
+        for (i, value) in y.iter().enumerate().skip(1) {
+            assert!(value.abs() < 1e-5, "y[{i}]={value}");
         }
     }
 }
diff --git a/acpu/src/vector/integer.rs b/acpu/src/vector/integer.rs
index 471b177..fee6bbb 100644
--- a/acpu/src/vector/integer.rs
+++ b/acpu/src/vector/integer.rs
@@ -280,7 +280,7 @@ pub fn macc_i16(acc: &mut [i32], a: &[i16], b: &[i16]) {
 
 // ── i32 elementwise ─────────────────────────────────────────────────────────
 
-/// Elementwise i32 add: dst[i] = a[i] + b[i]. 16-wide.
+/// Elementwise i32 add: `dst[i] = a[i] + b[i]`. 16-wide.
 pub fn add_i32(dst: &mut [i32], a: &[i32], b: &[i32]) {
     let len = dst.len().min(a.len()).min(b.len());
     let mut i = 0;
@@ -311,7 +311,7 @@ pub fn add_i32(dst: &mut [i32], a: &[i32], b: &[i32]) {
     }
 }
 
-/// Elementwise i32 multiply: dst[i] = a[i] * b[i]. 32-wide.
+/// Elementwise i32 multiply: `dst[i] = a[i] * b[i]`. 32-wide.
 pub fn mul_i32(dst: &mut [i32], a: &[i32], b: &[i32]) {
     let len = dst.len().min(a.len()).min(b.len());
     let mut i = 0;
@@ -408,7 +408,7 @@ mod tests {
 
     #[test]
     fn test_sum_i32() {
-        let v: Vec<i32> = (0..4096).map(|i| (i % 100) as i32 - 50).collect();
+        let v: Vec<i32> = (0..4096).map(|i| (i % 100) - 50).collect();
         let expected: i64 = v.iter().map(|&x| x as i64).sum();
         assert_eq!(sum_i32(&v), expected);
     }
diff --git a/acpu/src/vector/integer_fused.rs b/acpu/src/vector/integer_fused.rs
index f2c3584..2c6aa7d 100644
--- a/acpu/src/vector/integer_fused.rs
+++ b/acpu/src/vector/integer_fused.rs
@@ -6,7 +6,7 @@
 #[cfg(target_arch = "aarch64")]
 use core::arch::aarch64::*;
 
-/// Sum of absolute differences: sum(|a[i] - b[i]|).
+/// Sum of absolute differences: `sum(|a[i] - b[i]|)`.
 /// Single pass — reads both arrays once, no intermediate storage.
 /// Uses UABD + UADALP chain (unsigned absolute difference + pairwise add long).
 pub fn sad_u8(a: &[u8], b: &[u8]) -> u64 {
@@ -57,7 +57,7 @@ pub fn sad_u8(a: &[u8], b: &[u8]) -> u64 {
     }
 }
 
-/// Sum of squared differences: sum((a[i] - b[i])²) for i32 slices.
+/// Sum of squared differences: `sum((a[i] - b[i])²)` for i32 slices.
 /// Single pass — no intermediate array. Widens to i64 to avoid overflow.
 pub fn ssd_i32(a: &[i32], b: &[i32]) -> i64 {
     assert_eq!(a.len(), b.len(), "ssd_i32: length mismatch");
@@ -108,7 +108,7 @@ pub fn ssd_i32(a: &[i32], b: &[i32]) -> i64 {
     }
 }
 
-/// Scale and accumulate: acc[i] += a[i] * scale.
+/// Scale and accumulate: `acc[i] += a[i] * scale`.
 /// Single pass with widening: i16 × i16 → i32 accumulated.
 pub fn scale_acc_i16(acc: &mut [i32], a: &[i16], scale: i16) {
     let len = acc.len().min(a.len());
@@ -147,7 +147,7 @@ pub fn scale_acc_i16(acc: &mut [i32], a: &[i16], scale: i16) {
     }
 }
 
-/// Fused sum of absolute values: sum(|x[i]|) for i8.
+/// Fused sum of absolute values: `sum(|x[i]|)` for i8.
 /// Combines abs + widen + accumulate in one pass.
 pub fn sum_abs_i8(x: &[i8]) -> u64 {
     let len = x.len();
diff --git a/acpu/src/vector/media.rs b/acpu/src/vector/media.rs
index 1958b24..4be53b2 100644
--- a/acpu/src/vector/media.rs
+++ b/acpu/src/vector/media.rs
@@ -383,7 +383,7 @@ mod tests {
     #[test]
     fn test_rgb_to_yuv_known() {
         let mut yuv = vec![0u8; 48];
-        rgb_to_yuv(&mut yuv, &vec![0u8; 48]);
+        rgb_to_yuv(&mut yuv, &[0u8; 48]);
         for i in 0..16 {
             assert_eq!((yuv[i * 3], yuv[i * 3 + 1], yuv[i * 3 + 2]), (16, 128, 128));
         }
@@ -414,8 +414,8 @@ mod tests {
         let mut out = vec![0u8; 3];
         rgb_to_yuv(&mut yuv, &[128, 128, 128]);
         yuv_to_rgb(&mut out, &yuv);
-        for c in 0..3 {
-            assert!((128i32 - out[c] as i32).abs() <= 2, "ch {}: {}", c, out[c]);
+        for (c, &value) in out.iter().enumerate() {
+            assert!((128i32 - value as i32).abs() <= 2, "ch {c}: {value}");
         }
     }
 
@@ -464,7 +464,7 @@ mod tests {
     #[test]
     fn test_resize_downsample() {
         let mut dst = vec![0.0f32; 4];
-        resize_bilinear_f32(&mut dst, &vec![7.5f32; 16], 4, 4, 2, 2);
+        resize_bilinear_f32(&mut dst, &[7.5f32; 16], 4, 4, 2, 2);
         assert!(dst.iter().all(|&v| (v - 7.5).abs() < 1e-4));
     }
 }
diff --git a/acpu/src/vector/render.rs b/acpu/src/vector/render.rs
index 7a48e5d..9fa0db7 100644
--- a/acpu/src/vector/render.rs
+++ b/acpu/src/vector/render.rs
@@ -9,7 +9,7 @@ use core::arch::aarch64::*;
 // rsqrt: fast inverse square root via FRSQRTE + 1 Newton-Raphson step
 // ---------------------------------------------------------------------------
 
-/// In-place fast inverse square root: x[i] = 1/sqrt(x[i]).
+/// In-place fast inverse square root: `x[i] = 1/sqrt(x[i])`.
 /// Uses NEON FRSQRTE + one Newton-Raphson refinement step.
 pub fn rsqrt(x: &mut [f32]) {
     let len = x.len();
@@ -58,7 +58,7 @@ pub fn rsqrt(x: &mut [f32]) {
     }
 }
 
-/// Fast inverse square root into separate buffer: dst[i] = 1/sqrt(src[i]).
+/// Fast inverse square root into separate buffer: `dst[i] = 1/sqrt(src[i])`.
 /// Panics if lengths differ.
 pub fn rsqrt_to(src: &[f32], dst: &mut [f32]) {
     assert_eq!(src.len(), dst.len(), "rsqrt_to: length mismatch");
@@ -113,7 +113,7 @@ pub fn rsqrt_to(src: &[f32], dst: &mut [f32]) {
 // recip: fast reciprocal via FRECPE + 1 Newton-Raphson step
 // ---------------------------------------------------------------------------
 
-/// In-place fast reciprocal: x[i] = 1/x[i].
+/// In-place fast reciprocal: `x[i] = 1/x[i]`.
 /// Uses NEON FRECPE + one Newton-Raphson refinement step.
 pub fn recip(x: &mut [f32]) {
     let len = x.len();
@@ -285,7 +285,7 @@ pub fn clamp_to(src: &[f32], dst: &mut [f32], lo: f32, hi: f32) {
 // lerp: linear interpolation dst = a + t*(b - a)
 // ---------------------------------------------------------------------------
 
-/// Linear interpolation: dst[i] = a[i] + t * (b[i] - a[i]).
+/// Linear interpolation: `dst[i] = a[i] + t * (b[i] - a[i])`.
 /// Panics if lengths differ.
 pub fn lerp(dst: &mut [f32], a: &[f32], b: &[f32], t: f32) {
     assert_eq!(a.len(), b.len(), "lerp: a/b length mismatch");
diff --git a/acpu/src/vector/rope.rs b/acpu/src/vector/rope.rs
index c096bba..c3c4a85 100644
--- a/acpu/src/vector/rope.rs
+++ b/acpu/src/vector/rope.rs
@@ -12,9 +12,11 @@ use core::arch::aarch64::*;
 /// `pos` is the token position.
 ///
 /// For each pair (x0, x1) with frequency f:
+/// ```text
 ///   theta = pos * f
 ///   out[2*i]   = x0 * cos(theta) - x1 * sin(theta)
 ///   out[2*i+1] = x0 * sin(theta) + x1 * cos(theta)
+/// ```
 pub fn rotate(out: &mut [f32], x: &[f32], freqs: &[f32], pos: usize) {
     let dim = x.len();
     assert!(dim.is_multiple_of(2), "rotate: dimension must be even");
diff --git a/acpu/tests/input_admission.rs b/acpu/tests/input_admission.rs
index 816cb2f..55cc956 100644
--- a/acpu/tests/input_admission.rs
+++ b/acpu/tests/input_admission.rs
@@ -16,12 +16,13 @@ fn rejects(message: &str, f: impl FnOnce()) {
 }
 
 type Matvec = fn(&[u32], &[u32], &[f32], &[f32], &mut [f32]);
+type CsrCase<'a> = (&'a [u32], &'a [u32], &'a [f32], usize, &'a str);
 
 #[test]
 fn csr_rejects_every_malformed_shape_before_output_mutation() {
     // Partition, count, pointer, scalar-tail and late-row failures. Every case
     // runs through both public entry points, including the zeroing variant.
-    let cases: &[(&[u32], &[u32], &[f32], usize, &str)] = &[
+    let cases: &[CsrCase<'_>] = &[
         (&[], &[], &[], 0, "row_ptr must be nonempty"),
         (&[1, 1], &[0], &[2.0], 1, "row_ptr must start at zero"),
         (&[0, 2, 1], &[0], &[2.0], 2, "row_ptr must be nondecreasing"),
diff --git a/acpu/tests/integration.rs b/acpu/tests/integration.rs
index 369a37f..6643af1 100644
--- a/acpu/tests/integration.rs
+++ b/acpu/tests/integration.rs
@@ -97,7 +97,14 @@ fn fp16_bulk_1024() {
 
 #[test]
 fn bf16_roundtrip() {
-    for &v in &[0.0f32, 1.0, -1.0, 3.14, -100.0, 256.0] {
+    for &v in &[
+        0.0f32,
+        1.0,
+        -1.0,
+        f32::from_bits(0x4048_f5c3), // original decimal 3.14 test input
+        -100.0,
+        256.0,
+    ] {
         let back = bf16_mod::bf16_to_f32(bf16_mod::f32_to_bf16(v));
         if v == 0.0 {
             assert_eq!(back, 0.0);
@@ -294,7 +301,7 @@ fn softmax_equal() {
 fn rmsnorm_unit_weight() {
     let x = vec![1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
     let mut out = vec![0.0f32; 8];
-    softmax::normalize(&mut out, &x, &vec![1.0; 8], 1e-5);
+    softmax::normalize(&mut out, &x, &[1.0; 8], 1e-5);
     let rms2: f32 = out.iter().map(|v| v * v).sum::<f32>() / 8.0;
     assert!((rms2 - 1.0).abs() < 1e-3);
 }
@@ -302,7 +309,7 @@ fn rmsnorm_unit_weight() {
 #[test]
 fn rmsnorm_scaling() {
     let mut out = vec![0.0f32; 16];
-    softmax::normalize(&mut out, &vec![2.0; 16], &vec![3.0; 16], 1e-5);
+    softmax::normalize(&mut out, &[2.0; 16], &[3.0; 16], 1e-5);
     for &v in &out {
         assert!((v - 3.0).abs() < 1e-3);
     }
@@ -362,7 +369,7 @@ fn sgemm_vs_naive() {
     const S: usize = 4;
     let a: Vec<f32> = (0..S * S).map(|i| (i % 5) as f32 * 0.3).collect();
     let b: Vec<f32> = (0..S * S).map(|i| (i % 7) as f32 * 0.2).collect();
-    let mut c_ref = vec![0.0f32; S * S];
+    let mut c_ref = [0.0f32; S * S];
     for i in 0..S {
         for j in 0..S {
             let mut acc = 0.0f32;
@@ -654,8 +661,8 @@ fn amx_fma32_outer_product() {
             amx_op::<OP_LDZ>((zero_buf as u64) | ((row as u64) << 56));
         }
 
-        amx_op::<OP_LDX>((x_buf as u64) | (0u64 << 56));
-        amx_op::<OP_LDY>((y_buf as u64) | (0u64 << 56));
+        amx_op::<OP_LDX>(x_buf as u64);
+        amx_op::<OP_LDY>(y_buf as u64);
 
         let op = fma_first(XRow::new_unchecked(0), YRow::new_unchecked(0), 0);
         amx_op::<OP_FMA32>(op);
diff --git a/aruminium/CLAUDE.md b/aruminium/CLAUDE.md
index ad0f195..c90c190 100644
--- a/aruminium/CLAUDE.md
+++ b/aruminium/CLAUDE.md
@@ -100,7 +100,7 @@ src/                  core library (zero deps)
   sync.rs             Fence, Event, SharedEvent
   texture.rs          Texture
   probe.rs            metal_probe binary — 5-level capability probe
-examples/             runnable demos (vecadd, matmul)
+examples/             runnable demos (vecadd, aruminium_matmul)
 benches/              separate crate with heavy deps (bench, compare)
 docs/                 documentation (tutorial, guide, explanations)
 specs/                specification (source of truth)
diff --git a/aruminium/Cargo.toml b/aruminium/Cargo.toml
index eda3c73..3d12ff9 100644
--- a/aruminium/Cargo.toml
+++ b/aruminium/Cargo.toml
@@ -1,5 +1,6 @@
 [package]
 name = "aruminium"
+autobenches = false # benches/ is the separate metal-benches workspace package.
 version.workspace = true
 edition.workspace = true
 license.workspace = true
@@ -29,8 +30,8 @@ name = "vecadd"
 path = "examples/vecadd.rs"
 
 example
-name = "matmul"
-path = "examples/matmul.rs"
+name = "aruminium_matmul"
+path = "examples/aruminium_matmul.rs"
 
 example
 name = "triangle"
diff --git a/aruminium/README.md b/aruminium/README.md
index aa4c65d..1fc0a56 100644
--- a/aruminium/README.md
+++ b/aruminium/README.md
@@ -124,7 +124,7 @@ aruminium::cast_f16_f32(&mut [f32], &[u16])  // bulk NEON
 ```text
 cargo build --release
 cargo run --example vecadd
-cargo run --example matmul
+cargo run --example aruminium_matmul
 cargo run --release -p metal-benches --bin bench

diff --git a/aruminium/benches/objc2.rs b/aruminium/benches/objc2.rs index 2578d18..155dbd6 100644 --- a/aruminium/benches/objc2.rs +++ b/aruminium/benches/objc2.rs @@ -300,8 +300,12 @@ pub fn render_pass_overhead(iters: usize) -> f64 { let queue = dev.newCommandQueue().unwrap(); let src = NSString::from_str(TRIANGLE_SRC); let lib = dev.newLibraryWithSource_options_error(&src, None).unwrap();

  • let vfn = lib.newFunctionWithName(&NSString::from_str("vmain")).unwrap();
  • let ffn = lib.newFunctionWithName(&NSString::from_str("fmain")).unwrap();
  • let vfn = lib

  •    .newFunctionWithName(&NSString::from_str("vmain"))
    
  •    .unwrap();
    
  • let ffn = lib

  •    .newFunctionWithName(&NSString::from_str("fmain"))
    
  •    .unwrap();
    

    let pipe_desc = MTLRenderPipelineDescriptor::new(); pipe_desc.setVertexFunction(Some(&*vfn)); @@ -371,8 +375,12 @@ pub fn render_batch_encode(n_draws: usize, iters: usize) -> f64 { let queue = dev.newCommandQueue().unwrap(); let src = NSString::from_str(TRIANGLE_SRC); let lib = dev.newLibraryWithSource_options_error(&src, None).unwrap();

  • let vfn = lib.newFunctionWithName(&NSString::from_str("vmain")).unwrap();
  • let ffn = lib.newFunctionWithName(&NSString::from_str("fmain")).unwrap();
  • let vfn = lib

  •    .newFunctionWithName(&NSString::from_str("vmain"))
    
  •    .unwrap();
    
  • let ffn = lib

  •    .newFunctionWithName(&NSString::from_str("fmain"))
    
  •    .unwrap();
    

    let pipe_desc = MTLRenderPipelineDescriptor::new(); pipe_desc.setVertexFunction(Some(&*vfn)); @@ -418,9 +426,7 @@ pub fn render_batch_encode(n_draws: usize, iters: usize) -> f64 { let enc = cmd.renderCommandEncoderWithDescriptor(&rpass).unwrap(); enc.setRenderPipelineState(&rpipeline); for _ in 0..n_draws {

  •        unsafe {
    
  •            enc.drawPrimitives_vertexStart_vertexCount(MTLPrimitiveType::Triangle, 0, 0)
    
  •        };
    
  •        unsafe { enc.drawPrimitives_vertexStart_vertexCount(MTLPrimitiveType::Triangle, 0, 0) };
       }
       enc.endEncoding();
       cmd.commit();
    

@@ -433,9 +439,7 @@ pub fn render_batch_encode(n_draws: usize, iters: usize) -> f64 { let enc = cmd.renderCommandEncoderWithDescriptor(&rpass).unwrap(); enc.setRenderPipelineState(&rpipeline); for _ in 0..n_draws {

  •        unsafe {
    
  •            enc.drawPrimitives_vertexStart_vertexCount(MTLPrimitiveType::Triangle, 0, 0)
    
  •        };
    
  •        unsafe { enc.drawPrimitives_vertexStart_vertexCount(MTLPrimitiveType::Triangle, 0, 0) };
       }
       enc.endEncoding();
       cmd.commit();
    

diff --git a/aruminium/docs/tutorial.md b/aruminium/docs/tutorial.md index 04004dd..146b525 100644 --- a/aruminium/docs/tutorial.md +++ b/aruminium/docs/tutorial.md @@ -230,6 +230,6 @@ fn main() -> Result<(), GpuError> {

next steps

-- see examples/matmul.rs for 2D dispatch with struct parameters +- see examples/aruminium_matmul.rs for 2D dispatch with struct parameters

  • see docs/guide.md for Dispatch, batch encoding, pipelining
  • see docs/explanations.md for why the architecture works this way diff --git a/aruminium/examples/README.md b/aruminium/examples/README.md index 97319c9..b7378a7 100644 --- a/aruminium/examples/README.md +++ b/aruminium/examples/README.md @@ -4,10 +4,10 @@ runnable demos. each one is self-contained and shows a real GPU workflow.
cargo run --example vecadd
-cargo run --example matmul
+cargo run --example aruminium_matmul
file what it does
vecadd.rs vector addition on GPU — simplest possible compute dispatch
- matmul.rs
+ aruminium_matmul.rs
diff --git a/aruminium/examples/matmul.rs b/aruminium/examples/matmul.rs
deleted file mode 100644
index b08d98f..0000000
--- a/aruminium/examples/matmul.rs
+++ /dev/null
@@ -1,111 +0,0 @@
-//! Matrix multiplication on Metal GPU — compute example

-use aruminium::{Gpu, GpuError};

-fn main() -> Result<(), GpuError> {

  • let device = Gpu::open()?;
  • println!("Device: {}", device.name());
  • let queue = device.new_command_queue()?;
  • // Naive matmul kernel: C[M,N] = A[M,K] * B[K,N]
  • let source = r#"
  •    #include <metal_stdlib>
    
  •    using namespace metal;
    
  •    struct MatmulParams {
    
  •        uint M;
    
  •        uint N;
    
  •        uint K;
    
  •    };
    
  •    kernel void matmul(device const float *A buffer(0),
    
  •                       device const float *B buffer(1),
    
  •                       device float *C       buffer(2),
    
  •                       constant MatmulParams &params buffer(3),
    
  •                       uint2 gid thread_position_in_grid) {
    
  •        uint row = gid.y;
    
  •        uint col = gid.x;
    
  •        if (row >= params.M || col >= params.N) return;
    
  •        float sum = 0.0;
    
  •        for (uint k = 0; k < params.K; k++) {
    
  •            sum += A[row * params.K + k] * B[k * params.N + col];
    
  •        }
    
  •        C[row * params.N + col] = sum;
    
  •    }
    
  • "#;
  • let lib = device.compile(source)?;
  • let func = lib.function("matmul")?;
  • let pipeline = device.pipeline(&func)?;
  • let m = 64usize;
  • let n = 64usize;
  • let k = 64usize;
  • let buf_a = device.buffer(m * k * 4)?;
  • let buf_b = device.buffer(k * n * 4)?;
  • let buf_c = device.buffer(m * n * 4)?;
  • // A = identity, B = all ones => C should be all ones
  • buf_a.write_f32(|d| {
  •    for i in 0..m {
    
  •        for j in 0..k {
    
  •            d[i * k + j] = if i == j { 1.0 } else { 0.0 };
    
  •        }
    
  •    }
    
  • });
  • buf_b.write_f32(|d| {
  •    for i in 0..d.len() {
    
  •        d[i] = 1.0;
    
  •    }
    
  • });
  • #[repr(C)]
  • struct MatmulParams {
  •    m: u32,
    
  •    n: u32,
    
  •    k: u32,
    
  • }
  • let params = MatmulParams {
  •    m: m as u32,
    
  •    n: n as u32,
    
  •    k: k as u32,
    
  • };
  • let params_bytes = unsafe {
  •    std::slice::from_raw_parts(
    
  •        &params as *const MatmulParams as *const u8,
    
  •        std::mem::size_of::<MatmulParams>(),
    
  •    )
    
  • };
  • let cmd = queue.commands()?;
  • let enc = cmd.encoder()?;
  • enc.bind(&pipeline);
  • enc.bind_buffer(&buf_a, 0, 0);
  • enc.bind_buffer(&buf_b, 0, 1);
  • enc.bind_buffer(&buf_c, 0, 2);
  • enc.push(params_bytes, 3);
  • enc.launch((n, m, 1), (16, 16, 1));
  • enc.finish();
  • cmd.submit();
  • cmd.wait();
  • buf_c.read_f32(|d| {
  •    let mut max_err: f32 = 0.0;
    
  •    for i in 0..m * n {
    
  •        max_err = max_err.max((d[i] - 1.0).abs());
    
  •    }
    
  •    if max_err < 1e-5 {
    
  •        println!(
    
  •            "PASS: {}x{}x{} matmul verified (max_err={:.2e})",
    
  •            m, n, k, max_err
    
  •        );
    
  •    } else {
    
  •        println!("FAIL: max_err = {:.6}", max_err);
    
  •    }
    
  • });
  • Ok(()) -} diff --git a/rane/CLAUDE.md b/rane/CLAUDE.md index 5bd1739..cb6b4a2 100644 --- a/rane/CLAUDE.md +++ b/rane/CLAUDE.md @@ -39,7 +39,7 @@ skip for trivial tasks. cargo fmt --all # format cargo clippy --workspace -- -W warnings # lint cargo build --release --workspace # build all -cargo run --example matmul # verify ANE access +cargo run --example rane_matmul # verify ANE access

every commit: format clean, clippy clean, builds, examples run.
@@ -103,7 +103,7 @@ src/                  core library (zero deps)
  weights.rs          checkpoint I/O, LayerWeights, KVCache
  mil/                MIL program builder → ANE bytecode
  ops/                CPU kernels (rmsnorm, rope, attention, loss, adam)
-examples/             runnable demos (matmul, infer, train, bench)
+examples/             runnable demos (rane_matmul, infer, train, bench)
tools/                separate crate with heavy deps (convert_hf, tokenize, chat)
specs/                specification (source of truth)
  api.md              API spec — concepts, lifecycle, apple mapping
diff --git a/rane/Cargo.toml b/rane/Cargo.toml
index ff8e491..aa0376b 100644
--- a/rane/Cargo.toml
+++ b/rane/Cargo.toml
@@ -1,5 +1,6 @@
[package]
name = "rane"
+autobenches = false # benches/ is the separate rane-benches workspace package.
version.workspace = true
edition.workspace = true
license.workspace = true
@@ -24,5 +25,5 @@ name = "rane_probe"
path = "src/probe/main.rs"

example
-name = "matmul"
-path = "examples/matmul.rs"
+name = "rane_matmul"
+path = "examples/rane_matmul.rs"
diff --git a/rane/README.md b/rane/README.md
index e5808f4..f74e010 100644
--- a/rane/README.md
+++ b/rane/README.md
@@ -130,7 +130,7 @@ rane::cast_f16_f32(&mut [f32], &[u16])  // bulk NEON

```bash
cargo build --release
-cargo run --example matmul
+cargo run --example rane_matmul
cargo test --test integration -- --test-threads=1
cargo run --release -p rane-benches --bin bench
cargo run --release -p rane-benches --bin compare
@@ -149,7 +149,7 @@ src/                    rane crate — zero deps, system frameworks only
  mil/mod.rs            MIL program builder (matmul, header, footer)
  probe/                rane_probe — 7-level reverse engineering tool
examples/
-  matmul.rs             64x64 matmul on ANE hardware
+  rane_matmul.rs             64x64 matmul on ANE hardware
benches/                separate crate with bench + compare binaries
tests/
  integration.rs        13 tests: surface, fp16, MIL, model lifecycle
diff --git a/rane/examples/matmul.rs b/rane/examples/matmul.rs
deleted file mode 100644
index add39ec..0000000
--- a/rane/examples/matmul.rs
+++ /dev/null
@@ -1,93 +0,0 @@
-//! Minimal ANE matmul demo — pure Rust, zero dependencies
-//!
-//! Compiles a 64×64 matmul on ANE, runs with identity matrix,
-//! verifies output matches input.
-//!
-//! Run: cargo run --example matmul
-
-use rane::mil;
-use rane::{f32_to_fp16, fp16_to_f32, Buffer, Program};
-
-fn main() -> Result<(), Box<dyn std::error::Error>> {
-    println!("ANE Matmul — Pure Rust\n");
-
-    // Build MIL program: y = x @ W
-    // Input: [1, 64, 1, 128] fp16 (64 activations + 64 weights per channel)
-    // Output: [1, 64, 1, 64] fp16
-    let ic = 64;
-    let oc = 64;
-    let seq = 64;
-    let program = mil::matmul(ic, oc, seq);
-    let (in_ch, in_sp) = program.input_shape();
-    let (out_ch, out_sp) = program.output_shape();
-    println!("  MIL: matmul({ic}x{oc}, seq={seq})");
-    println!(
-        "  Input:  [1, {in_ch}, 1, {in_sp}] fp16 ({} KB)",
-        program.input_size() / 1024
-    );
-    println!(
-        "  Output: [1, {out_ch}, 1, {out_sp}] fp16 ({} KB)\n",
-        program.output_size() / 1024
-    );
-
-    // Compile
-    print!("  Compiling...");
-    let mut model = Program::compile(&program, &[])?;
-    println!(" OK");
-
-    // Load into ANE
-    print!("  Loading...");
-    model.load()?;
-    println!(" OK");
-
-    // Prepare I/O surfaces
-    let input = Buffer::new(program.input_size())?;
-    let output = Buffer::new(program.output_size())?;
-
-    // Fill input: activations = 1.0, weights = identity matrix
-    input.write(|data| {
-        for ch in 0..ic {
-            for s in 0..seq {
-                data[ch * in_sp + s] = f32_to_fp16(1.0);
-            }
-            for o in 0..oc {
-                data[ch * in_sp + seq + o] = if ch == o { f32_to_fp16(1.0) } else { 0 };
-            }
-        }
-    });
-    println!("  Input: all 1.0 activations, identity weight matrix");
-
-    // Run on ANE
-    print!("  Evaluating on ANE...");
-    model.run(&input, &output)?;
-    println!(" OK\n");
-
-    // Read output
-    output.read(|data| {
-        print!("  Output[0..8] = [");
-        for i in 0..8 {
-            if i > 0 {
-                print!(", ");
-            }
-            print!("{:.1}", fp16_to_f32(data[i]));
-        }
-        println!("]");
-
-        // Verify: identity matmul should give all 1.0 (each output = sum of row × identity col = 1.0)
-        // Actually: [SEQ,IC] @ [IC,OC] with identity → output = ones × I = ones
-        // But the matmul is (seq=64) @ (ic=64,oc=64), so each output is dot(ones_64, identity_col) = 1.0
-        let all_ones = data[..out_ch * out_sp]
-            .iter()
-            .all(|&v| fp16_to_f32(v) == 1.0);
-        if all_ones {
-            println!("\n  VERIFIED: all {} output values = 1.0", out_ch * out_sp);
-            println!("  Pure Rust → MIL → ANE bytecode → ANE hardware → correct result");
-        } else {
-            let nonzero: Vec<_> = data[..8].iter().map(|&v| fp16_to_f32(v)).collect();
-            println!("\n  Output values: {:?}", nonzero);
-        }
-    });
-
-    // Cleanup is automatic (Drop)
-    Ok(())
-}
diff --git a/aruminium/examples/aruminium_matmul.rs b/aruminium/examples/aruminium_matmul.rs
new file mode 100644
index 0000000..b08d98f
--- /dev/null
+++ b/aruminium/examples/aruminium_matmul.rs
@@ -0,0 +1,111 @@
+//! Matrix multiplication on Metal GPU — compute example
+
+use aruminium::{Gpu, GpuError};
+
+fn main() -> Result<(), GpuError> {
+    let device = Gpu::open()?;
+    println!("Device: {}", device.name());
+
+    let queue = device.new_command_queue()?;
+
+    // Naive matmul kernel: C[M,N] = A[M,K] * B[K,N]
+    let source = r#"
+        #include <metal_stdlib>
+        using namespace metal;
+
+        struct MatmulParams {
+            uint M;
+            uint N;
+            uint K;
+        };
+
+        kernel void matmul(device const float *A buffer(0),
+                           device const float *B buffer(1),
+                           device float *C       buffer(2),
+                           constant MatmulParams &params buffer(3),
+                           uint2 gid thread_position_in_grid) {
+            uint row = gid.y;
+            uint col = gid.x;
+            if (row >= params.M || col >= params.N) return;
+
+            float sum = 0.0;
+            for (uint k = 0; k < params.K; k++) {
+                sum += A[row * params.K + k] * B[k * params.N + col];
+            }
+            C[row * params.N + col] = sum;
+        }
+    "#;
+
+    let lib = device.compile(source)?;
+    let func = lib.function("matmul")?;
+    let pipeline = device.pipeline(&func)?;
+
+    let m = 64usize;
+    let n = 64usize;
+    let k = 64usize;
+
+    let buf_a = device.buffer(m * k * 4)?;
+    let buf_b = device.buffer(k * n * 4)?;
+    let buf_c = device.buffer(m * n * 4)?;
+
+    // A = identity, B = all ones => C should be all ones
+    buf_a.write_f32(|d| {
+        for i in 0..m {
+            for j in 0..k {
+                d[i * k + j] = if i == j { 1.0 } else { 0.0 };
+            }
+        }
+    });
+    buf_b.write_f32(|d| {
+        for i in 0..d.len() {
+            d[i] = 1.0;
+        }
+    });
+
+    #[repr(C)]
+    struct MatmulParams {
+        m: u32,
+        n: u32,
+        k: u32,
+    }
+    let params = MatmulParams {
+        m: m as u32,
+        n: n as u32,
+        k: k as u32,
+    };
+    let params_bytes = unsafe {
+        std::slice::from_raw_parts(
+            &params as *const MatmulParams as *const u8,
+            std::mem::size_of::<MatmulParams>(),
+        )
+    };
+
+    let cmd = queue.commands()?;
+    let enc = cmd.encoder()?;
+    enc.bind(&pipeline);
+    enc.bind_buffer(&buf_a, 0, 0);
+    enc.bind_buffer(&buf_b, 0, 1);
+    enc.bind_buffer(&buf_c, 0, 2);
+    enc.push(params_bytes, 3);
+    enc.launch((n, m, 1), (16, 16, 1));
+    enc.finish();
+    cmd.submit();
+    cmd.wait();
+
+    buf_c.read_f32(|d| {
+        let mut max_err: f32 = 0.0;
+        for i in 0..m * n {
+            max_err = max_err.max((d[i] - 1.0).abs());
+        }
+        if max_err < 1e-5 {
+            println!(
+                "PASS: {}x{}x{} matmul verified (max_err={:.2e})",
+                m, n, k, max_err
+            );
+        } else {
+            println!("FAIL: max_err = {:.6}", max_err);
+        }
+    });
+
+    Ok(())
+}
diff --git a/rane/examples/rane_matmul.rs b/rane/examples/rane_matmul.rs
new file mode 100644
index 0000000..6145789
--- /dev/null
+++ b/rane/examples/rane_matmul.rs
@@ -0,0 +1,93 @@
+//! Minimal ANE matmul demo — pure Rust, zero dependencies
+//!
+//! Compiles a 64×64 matmul on ANE, runs with identity matrix,
+//! verifies output matches input.
+//!
+//! Run: cargo run --example rane_matmul
+
+use rane::mil;
+use rane::{f32_to_fp16, fp16_to_f32, Buffer, Program};
+
+fn main() -> Result<(), Box<dyn std::error::Error>> {
+    println!("ANE Matmul — Pure Rust\n");
+
+    // Build MIL program: y = x @ W
+    // Input: [1, 64, 1, 128] fp16 (64 activations + 64 weights per channel)
+    // Output: [1, 64, 1, 64] fp16
+    let ic = 64;
+    let oc = 64;
+    let seq = 64;
+    let program = mil::matmul(ic, oc, seq);
+    let (in_ch, in_sp) = program.input_shape();
+    let (out_ch, out_sp) = program.output_shape();
+    println!("  MIL: matmul({ic}x{oc}, seq={seq})");
+    println!(
+        "  Input:  [1, {in_ch}, 1, {in_sp}] fp16 ({} KB)",
+        program.input_size() / 1024
+    );
+    println!(
+        "  Output: [1, {out_ch}, 1, {out_sp}] fp16 ({} KB)\n",
+        program.output_size() / 1024
+    );
+
+    // Compile
+    print!("  Compiling...");
+    let mut model = Program::compile(&program, &[])?;
+    println!(" OK");
+
+    // Load into ANE
+    print!("  Loading...");
+    model.load()?;
+    println!(" OK");
+
+    // Prepare I/O surfaces
+    let input = Buffer::new(program.input_size())?;
+    let output = Buffer::new(program.output_size())?;
+
+    // Fill input: activations = 1.0, weights = identity matrix
+    input.write(|data| {
+        for ch in 0..ic {
+            for s in 0..seq {
+                data[ch * in_sp + s] = f32_to_fp16(1.0);
+            }
+            for o in 0..oc {
+                data[ch * in_sp + seq + o] = if ch == o { f32_to_fp16(1.0) } else { 0 };
+            }
+        }
+    });
+    println!("  Input: all 1.0 activations, identity weight matrix");
+
+    // Run on ANE
+    print!("  Evaluating on ANE...");
+    model.run(&input, &output)?;
+    println!(" OK\n");
+
+    // Read output
+    output.read(|data| {
+        print!("  Output[0..8] = [");
+        for i in 0..8 {
+            if i > 0 {
+                print!(", ");
+            }
+            print!("{:.1}", fp16_to_f32(data[i]));
+        }
+        println!("]");
+
+        // Verify: identity matmul should give all 1.0 (each output = sum of row × identity col = 1.0)
+        // Actually: [SEQ,IC] @ [IC,OC] with identity → output = ones × I = ones
+        // But the matmul is (seq=64) @ (ic=64,oc=64), so each output is dot(ones_64, identity_col) = 1.0
+        let all_ones = data[..out_ch * out_sp]
+            .iter()
+            .all(|&v| fp16_to_f32(v) == 1.0);
+        if all_ones {
+            println!("\n  VERIFIED: all {} output values = 1.0", out_ch * out_sp);
+            println!("  Pure Rust → MIL → ANE bytecode → ANE hardware → correct result");
+        } else {
+            let nonzero: Vec<_> = data[..8].iter().map(|&v| fp16_to_f32(v)).collect();
+            println!("\n  Output values: {:?}", nonzero);
+        }
+    });
+
+    // Cleanup is automatic (Drop)
+    Ok(())
+}

Graph