@mlx-bun/inference 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (467) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1475 -2
  3. package/THIRD_PARTY_NOTICES.md +3404 -0
  4. package/dist/native/libmlx_bun_ane.dylib +0 -0
  5. package/dist/native/libmlx_bun_expert_io.dylib +0 -0
  6. package/dist/native/mlx-bun-frame-extract +0 -0
  7. package/examples/fit-model.ts +25 -0
  8. package/examples/qwen3-forward.ts +42 -0
  9. package/examples/qwen3-generate.ts +28 -0
  10. package/examples/trellis-expand.ts +23 -0
  11. package/package.json +129 -4
  12. package/src/adapters/available.ts +110 -0
  13. package/src/adapters/index.ts +3 -0
  14. package/src/adapters/manager.ts +316 -0
  15. package/src/artifacts/auxiliary-files.ts +45 -0
  16. package/src/artifacts/config-dialects.ts +94 -0
  17. package/src/artifacts/config.ts +341 -0
  18. package/src/artifacts/draft-vocabulary.ts +30 -0
  19. package/src/artifacts/expert-offload-build.ts +75 -0
  20. package/src/artifacts/expert-offload.ts +89 -0
  21. package/src/artifacts/experts/index.ts +3 -0
  22. package/src/artifacts/experts/io.ts +386 -0
  23. package/src/artifacts/experts/residency.ts +1134 -0
  24. package/src/artifacts/experts/usage.ts +415 -0
  25. package/src/artifacts/fingerprint.ts +44 -0
  26. package/src/artifacts/glm52/container.ts +305 -0
  27. package/src/artifacts/glm52/expert-layout.ts +249 -0
  28. package/src/artifacts/glm52/index.ts +7 -0
  29. package/src/artifacts/glm52/kernel-layout.ts +124 -0
  30. package/src/artifacts/glm52/layout.ts +152 -0
  31. package/src/artifacts/glm52/memory.ts +500 -0
  32. package/src/artifacts/glm52/resident-weights.ts +135 -0
  33. package/src/artifacts/glm52/weights.ts +503 -0
  34. package/src/artifacts/glm52-config.ts +262 -0
  35. package/src/artifacts/identity.ts +94 -0
  36. package/src/artifacts/index.ts +15 -0
  37. package/src/artifacts/mmap.ts +90 -0
  38. package/src/artifacts/safetensors-writer.ts +249 -0
  39. package/src/artifacts/safetensors.ts +164 -0
  40. package/src/artifacts/turboquant-fold.ts +42 -0
  41. package/src/artifacts/weight-audit.ts +43 -0
  42. package/src/artifacts/weights.ts +255 -0
  43. package/src/contracts/index.ts +2 -0
  44. package/src/contracts/mlx/attention.ts +8 -0
  45. package/src/contracts/mlx/cache.ts +510 -0
  46. package/src/contracts/mlx/checkpoint.ts +10 -0
  47. package/src/contracts/mlx/draft-checkpoint.ts +14 -0
  48. package/src/contracts/mlx/draft-projection.ts +27 -0
  49. package/src/contracts/mlx/draft-target.ts +84 -0
  50. package/src/contracts/mlx/drafter.ts +176 -0
  51. package/src/contracts/mlx/forward-work.ts +23 -0
  52. package/src/contracts/mlx/glm52-weights.ts +25 -0
  53. package/src/contracts/mlx/graph.ts +309 -0
  54. package/src/contracts/mlx/head.ts +6 -0
  55. package/src/contracts/mlx/index.ts +15 -0
  56. package/src/contracts/mlx/kv-codec.ts +9 -0
  57. package/src/contracts/mlx/media.ts +113 -0
  58. package/src/contracts/mlx/positions.ts +16 -0
  59. package/src/contracts/mlx/row-table.ts +2 -0
  60. package/src/contracts/mlx/trainable.ts +103 -0
  61. package/src/contracts/mlx/whisper.ts +96 -0
  62. package/src/contracts/portable/composition.ts +106 -0
  63. package/src/contracts/portable/denoising.ts +17 -0
  64. package/src/contracts/portable/execution.ts +79 -0
  65. package/src/contracts/portable/generation.ts +103 -0
  66. package/src/contracts/portable/graph.ts +80 -0
  67. package/src/contracts/portable/index.ts +15 -0
  68. package/src/contracts/portable/memory-plan.ts +26 -0
  69. package/src/contracts/portable/object-cache.ts +8 -0
  70. package/src/contracts/portable/prefill.ts +63 -0
  71. package/src/contracts/portable/prefix-cache.ts +33 -0
  72. package/src/contracts/portable/prompt.ts +2 -0
  73. package/src/contracts/portable/resources.ts +25 -0
  74. package/src/contracts/portable/rollback.ts +7 -0
  75. package/src/contracts/portable/sampling.ts +44 -0
  76. package/src/contracts/portable/scheduling.ts +54 -0
  77. package/src/contracts/portable/token-delivery.ts +4 -0
  78. package/src/contracts/portable/tsconfig.json +14 -0
  79. package/src/embeddings/index.ts +1 -0
  80. package/src/embeddings/text.ts +85 -0
  81. package/src/execution/admission.ts +59 -0
  82. package/src/execution/batch-group.ts +1240 -0
  83. package/src/execution/batch-types.ts +225 -0
  84. package/src/execution/cancellation.ts +38 -0
  85. package/src/execution/continuation-request.ts +45 -0
  86. package/src/execution/continuation-types.ts +10 -0
  87. package/src/execution/coordinator.ts +70 -0
  88. package/src/execution/denoising-group.ts +180 -0
  89. package/src/execution/engine.ts +56 -0
  90. package/src/execution/fill-group.ts +505 -0
  91. package/src/execution/fit.ts +184 -0
  92. package/src/execution/gateway-binding.ts +178 -0
  93. package/src/execution/grammar-group.ts +224 -0
  94. package/src/execution/index.ts +18 -0
  95. package/src/execution/methods.ts +75 -0
  96. package/src/execution/mixed-iteration.ts +96 -0
  97. package/src/execution/plan.ts +65 -0
  98. package/src/execution/prefill-cohort.ts +100 -0
  99. package/src/execution/prefill-rows.ts +263 -0
  100. package/src/execution/request-policy.ts +19 -0
  101. package/src/execution/row-sampling.ts +49 -0
  102. package/src/execution/scheduler.ts +92 -0
  103. package/src/execution/session.ts +247 -0
  104. package/src/execution/speculative-group.ts +797 -0
  105. package/src/execution/tasks.ts +44 -0
  106. package/src/generation/autoregressive.ts +840 -0
  107. package/src/generation/bindings/autoregressive.ts +104 -0
  108. package/src/generation/bindings/denoising.ts +60 -0
  109. package/src/generation/bindings/prefill-policy.ts +36 -0
  110. package/src/generation/checkpoint-identity.ts +60 -0
  111. package/src/generation/denoising.ts +85 -0
  112. package/src/generation/diffusion.ts +583 -0
  113. package/src/generation/fill/echo-index.ts +188 -0
  114. package/src/generation/fill/index.ts +3 -0
  115. package/src/generation/fill/proposal.ts +69 -0
  116. package/src/generation/fill/schema-rows.ts +506 -0
  117. package/src/generation/fill/session.ts +464 -0
  118. package/src/generation/fill/tool-boundary.ts +103 -0
  119. package/src/generation/fill-append.ts +58 -0
  120. package/src/generation/generate.ts +44 -0
  121. package/src/generation/grammar-step.ts +39 -0
  122. package/src/generation/index.ts +14 -0
  123. package/src/generation/phase-dispatch.ts +115 -0
  124. package/src/generation/prefill.ts +33 -0
  125. package/src/generation/result.ts +49 -0
  126. package/src/generation/scopes.ts +157 -0
  127. package/src/generation/speculative/acceptance.ts +41 -0
  128. package/src/generation/speculative/adaptive-draft-gate.ts +166 -0
  129. package/src/generation/speculative/bindings/assistant-rows.ts +102 -0
  130. package/src/generation/speculative/bindings/autoregressive-rows.ts +124 -0
  131. package/src/generation/speculative/bindings/binding.ts +106 -0
  132. package/src/generation/speculative/bindings/deepspec-rows.ts +33 -0
  133. package/src/generation/speculative/bindings/draft-target.ts +10 -0
  134. package/src/generation/speculative/bindings/glm52-mtp-rows.ts +128 -0
  135. package/src/generation/speculative/bindings/projected-context-rows.ts +78 -0
  136. package/src/generation/speculative/bindings/projected-draft-rows.ts +95 -0
  137. package/src/generation/speculative/bindings/qwen-mtp-rows.ts +336 -0
  138. package/src/generation/speculative/bindings/two-model-rows.ts +63 -0
  139. package/src/generation/speculative/cache-identity.ts +16 -0
  140. package/src/generation/speculative/draft-kind.ts +149 -0
  141. package/src/generation/speculative/draft-policy.ts +41 -0
  142. package/src/generation/speculative/draft-registry.ts +118 -0
  143. package/src/generation/speculative/draft-vocab.ts +110 -0
  144. package/src/generation/speculative/index.ts +17 -0
  145. package/src/generation/speculative/output.ts +49 -0
  146. package/src/generation/speculative/round.ts +307 -0
  147. package/src/generation/speculative/source.ts +144 -0
  148. package/src/generation/speculative/sources/assistant-source.ts +64 -0
  149. package/src/generation/speculative/sources/deepspec-source.ts +70 -0
  150. package/src/generation/speculative/sources/dflash-source.ts +84 -0
  151. package/src/generation/speculative/sources/dflash2-source.ts +86 -0
  152. package/src/generation/speculative/sources/glm52-mtp-source.ts +66 -0
  153. package/src/generation/speculative/sources/ngram-source.ts +165 -0
  154. package/src/generation/speculative/sources/qwen-mtp-source.ts +154 -0
  155. package/src/generation/speculative/sources/two-model.ts +75 -0
  156. package/src/generation/types.ts +194 -0
  157. package/src/index.ts +20 -0
  158. package/src/input/audio/audiotoolbox.ts +112 -0
  159. package/src/input/audio/decode.ts +133 -0
  160. package/src/input/audio/features.ts +202 -0
  161. package/src/input/audio/index.ts +6 -0
  162. package/src/input/audio/transcode.ts +67 -0
  163. package/src/input/audio/whisper-mel.ts +185 -0
  164. package/src/input/audio/whisper-tokenizer.ts +238 -0
  165. package/src/input/chat-template.ts +389 -0
  166. package/src/input/index.ts +6 -0
  167. package/src/input/media-fetch.ts +439 -0
  168. package/src/input/packed-mixed.ts +43 -0
  169. package/src/input/special-tokens.ts +75 -0
  170. package/src/input/token-groups.ts +49 -0
  171. package/src/input/tokenizer.ts +336 -0
  172. package/src/input/tool-call.ts +689 -0
  173. package/src/input/vision/index.ts +3 -0
  174. package/src/input/vision/preprocess.ts +247 -0
  175. package/src/input/vision/prompt.ts +398 -0
  176. package/src/input/vision/qwen3vl-preprocess.ts +409 -0
  177. package/src/input/vision/qwen3vl-prompt.ts +237 -0
  178. package/src/input/vision/video-frames.ts +100 -0
  179. package/src/kernels/ane/fill.ts +101 -0
  180. package/src/kernels/ane/linear.ts +416 -0
  181. package/src/kernels/attention/flash.ts +694 -0
  182. package/src/kernels/attention/kvq4-decode.ts +155 -0
  183. package/src/kernels/attention/masks.ts +40 -0
  184. package/src/kernels/attention/multi-query.ts +193 -0
  185. package/src/kernels/attention/paged.ts +130 -0
  186. package/src/kernels/delta/gated.ts +306 -0
  187. package/src/kernels/delta/index.ts +3 -0
  188. package/src/kernels/delta/silu-rms-heads.ts +69 -0
  189. package/src/kernels/delta/state.ts +74 -0
  190. package/src/kernels/gated-rms-norm.ts +64 -0
  191. package/src/kernels/glm52/layout.ts +37 -0
  192. package/src/kernels/glm52/streamed-experts.ts +360 -0
  193. package/src/kernels/logits.ts +38 -0
  194. package/src/kernels/quantization/affine-row.ts +154 -0
  195. package/src/kernels/quantization/affine-rows.ts +36 -0
  196. package/src/kernels/quantization/affine-split-mma.ts +144 -0
  197. package/src/kernels/quantization/affine3-mma.ts +117 -0
  198. package/src/kernels/quantization/affine3-rows.ts +103 -0
  199. package/src/kernels/quantization/affine4-mma.ts +113 -0
  200. package/src/kernels/quantization/affine4-rows.ts +102 -0
  201. package/src/kernels/residual-rms-norm.ts +65 -0
  202. package/src/kernels/sampling/index.ts +2 -0
  203. package/src/kernels/sampling/normalized-argmax.ts +116 -0
  204. package/src/kernels/sampling/token-bitmask.ts +52 -0
  205. package/src/kernels/softcap.ts +35 -0
  206. package/src/kernels/trellis/codebook.ts +123 -0
  207. package/src/kernels/trellis/down-codebook.ts +184 -0
  208. package/src/kernels/trellis/down-factored.ts +180 -0
  209. package/src/kernels/trellis/down-k3-interleaved-factored.ts +146 -0
  210. package/src/kernels/trellis/down-mma-wide.ts +195 -0
  211. package/src/kernels/trellis/down-mma.ts +145 -0
  212. package/src/kernels/trellis/expand.ts +42 -0
  213. package/src/kernels/trellis/gate-up-codebook-mma.ts +141 -0
  214. package/src/kernels/trellis/gate-up-codebook.ts +137 -0
  215. package/src/kernels/trellis/gate-up-factored.ts +197 -0
  216. package/src/kernels/trellis/gate-up-mma-wide.ts +147 -0
  217. package/src/kernels/trellis/gate-up-mma.ts +148 -0
  218. package/src/kernels/trellis/gate-up.ts +248 -0
  219. package/src/kernels/trellis/geometry.ts +22 -0
  220. package/src/kernels/trellis/index.ts +103 -0
  221. package/src/kernels/trellis/launch.ts +12 -0
  222. package/src/kernels/trellis/mixed-gate-up-factored.ts +119 -0
  223. package/src/kernels/trellis/mixed-gate-up.ts +146 -0
  224. package/src/kernels/trellis/qualified.ts +34 -0
  225. package/src/kernels/trellis/reduce.ts +150 -0
  226. package/src/kernels/trellis/scatter.ts +407 -0
  227. package/src/kernels/trellis/splitk-prefill.ts +152 -0
  228. package/src/kernels/trellis/tiled-prefill.ts +131 -0
  229. package/src/kernels/trellis/vector-expand.ts +58 -0
  230. package/src/kernels/trellis/wide-prefill.ts +89 -0
  231. package/src/kernels/turboquant/decode.ts +82 -0
  232. package/src/kernels/turboquant/index.ts +5 -0
  233. package/src/kernels/turboquant/inverse.ts +122 -0
  234. package/src/kernels/turboquant/ops.ts +860 -0
  235. package/src/kernels/turboquant/signs.ts +130 -0
  236. package/src/kernels/turboquant/tables.ts +124 -0
  237. package/src/layers/affine-verify-linear.ts +75 -0
  238. package/src/layers/ane-prefill-split.ts +283 -0
  239. package/src/layers/compiled-normalization.ts +41 -0
  240. package/src/layers/delta-heads.ts +23 -0
  241. package/src/layers/dense-embedding.ts +29 -0
  242. package/src/layers/dense-linear.ts +32 -0
  243. package/src/layers/dequantized-linear.ts +72 -0
  244. package/src/layers/folded-attention.ts +42 -0
  245. package/src/layers/geglu.ts +130 -0
  246. package/src/layers/helpers.ts +7 -0
  247. package/src/layers/index.ts +36 -0
  248. package/src/layers/kv4-decode-attention.ts +15 -0
  249. package/src/layers/layer-norm.ts +24 -0
  250. package/src/layers/loading.ts +92 -0
  251. package/src/layers/lora.ts +150 -0
  252. package/src/layers/normalization.ts +9 -0
  253. package/src/layers/prefix-layout.ts +33 -0
  254. package/src/layers/quantized-append-attention.ts +32 -0
  255. package/src/layers/quantized-attention.ts +353 -0
  256. package/src/layers/quantized-embedding.ts +39 -0
  257. package/src/layers/quantized-linear.ts +137 -0
  258. package/src/layers/quantized-switch-linear.ts +37 -0
  259. package/src/layers/qwen-append.ts +12 -0
  260. package/src/layers/qwen-mrope.ts +238 -0
  261. package/src/layers/rope-2d.ts +110 -0
  262. package/src/layers/rope.ts +389 -0
  263. package/src/layers/swiglu.ts +23 -0
  264. package/src/layers/trellis-codebook-down.ts +52 -0
  265. package/src/layers/trellis-codebook-gate-up.ts +42 -0
  266. package/src/layers/trellis-down.ts +117 -0
  267. package/src/layers/trellis-gate-up.ts +71 -0
  268. package/src/layers/trellis-linear.ts +211 -0
  269. package/src/layers/trellis-prompt.ts +102 -0
  270. package/src/layers/trellis-reduce-gate-up.ts +73 -0
  271. package/src/layers/trellis-scatter-down.ts +98 -0
  272. package/src/models/ane-install.ts +74 -0
  273. package/src/models/audio/conformer.ts +656 -0
  274. package/src/models/cache-composition.ts +44 -0
  275. package/src/models/capabilities.ts +89 -0
  276. package/src/models/chat-template.ts +10 -0
  277. package/src/models/composition.ts +107 -0
  278. package/src/models/diffusion-gemma/experts.ts +59 -0
  279. package/src/models/diffusion-gemma/family.ts +21 -0
  280. package/src/models/diffusion-gemma/model.ts +900 -0
  281. package/src/models/diffusion-gemma/vision.ts +549 -0
  282. package/src/models/drafter-loaders.ts +49 -0
  283. package/src/models/drafters.ts +39 -0
  284. package/src/models/factory.ts +351 -0
  285. package/src/models/families.ts +70 -0
  286. package/src/models/family.ts +125 -0
  287. package/src/models/gemma4/assistant-target.ts +46 -0
  288. package/src/models/gemma4/assistant.ts +327 -0
  289. package/src/models/gemma4/blocks.ts +755 -0
  290. package/src/models/gemma4/compiled-decode.ts +452 -0
  291. package/src/models/gemma4/family.ts +39 -0
  292. package/src/models/gemma4/gemma4-12b.ts +677 -0
  293. package/src/models/gemma4/gemma4-26b.ts +544 -0
  294. package/src/models/gemma4/gemma4-e4b.ts +599 -0
  295. package/src/models/gemma4/graphs.ts +147 -0
  296. package/src/models/gemma4/media.ts +88 -0
  297. package/src/models/gemma4/model.ts +860 -0
  298. package/src/models/gemma4/serving-blocks.ts +72 -0
  299. package/src/models/gemma4/trainable.ts +186 -0
  300. package/src/models/gemma4/written-blocks.ts +232 -0
  301. package/src/models/gemma4/written-forward.ts +159 -0
  302. package/src/models/gemma4/written-input.ts +29 -0
  303. package/src/models/glm52/atlas.ts +507 -0
  304. package/src/models/glm52/coupling.ts +388 -0
  305. package/src/models/glm52/dsa.ts +601 -0
  306. package/src/models/glm52/family.ts +20 -0
  307. package/src/models/glm52/mla.ts +812 -0
  308. package/src/models/glm52/model.ts +1127 -0
  309. package/src/models/glm52/moe.ts +223 -0
  310. package/src/models/glm52/mtp.ts +60 -0
  311. package/src/models/glm52/pilot.ts +537 -0
  312. package/src/models/glm52/reference.ts +445 -0
  313. package/src/models/glm52/residency.ts +557 -0
  314. package/src/models/glm52/streamed-experts.ts +447 -0
  315. package/src/models/graph.ts +59 -0
  316. package/src/models/implementation.ts +230 -0
  317. package/src/models/index.ts +15 -0
  318. package/src/models/media-input.ts +15 -0
  319. package/src/models/memory-plan.ts +39 -0
  320. package/src/models/minicpm5/family.ts +29 -0
  321. package/src/models/minicpm5/model.ts +394 -0
  322. package/src/models/minicpm5/trainable.ts +90 -0
  323. package/src/models/profile.ts +337 -0
  324. package/src/models/qwen/blocks.ts +658 -0
  325. package/src/models/qwen/checkpoint.ts +190 -0
  326. package/src/models/qwen/families.ts +57 -0
  327. package/src/models/qwen/media-input.ts +161 -0
  328. package/src/models/qwen/mtp.ts +101 -0
  329. package/src/models/qwen/qwen3-moe.ts +355 -0
  330. package/src/models/qwen/qwen3.ts +323 -0
  331. package/src/models/qwen/qwen38-27b-trellis-m1max.ts +1532 -0
  332. package/src/models/qwen/qwen38-27b-trellis-m4pro.ts +1092 -0
  333. package/src/models/qwen/qwen3_5.ts +433 -0
  334. package/src/models/qwen/written-layers.ts +285 -0
  335. package/src/models/row-table.ts +1 -0
  336. package/src/models/runtime.ts +73 -0
  337. package/src/models/speculative/deepspec-artifact.ts +10 -0
  338. package/src/models/speculative/deepspec.ts +744 -0
  339. package/src/models/speculative/dflash.ts +553 -0
  340. package/src/models/speculative/dflash2-artifact.ts +9 -0
  341. package/src/models/speculative/dflash2-operations.ts +1 -0
  342. package/src/models/speculative/dflash2.ts +576 -0
  343. package/src/models/speculative/loader.ts +29 -0
  344. package/src/models/support.ts +79 -0
  345. package/src/models/universal/archs.ts +365 -0
  346. package/src/models/universal/blocks.ts +479 -0
  347. package/src/models/universal/dense.ts +255 -0
  348. package/src/models/universal/family.ts +17 -0
  349. package/src/models/vision/qwen3vl.ts +566 -0
  350. package/src/models/vision/siglip.ts +520 -0
  351. package/src/models/vision/unified.ts +176 -0
  352. package/src/models/whisper/family.ts +19 -0
  353. package/src/models/whisper/fast.ts +734 -0
  354. package/src/models/whisper/model.ts +430 -0
  355. package/src/runtime/compiled-trace.ts +16 -0
  356. package/src/runtime/config.ts +77 -0
  357. package/src/runtime/expert-trace.ts +71 -0
  358. package/src/runtime/graph-forward.ts +65 -0
  359. package/src/runtime/integers.ts +6 -0
  360. package/src/runtime/native.ts +16 -0
  361. package/src/runtime/resources.ts +53 -0
  362. package/src/runtime/row-operations.ts +42 -0
  363. package/src/runtime/trace.ts +161 -0
  364. package/src/sampling/curve.ts +122 -0
  365. package/src/sampling/draft.ts +55 -0
  366. package/src/sampling/extras.ts +45 -0
  367. package/src/sampling/filters.ts +134 -0
  368. package/src/sampling/grammar.ts +630 -0
  369. package/src/sampling/hlg.ts +290 -0
  370. package/src/sampling/index.ts +9 -0
  371. package/src/sampling/processors.ts +142 -0
  372. package/src/sampling/sampler.ts +120 -0
  373. package/src/sampling/step.ts +343 -0
  374. package/src/sampling/types.ts +161 -0
  375. package/src/sampling/window-filters.ts +46 -0
  376. package/src/scoring/decisions.ts +96 -0
  377. package/src/scoring/full-sequence.ts +103 -0
  378. package/src/scoring/index.ts +9 -0
  379. package/src/scoring/kl.ts +29 -0
  380. package/src/scoring/perplexity.ts +165 -0
  381. package/src/scoring/response-logps.ts +65 -0
  382. package/src/state/affine-attention.ts +180 -0
  383. package/src/state/attachment.ts +68 -0
  384. package/src/state/attention-read.ts +215 -0
  385. package/src/state/batched-kv.ts +294 -0
  386. package/src/state/batched-mask.ts +445 -0
  387. package/src/state/batched-quant.ts +389 -0
  388. package/src/state/batched-quantized-kv.ts +209 -0
  389. package/src/state/batched-rotating-quant.ts +457 -0
  390. package/src/state/batched-rotating-state.ts +149 -0
  391. package/src/state/batched-rotating.ts +430 -0
  392. package/src/state/batched-row-storage.ts +179 -0
  393. package/src/state/batched-ssm.ts +54 -0
  394. package/src/state/batched-turboquant-kv.ts +144 -0
  395. package/src/state/bf16-first-kv.ts +663 -0
  396. package/src/state/cache-service.ts +592 -0
  397. package/src/state/capabilities.ts +65 -0
  398. package/src/state/checkpoint.ts +46 -0
  399. package/src/state/continuation-persistence.ts +126 -0
  400. package/src/state/decode-step-inputs.ts +31 -0
  401. package/src/state/decoded-kv-donor.ts +12 -0
  402. package/src/state/delayed-quantized-kv.ts +141 -0
  403. package/src/state/delayed-rotating-quantized-kv.ts +178 -0
  404. package/src/state/delayed-turboquant-kv.ts +123 -0
  405. package/src/state/durability.ts +214 -0
  406. package/src/state/encoder-cache.ts +26 -0
  407. package/src/state/full-kv-row-append.ts +33 -0
  408. package/src/state/full-kv-row-donor.ts +54 -0
  409. package/src/state/full-prefill-padding.ts +56 -0
  410. package/src/state/full-prefill-row.ts +112 -0
  411. package/src/state/full-transitioning-kv-rows.ts +70 -0
  412. package/src/state/glm52-cache.ts +783 -0
  413. package/src/state/grouped-heads-kv4-cache.ts +26 -0
  414. package/src/state/index.ts +38 -0
  415. package/src/state/kv-attention-view.ts +77 -0
  416. package/src/state/kv-budget.ts +14 -0
  417. package/src/state/kv-scheme.ts +315 -0
  418. package/src/state/kv-storage.ts +57 -0
  419. package/src/state/kv-tensor-rows.ts +212 -0
  420. package/src/state/kv.ts +324 -0
  421. package/src/state/kv4-head256-cache.ts +46 -0
  422. package/src/state/latent-legos.ts +895 -0
  423. package/src/state/layout.ts +277 -0
  424. package/src/state/leases.ts +26 -0
  425. package/src/state/paged/cache.ts +689 -0
  426. package/src/state/paged/codec.ts +36 -0
  427. package/src/state/paged/rows.ts +223 -0
  428. package/src/state/persistence-types.ts +173 -0
  429. package/src/state/persistence-worker.ts +83 -0
  430. package/src/state/persistence.ts +1036 -0
  431. package/src/state/persistence.worker.d.ts +3 -0
  432. package/src/state/persistence.worker.js +264 -0
  433. package/src/state/prefix-cache.ts +685 -0
  434. package/src/state/quantized-kv.ts +369 -0
  435. package/src/state/quantized-tensor.ts +26 -0
  436. package/src/state/request-policy.ts +48 -0
  437. package/src/state/retention-policy.ts +37 -0
  438. package/src/state/rollback.ts +131 -0
  439. package/src/state/rotating-kv-donor.ts +35 -0
  440. package/src/state/rotating-kv-layout.ts +341 -0
  441. package/src/state/rotating-kv.ts +529 -0
  442. package/src/state/rotating-quantized-kv.ts +616 -0
  443. package/src/state/rotating-row-transaction.ts +35 -0
  444. package/src/state/rows.ts +104 -0
  445. package/src/state/softcap-attention.ts +118 -0
  446. package/src/state/speculative/glm52-mtp-state.ts +38 -0
  447. package/src/state/speculative/qwen-mtp-state.ts +34 -0
  448. package/src/state/speculative-rotating-kv.ts +113 -0
  449. package/src/state/ssd-cache.ts +434 -0
  450. package/src/state/ssm-prefill-padding.ts +39 -0
  451. package/src/state/ssm.ts +422 -0
  452. package/src/state/target-layout.ts +7 -0
  453. package/src/state/tiered-prefix-cache.ts +45 -0
  454. package/src/state/training-cache.ts +300 -0
  455. package/src/state/transitioning-kv-rows.ts +267 -0
  456. package/src/state/turboquant-attention.ts +97 -0
  457. package/src/state/turboquant-codec.ts +90 -0
  458. package/src/state/turboquant-kv.ts +442 -0
  459. package/src/state/views.ts +26 -0
  460. package/src/transcription/index.ts +3 -0
  461. package/src/transcription/silero-vad.ts +379 -0
  462. package/src/transcription/whisper/decode.ts +773 -0
  463. package/src/transcription/whisper/format.ts +74 -0
  464. package/src/transcription/whisper/index.ts +4 -0
  465. package/src/transcription/whisper/timing.ts +274 -0
  466. package/src/transcription/whisper/transcribe.ts +394 -0
  467. package/src/transcription/whisper/types.ts +22 -0
@@ -0,0 +1,407 @@
1
+ import { MlxArray } from "@mlx-bun/mlx/array";
2
+ import { Dtype } from "@mlx-bun/mlx/ffi";
3
+ import * as ops from "@mlx-bun/mlx/ops";
4
+ import { MetalKernel } from "@mlx-bun/mlx/metal-kernel";
5
+ import type { TrellisGeometry } from "./geometry";
6
+ import { HEADER, lutFor, decoderVariant, wordsPerBlock } from "./codebook";
7
+ import { TRELLIS_THREADS } from "./launch";
8
+ import { qualifiedRepresentations, type ScatterRepresentation } from "./qualified";
9
+
10
+ const SCATTER_SPLITS = 128;
11
+
12
+ const SCATTER_SOURCE = String.raw`
13
+ threadgroup float lutTG[4096];
14
+ if ((VARIANT) == 2 || FLOAT_CODEBOOK) {
15
+ for (uint i = thread_position_in_threadgroup.x; i < 4096u; i += (uint)THREADS)
16
+ lutTG[i] = FLOAT_CODEBOOK ? trellis_unrefined_bits_y(trellis_y(i)) : lut[i];
17
+ threadgroup_barrier(metal::mem_flags::mem_threadgroup);
18
+ }
19
+ const uint lane = thread_index_in_simdgroup;
20
+ const uint sg = simdgroup_index_in_threadgroup;
21
+ const uint wpb = (uint)(BT * K / 32);
22
+ const uint nb = 32u / wpb; // blocks per SIMD group
23
+ const uint nBlocks = (uint)C / (uint)BT;
24
+ const uint groups = (nBlocks + nb - 1u) / nb;
25
+ const uint group = thread_position_in_grid.y * (uint)SG_TG + sg;
26
+ const uint zi = thread_position_in_grid.z;
27
+ const uint sample = zi / (uint)SPLITS;
28
+ const uint split = zi - sample * (uint)SPLITS;
29
+ const uint bi = lane / wpb;
30
+ const uint wi = lane - bi * wpb;
31
+ const uint blk = group * nb + bi;
32
+ const bool active = (group < groups) && (bi < nb) && (blk < nBlocks) && (sample < (uint)M);
33
+ const uint nbrLane = bi * wpb + ((wi + 1u == wpb) ? 0u : wi + 1u);
34
+ // This lane's positions: symbol offsets p = multiples of K inside [32wi, 32wi+32).
35
+ const uint pBase = 32u * wi;
36
+ const uint p0 = ((pBase + (uint)K - 1u) / (uint)K) * (uint)K;
37
+ uint offs[NP];
38
+ bool valid[NP];
39
+ bool spill[NP];
40
+ uint cols[NP];
41
+ #pragma clang loop unroll(full)
42
+ for (uint i = 0; i < (uint)NP; ++i) {
43
+ const uint p = p0 + i * (uint)K;
44
+ valid[i] = active && (p < pBase + 32u);
45
+ offs[i] = p - pBase;
46
+ spill[i] = offs[i] + (uint)L > 32u;
47
+ const uint t = (uint)BT - 1u - p / (uint)K;
48
+ cols[i] = blk * (uint)BT + t;
49
+ }
50
+ const ulong rowWords = (ulong)(INTERLEAVE ? 2 : nBlocks) * wpb;
51
+ const uint rowsPer = ((uint)R + (uint)SPLITS - 1u) / (uint)SPLITS;
52
+ const uint r0 = split * rowsPer;
53
+ const uint r1 = metal::min((uint)R, r0 + rowsPer);
54
+ const device T* xs = x + (ulong)sample * (ulong)R;
55
+ const device uint32_t* col0 = codes + (INTERLEAVE
56
+ ? (ulong)(blk / 2) * R * 2 * wpb + (blk % 2) * wpb : (ulong)blk * wpb) + wi;
57
+ const uint mask = (1u << (uint)L) - 1u;
58
+ float acc[NP];
59
+ #pragma clang loop unroll(full)
60
+ for (uint i = 0; i < (uint)NP; ++i) acc[i] = 0.0f;
61
+ for (uint r = r0; r < r1; ++r) {
62
+ const uint word = active ? col0[(ulong)r * rowWords] : 0u;
63
+ const uint nxt = metal::simd_shuffle(word, (ushort)nbrLane);
64
+ const float xr = float(xs[r]);
65
+ const float sr = float(scales[r]);
66
+ #pragma clang loop unroll(full)
67
+ for (uint i = 0; i < (uint)NP; ++i) {
68
+ uint win = word >> offs[i];
69
+ if (spill[i]) win |= nxt << (32u - offs[i]);
70
+ win &= mask;
71
+ const float value = FLOAT_CODEBOOK ? lutTG[win] : (BITS_Y ? trellis_unrefined_bits_y(trellis_y(win)) : TRELLIS_DECODE(win, lutTG, lut));
72
+ acc[i] = metal::fma(TRELLIS_ROUND(value * sr), xr, acc[i]);
73
+ }
74
+ }
75
+ const ulong outBase = ((ulong)sample * (ulong)SPLITS + split) * (ulong)C;
76
+ #pragma clang loop unroll(full)
77
+ for (uint i = 0; i < (uint)NP; ++i)
78
+ if (valid[i]) partial[outBase + cols[i]] = acc[i];
79
+ `;
80
+
81
+ const BALANCED_SCATTER_SOURCE = String.raw`
82
+ threadgroup float lutTG[4096];
83
+ if (FLOAT_CODEBOOK) {
84
+ for (uint i = thread_position_in_threadgroup.x; i < 4096u; i += (uint)THREADS)
85
+ lutTG[i] = trellis_unrefined_bits_y(trellis_y(i));
86
+ threadgroup_barrier(metal::mem_flags::mem_threadgroup);
87
+ }
88
+ const uint lane = thread_index_in_simdgroup;
89
+ const uint sg = simdgroup_index_in_threadgroup;
90
+ const uint block = thread_position_in_grid.y * (uint)SG_TG + sg;
91
+ const uint nBlocks = (uint)C / (uint)BT;
92
+ const uint zi = thread_position_in_grid.z;
93
+ const uint sample = zi / (uint)SPLITS;
94
+ const uint split = zi - sample * (uint)SPLITS;
95
+ if (block >= nBlocks || sample >= (uint)M) return;
96
+ const uint wpb = (uint)(BT * K / 32);
97
+ const ulong rowWords = (ulong)(INTERLEAVE ? 2 : nBlocks) * wpb;
98
+ const uint pBase = lane * 8u * (uint)K;
99
+ const uint wi = pBase >> 5u;
100
+ const uint off = pBase & 31u;
101
+ const uint next = (wi + 1u == wpb) ? 0u : wi + 1u;
102
+ const device uint32_t* words = codes + (INTERLEAVE
103
+ ? (ulong)(block / 2) * R * 2 * wpb + (block % 2) * wpb : (ulong)block * wpb);
104
+ const uint rowsPer = ((uint)R + (uint)SPLITS - 1u) / (uint)SPLITS;
105
+ const uint r0 = split * rowsPer;
106
+ const uint r1 = metal::min((uint)R, r0 + rowsPer);
107
+ const device T* xs = x + (ulong)sample * (ulong)R;
108
+ float acc[8];
109
+ #pragma clang loop unroll(full)
110
+ for (uint i = 0; i < 8u; ++i) acc[i] = 0.0f;
111
+ for (uint r = r0; r < r1; ++r) {
112
+ const uint word = words[(ulong)r * rowWords + wi];
113
+ const uint nxt = words[(ulong)r * rowWords + next];
114
+ const uint lo = off == 0u ? word : (word >> off) | (nxt << (32u - off));
115
+ const uint hi = off == 0u ? nxt : nxt >> off;
116
+ const float xr = float(xs[r]);
117
+ const float sr = float(scales[r]);
118
+ #pragma clang loop unroll(full)
119
+ for (uint i = 0; i < 8u; ++i) {
120
+ const uint shift = i * (uint)K;
121
+ uint win = lo >> shift;
122
+ if (shift + (uint)L > 32u) win |= hi << (32u - shift);
123
+ win &= (1u << (uint)L) - 1u;
124
+ const int y = trellis_y(win);
125
+ const float value = FLOAT_CODEBOOK ? lutTG[win] : (BITS_Y ? trellis_unrefined_bits_y(y) : trellis_unrefined_y(y));
126
+ acc[i] = metal::fma(value * sr, xr, acc[i]);
127
+ }
128
+ }
129
+ const ulong outBase = ((ulong)sample * (ulong)SPLITS + split) * (ulong)C;
130
+ #pragma clang loop unroll(full)
131
+ for (uint i = 0; i < 8u; ++i)
132
+ partial[outBase + block * (uint)BT + (uint)BT - 1u - lane * 8u - i] = acc[i];
133
+ `;
134
+
135
+ const SCATTER_SHARED_M_SOURCE = String.raw`
136
+ threadgroup float lutTG[4096];
137
+ if ((VARIANT) == 2) {
138
+ for (uint i = thread_position_in_threadgroup.x; i < 4096u; i += ${TRELLIS_THREADS}u) lutTG[i] = lut[i];
139
+ threadgroup_barrier(metal::mem_flags::mem_threadgroup);
140
+ }
141
+ const uint lane = thread_index_in_simdgroup;
142
+ const uint sg = simdgroup_index_in_threadgroup;
143
+ const uint wpb = (uint)(BT * K / 32);
144
+ const uint nb = 32u / wpb; // blocks per SIMD group
145
+ const uint nBlocks = (uint)C / (uint)BT;
146
+ const uint groups = (nBlocks + nb - 1u) / nb;
147
+ const uint group = thread_position_in_grid.y * (uint)SG_TG + sg;
148
+ const uint zi = thread_position_in_grid.z;
149
+ const uint sample = 0u;
150
+ const uint split = zi;
151
+ const uint bi = lane / wpb;
152
+ const uint wi = lane - bi * wpb;
153
+ const uint blk = group * nb + bi;
154
+ const bool active = (group < groups) && (bi < nb) && (blk < nBlocks) && (sample < (uint)M);
155
+ const uint nbrLane = bi * wpb + ((wi + 1u == wpb) ? 0u : wi + 1u);
156
+ // This lane's positions: symbol offsets p = multiples of K inside [32wi, 32wi+32).
157
+ const uint pBase = 32u * wi;
158
+ const uint p0 = ((pBase + (uint)K - 1u) / (uint)K) * (uint)K;
159
+ uint offs[NP];
160
+ bool valid[NP];
161
+ bool spill[NP];
162
+ uint cols[NP];
163
+ #pragma clang loop unroll(full)
164
+ for (uint i = 0; i < (uint)NP; ++i) {
165
+ const uint p = p0 + i * (uint)K;
166
+ valid[i] = active && (p < pBase + 32u);
167
+ offs[i] = p - pBase;
168
+ spill[i] = offs[i] + (uint)L > 32u;
169
+ const uint t = (uint)BT - 1u - p / (uint)K;
170
+ cols[i] = blk * (uint)BT + t;
171
+ }
172
+ const ulong rowWords = (ulong)(INTERLEAVE ? 2 : nBlocks) * wpb;
173
+ const uint rowsPer = ((uint)R + (uint)SPLITS - 1u) / (uint)SPLITS;
174
+ const uint r0 = split * rowsPer;
175
+ const uint r1 = metal::min((uint)R, r0 + rowsPer);
176
+
177
+ const device uint32_t* col0 = codes + (INTERLEAVE
178
+ ? (ulong)(blk / 2) * R * 2 * wpb + (blk % 2) * wpb : (ulong)blk * wpb) + wi;
179
+ const uint mask = (1u << (uint)L) - 1u;
180
+ float acc[M][NP];
181
+ #pragma clang loop unroll(full)
182
+ for (uint m = 0; m < (uint)M; ++m)
183
+ #pragma clang loop unroll(full)
184
+ for (uint i = 0; i < (uint)NP; ++i) acc[m][i] = 0.0f;
185
+ for (uint r = r0; r < r1; ++r) {
186
+ const uint word = active ? col0[(ulong)r * rowWords] : 0u;
187
+ const uint nxt = metal::simd_shuffle(word, (ushort)nbrLane);
188
+ float xr[M];
189
+ #pragma clang loop unroll(full)
190
+ for (uint m = 0; m < (uint)M; ++m) xr[m] = float(x[(ulong)m * (ulong)R + r]);
191
+ const float sr = float(scales[r]);
192
+ #pragma clang loop unroll(full)
193
+ for (uint i = 0; i < (uint)NP; ++i) {
194
+ uint win = word >> offs[i];
195
+ if (spill[i]) win |= nxt << (32u - offs[i]);
196
+ win &= mask;
197
+ const float weight = TRELLIS_ROUND(TRELLIS_DECODE(win, lutTG, lut) * sr);
198
+ #pragma clang loop unroll(full)
199
+ for (uint m = 0; m < (uint)M; ++m) acc[m][i] = metal::fma(weight, xr[m], acc[m][i]);
200
+ }
201
+ }
202
+ #pragma clang loop unroll(full)
203
+ for (uint m = 0; m < (uint)M; ++m) {
204
+ const ulong outBase = ((ulong)m * (ulong)SPLITS + split) * (ulong)C;
205
+ #pragma clang loop unroll(full)
206
+ for (uint i = 0; i < (uint)NP; ++i)
207
+ if (valid[i]) partial[outBase + cols[i]] = acc[m][i];
208
+ }
209
+ `;
210
+
211
+ const BALANCED_SCATTER_SHARED_M_SOURCE = String.raw`
212
+ // Model-owned tuning selects this table for measured small-M shapes.
213
+ // Store integers so the reciprocal multiply retains its original rounding.
214
+ threadgroup short codebookY[CODEBOOK ? 4096 : 1];
215
+ if (CODEBOOK) {
216
+ for (uint i = thread_position_in_threadgroup.x; i < 4096u; i += threads_per_threadgroup.x)
217
+ codebookY[i] = (short)trellis_y(i);
218
+ threadgroup_barrier(metal::mem_flags::mem_threadgroup);
219
+ }
220
+ const uint lane = thread_index_in_simdgroup;
221
+ const uint sg = simdgroup_index_in_threadgroup;
222
+ const uint block = thread_position_in_grid.y * (uint)SG_TG + sg;
223
+ const uint nBlocks = (uint)C / (uint)BT;
224
+ const uint zi = thread_position_in_grid.z;
225
+ const uint sample = 0u;
226
+ const uint split = zi;
227
+ if (block >= nBlocks || sample >= (uint)M) return;
228
+ const uint wpb = (uint)(BT * K / 32);
229
+ const ulong rowWords = (ulong)(INTERLEAVE ? 2 : nBlocks) * wpb;
230
+ const uint pBase = lane * 8u * (uint)K;
231
+ const uint wi = pBase >> 5u;
232
+ const uint off = pBase & 31u;
233
+ const uint next = (wi + 1u == wpb) ? 0u : wi + 1u;
234
+ const device uint32_t* words = codes + (INTERLEAVE
235
+ ? (ulong)(block / 2) * R * 2 * wpb + (block % 2) * wpb : (ulong)block * wpb);
236
+ const uint rowsPer = ((uint)R + (uint)SPLITS - 1u) / (uint)SPLITS;
237
+ const uint r0 = split * rowsPer;
238
+ const uint r1 = metal::min((uint)R, r0 + rowsPer);
239
+ float acc[M][8];
240
+ #pragma clang loop unroll(full)
241
+ for (uint m = 0; m < (uint)M; ++m)
242
+ #pragma clang loop unroll(full)
243
+ for (uint i = 0; i < 8u; ++i) acc[m][i] = 0.0f;
244
+ for (uint r = r0; r < r1; ++r) {
245
+ const uint word = words[(ulong)r * rowWords + wi];
246
+ const uint nxt = words[(ulong)r * rowWords + next];
247
+ const uint lo = off == 0u ? word : (word >> off) | (nxt << (32u - off));
248
+ const uint hi = off == 0u ? nxt : nxt >> off;
249
+ float xr[M];
250
+ #pragma clang loop unroll(full)
251
+ for (uint m = 0; m < (uint)M; ++m) xr[m] = float(x[(ulong)m * (ulong)R + r]);
252
+ const float sr = float(scales[r]);
253
+ #pragma clang loop unroll(full)
254
+ for (uint i = 0; i < 8u; ++i) {
255
+ const uint shift = i * (uint)K;
256
+ uint win = lo >> shift;
257
+ if (shift + (uint)L > 32u) win |= hi << (32u - shift);
258
+ win &= (1u << (uint)L) - 1u;
259
+ const float value = trellis_unrefined_y(CODEBOOK ? (int)codebookY[win] : trellis_y(win));
260
+ const float weight = value * sr;
261
+ #pragma clang loop unroll(full)
262
+ for (uint m = 0; m < (uint)M; ++m) acc[m][i] = metal::fma(weight, xr[m], acc[m][i]);
263
+ }
264
+ }
265
+ #pragma clang loop unroll(full)
266
+ for (uint m = 0; m < (uint)M; ++m) {
267
+ const ulong outBase = ((ulong)m * (ulong)SPLITS + split) * (ulong)C;
268
+ #pragma clang loop unroll(full)
269
+ for (uint i = 0; i < 8u; ++i)
270
+ partial[outBase + block * (uint)BT + (uint)BT - 1u - lane * 8u - i] = acc[m][i];
271
+ }
272
+ `;
273
+
274
+ let balancedScatter: MetalKernel | null = null;
275
+ let sharedScatter: { generic: MetalKernel; balanced: MetalKernel } | null = null;
276
+ function sharedScatterKernelSet() {
277
+ return sharedScatter ??= {
278
+ generic: new MetalKernel({
279
+ name: "mlx_bun_trellis_scatter_shared_m", inputNames: ["x", "codes", "scales", "lut"],
280
+ outputNames: ["partial"], source: SCATTER_SHARED_M_SOURCE, header: HEADER, ensureRowContiguous: true,
281
+ }),
282
+ balanced: new MetalKernel({
283
+ name: "mlx_bun_trellis_scatter_balanced3_shared_m", inputNames: ["x", "codes", "scales", "lut"],
284
+ outputNames: ["partial"], source: BALANCED_SCATTER_SHARED_M_SOURCE, header: HEADER, ensureRowContiguous: true,
285
+ }),
286
+ };
287
+ }
288
+ function balancedScatterKernel() {
289
+ return balancedScatter ??= new MetalKernel({
290
+ name: "mlx_bun_trellis_scatter_balanced3", inputNames: ["x", "codes", "scales", "lut"],
291
+ outputNames: ["partial"], source: BALANCED_SCATTER_SOURCE, header: HEADER, ensureRowContiguous: true,
292
+ });
293
+ }
294
+ let base: MetalKernel | undefined;
295
+ function scatterKernel(): MetalKernel {
296
+ return base ??= new MetalKernel({ name: "mlx_bun_trellis_scatter",
297
+ inputNames: ["x", "codes", "scales", "lut"], outputNames: ["partial"],
298
+ source: SCATTER_SOURCE, header: HEADER, ensureRowContiguous: true });
299
+ }
300
+
301
+ /** Geometry qualified for the single-row exact-representation kernels. */
302
+ export function scatterBitsEligible(g: TrellisGeometry, m: number, dtype: Dtype, selected: number): boolean {
303
+ return selected === 13 && m === 1 && dtype === Dtype.bfloat16 && g.axis === 0 &&
304
+ g.T === 256 && g.L === 12 && g.rows === 17408 && g.cols === 5120 &&
305
+ (g.k === 3 ? g.blockInterleave === 2 : (g.k === 2 || g.k === 4) && !g.blockInterleave);
306
+ }
307
+
308
+ /** Keep the generated float table behind the measured M1 geometry. */
309
+ export function scatterFloatCodebookEligible(g: TrellisGeometry, m: number, dtype: Dtype, selected: number,
310
+ architecture: string): boolean {
311
+ return qualifiedRepresentations(architecture).scatter.floatCodebook && scatterBitsEligible(g, m, dtype, selected);
312
+ }
313
+
314
+ /** Variants 8..13 decode 3-bit codes at T 256, L <= 12 with the balanced kernels. */
315
+ const balancedFor = (g: TrellisGeometry, selected: number) => selected >= 8 && selected <= 13 && g.k === 3 && g.T === 256 && g.L <= 12;
316
+ /** Variants 10..13 share each decoded weight across rows. */
317
+ const sharesRows = (selected: number) => selected >= 10 && selected <= 13;
318
+ /** The shared-row codebook at 3..4 bf16 rows of the 3-bit block interleave (variant 13), where the layer composes it. */
319
+ const sharedCodebookShape = (g: TrellisGeometry, M: number, dtype: Dtype, selected: number) => selected === 13 &&
320
+ (M === 3 || M === 4) && dtype === Dtype.bfloat16 && g.k === 3 && g.L === 12 && g.T === 256 && g.blockInterleave === 2;
321
+
322
+ /** One activation row of axis-0 codes the balanced kernels do not take (`scatterRow`'s kernel, `SCATTER_SOURCE`):
323
+ * borrow [1, inFeatures]; return owned lazy [1, outFeatures]. `representation` applies where
324
+ * `scatterBitsEligible` holds; layers pass the one they resolved at construction. */
325
+ export function scatterRow(x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry, selected: number,
326
+ representation: ScatterRepresentation): MlxArray {
327
+ if (x2.shape[0] !== 1) throw new Error("scatterRow: expects one activation row");
328
+ if (balancedFor(g, selected)) throw new Error("scatterRow: 3-bit codes at T 256 take balancedScatterRow");
329
+ const qualified = scatterBitsEligible(g, 1, x2.dtype, selected);
330
+ return launch(scatterKernel(), x2, codes, scales, g, selected, false,
331
+ qualified && (g.k === 2 || g.k === 4) && representation.genericBits, qualified && representation.floatCodebook, false);
332
+ }
333
+
334
+ /** One activation row of 3-bit axis-0 codes at T 256 (`BALANCED_SCATTER_SOURCE`, variants 8..13). */
335
+ export function balancedScatterRow(x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry, selected: number,
336
+ representation: ScatterRepresentation): MlxArray {
337
+ if (x2.shape[0] !== 1) throw new Error("balancedScatterRow: expects one activation row");
338
+ if (!balancedFor(g, selected)) throw new Error("balancedScatterRow: needs 3-bit codes at T 256, L <= 12 (variants 8..13)");
339
+ const qualified = scatterBitsEligible(g, 1, x2.dtype, selected);
340
+ return launch(balancedScatterKernel(), x2, codes, scales, g, selected, false,
341
+ qualified && representation.bits, qualified && representation.floatCodebook, false);
342
+ }
343
+
344
+ /** 2..4 activation rows sharing each decoded weight (variants 10..13) of axis-0 codes the balanced kernels do not take. */
345
+ export function scatterRows(x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry, selected: number): MlxArray {
346
+ const M = x2.shape[0]!;
347
+ if (M < 2 || M > 4) throw new Error(`scatterRows: M=${M} outside 2..4`);
348
+ if (!sharesRows(selected) || balancedFor(g, selected)) throw new Error("scatterRows: needs a row-sharing variant (10..13) and codes the balanced kernels do not take");
349
+ return launch(sharedScatterKernelSet().generic, x2, codes, scales, g, selected, true, false, false, false);
350
+ }
351
+
352
+ /** 2..4 activation rows sharing each decoded weight of 3-bit axis-0 codes at T 256 (variants 10..13);
353
+ * `sharedCodebook` applies at three and four bf16 rows of the block interleave (layers pass what they composed). */
354
+ export function balancedScatterRows(x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry, selected: number,
355
+ sharedCodebook: boolean): MlxArray {
356
+ const M = x2.shape[0]!;
357
+ if (M < 2 || M > 4) throw new Error(`balancedScatterRows: M=${M} outside 2..4`);
358
+ if (!sharesRows(selected) || !balancedFor(g, selected)) throw new Error("balancedScatterRows: needs a row-sharing variant (10..13) and 3-bit codes at T 256");
359
+ return launch(sharedScatterKernelSet().balanced, x2, codes, scales, g, selected, true, false, false,
360
+ sharedCodebook && sharedCodebookShape(g, M, x2.dtype, selected));
361
+ }
362
+
363
+ /** Borrow [M, inFeatures] and axis-0 weights; return owned lazy [M, outFeatures].
364
+ * The caller selects a supported variant and limits M to 1..4. `representation`
365
+ * applies where `scatterBitsEligible` holds; layers pass the one they resolved
366
+ * at construction (`qualifiedRepresentations`), benches and tests the one they compare. */
367
+ export function trellisScatter(x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry, selected: number,
368
+ useSharedScatterCodebook: boolean, representation: ScatterRepresentation): MlxArray {
369
+ const M = x2.shape[0]!;
370
+ const balanced = balancedFor(g, selected);
371
+ const shared = sharesRows(selected) && M > 1;
372
+ const qualifiedShape = scatterBitsEligible(g, M, x2.dtype, selected);
373
+ const bitsY = qualifiedShape && (balanced ? representation.bits
374
+ : (g.k === 2 || g.k === 4) && representation.genericBits);
375
+ const floatCodebook = qualifiedShape && representation.floatCodebook;
376
+ const codebook = useSharedScatterCodebook && sharedCodebookShape(g, M, x2.dtype, selected);
377
+ const kernel = shared
378
+ ? balanced ? sharedScatterKernelSet().balanced : sharedScatterKernelSet().generic
379
+ : balanced ? balancedScatterKernel() : scatterKernel();
380
+ return launch(kernel, x2, codes, scales, g, selected, shared, bitsY, floatCodebook, codebook);
381
+ }
382
+
383
+ function launch(kernel: MetalKernel, x2: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry, selected: number,
384
+ shared: boolean, bitsY: boolean, floatCodebook: boolean, codebook: boolean): MlxArray {
385
+ const M = x2.shape[0]!;
386
+ const wpb = wordsPerBlock(g.T, g.k);
387
+ const nb = Math.floor(32 / wpb);
388
+ if (nb < 1) throw new Error(`trellis scatter: block of ${wpb} words exceeds one SIMD group`);
389
+ const groups = Math.ceil((g.cols / g.T) / nb);
390
+ const NP = Math.ceil(32 / g.k);
391
+ const threads = floatCodebook ? (g.k === 3 ? 512 : g.k === 4 ? 256 : 128) : TRELLIS_THREADS;
392
+ const groupsPerThreadgroup = threads / 32;
393
+ const [partial] = kernel.apply([x2, codes, scales, lutFor(g.L)], {
394
+ outputs: [{ shape: [M, SCATTER_SPLITS, g.cols], dtype: Dtype.float32 }],
395
+ grid: [threads, Math.ceil(groups / groupsPerThreadgroup), (shared ? 1 : M) * SCATTER_SPLITS],
396
+ threadGroup: [threads, 1, 1],
397
+ templateDtypes: { T: x2.dtype },
398
+ templateInts: { M, R: g.rows, C: g.cols, BT: g.T, K: g.k, L: g.L, SG_TG: groupsPerThreadgroup,
399
+ SPLITS: SCATTER_SPLITS, NP, VARIANT: decoderVariant(selected), INTERLEAVE: g.blockInterleave ?? 0, CODEBOOK: Number(codebook), BITS_Y: Number(bitsY),
400
+ FLOAT_CODEBOOK: Number(floatCodebook), THREADS: threads },
401
+ });
402
+ const sum = ops.sumAxis(partial!, 1, false);
403
+ partial!.dispose();
404
+ const out = sum.astype(x2.dtype);
405
+ sum.dispose();
406
+ return out;
407
+ }
@@ -0,0 +1,152 @@
1
+ // Packed axis-0 prefill with in-tile weight reconstruction and float partials.
2
+ // Partitioning, SIMD fragment layout and ordered accumulation follow MLX 0.31.2
3
+ // (MIT, Apple Inc.): mlx/backend/metal/matmul.cpp and steel/gemm/kernels/
4
+ // steel_gemm_splitk.h. The shared operation preserves that reduction contract.
5
+ import { MlxArray } from "@mlx-bun/mlx/array";
6
+ import { Dtype } from "@mlx-bun/mlx/ffi";
7
+ import { MetalKernel } from "@mlx-bun/mlx/metal-kernel";
8
+ import type { TrellisGeometry } from "./geometry";
9
+ import { HEADER } from "./codebook";
10
+
11
+ export function splitKTrellisPrefillEligible(g: TrellisGeometry, m: number, dtype: Dtype): boolean {
12
+ return dtype === Dtype.bfloat16 && m >= 5 && m <= 8 &&
13
+ g.axis === 0 && g.T === 256 && g.L === 12 && [2, 3, 4].includes(g.k) &&
14
+ g.inFeatures === 17408 && g.outFeatures === 5120;
15
+ }
16
+
17
+ let partialKernel: MetalKernel | undefined;
18
+ let reductionKernel: MetalKernel | undefined;
19
+ function kernels(): [MetalKernel, MetalKernel] {
20
+ partialKernel ??= new MetalKernel({ name: "mlx_bun_trellis_splitk_prefill",
21
+ inputNames: ["x", "codes", "scales"], outputNames: ["out"],
22
+ header: "#include <metal_simdgroup_matrix>\n" + HEADER, source: String.raw`
23
+ const uint tid=thread_position_in_threadgroup.x;
24
+ const uint lane=thread_index_in_simdgroup;
25
+ const uint sg=simdgroup_index_in_threadgroup;
26
+ const uint mbase=threadgroup_position_in_grid.y*BM;
27
+ const uint nbase=threadgroup_position_in_grid.x*BN;
28
+ const uint fm=((lane/4)&4)+((lane/2)%4);
29
+ const uint fn=((lane/4)&2)*2+(lane%2)*2;
30
+ // The eligible M=5..8 path needs one row of 8x8 SIMD-group tiles.
31
+ constexpr int WM=BM==8?1:2, WN=4/WM, SM=WM*8, SN=WN*8;
32
+ const uint sm=(sg/WN)*8+fm, sn=(sg%WN)*8+fn;
33
+ constexpr int TM=BM/SM, TN=BN/SN;
34
+ threadgroup T As[BM*BK];
35
+ threadgroup T Bs[BK*BN];
36
+ metal::simdgroup_float8x8 acc[TM][TN];
37
+ #pragma clang loop unroll(full)
38
+ for(uint i=0;i<TM;i++) {
39
+ #pragma clang loop unroll(full)
40
+ for(uint j=0;j<TN;j++) {
41
+ acc[i][j].thread_elements()[0]=0.0f;
42
+ acc[i][j].thread_elements()[1]=0.0f;
43
+ }
44
+ }
45
+ constexpr uint wpb=BT*BITS/32;
46
+ const uint split=threadgroup_position_in_grid.z;
47
+ const uint k0=split*PARTITION;
48
+ const uint k1=split+1==SPLITS?KC:k0+PARTITION;
49
+ for(uint kb=k0;kb<k1;kb+=BK) {
50
+ for(uint a=tid;a<BM*BK;a+=128) {
51
+ const uint m=mbase+a/BK, k=kb+a%BK;
52
+ As[(a/BK)*BK+a%BK]=(m<M && k<KC)?x[(ulong)m*KC+k]:T(0);
53
+ }
54
+ for(uint b=tid;b<BK*BN;b+=128) {
55
+ const uint k=kb+b/BN, n=nbase+b%BN;
56
+ T w=T(0);
57
+ if(k<KC && n<N) {
58
+ const uint row=k;
59
+ const uint col=n;
60
+ const uint block=col/BT, t=col%BT;
61
+ const device uint* bw=codes+(INTERLEAVE
62
+ ? (ulong)(block/2)*KC*2*wpb+(ulong)row*2*wpb+(block%2)*wpb
63
+ : (ulong)row*(C/BT)*wpb+block*wpb);
64
+ const uint pos=(BT-1-t)*BITS, wi=pos>>5, off=pos&31u;
65
+ uint win=bw[wi]>>off;
66
+ if(off+L>32)win|=bw[wi+1==wpb?0:wi+1]<<(32-off);
67
+ win&=(1u<<L)-1;
68
+ // Expansion consumes the precise host LUT even for variant 6.
69
+ const float value=trellis_val_rcp(win);
70
+ w=T(value*float(scales[row]));
71
+ }
72
+ Bs[(b/BN)*BN+b%BN]=w;
73
+ }
74
+ threadgroup_barrier(metal::mem_flags::mem_threadgroup);
75
+ #pragma clang loop unroll(full)
76
+ for(uint kk=0;kk<BK;kk+=8) {
77
+ metal::simdgroup_float8x8 a[TM],b[TN];
78
+ #pragma clang loop unroll(full)
79
+ for(uint i=0;i<TM;i++) {
80
+ a[i].thread_elements()[0]=float(As[(sm+i*SM)*BK+kk+fn]);
81
+ a[i].thread_elements()[1]=float(As[(sm+i*SM)*BK+kk+fn+1]);
82
+ }
83
+ #pragma clang loop unroll(full)
84
+ for(uint j=0;j<TN;j++) {
85
+ b[j].thread_elements()[0]=float(Bs[(kk+fm)*BN+sn+j*SN]);
86
+ b[j].thread_elements()[1]=float(Bs[(kk+fm)*BN+sn+j*SN+1]);
87
+ }
88
+ #pragma clang loop unroll(full)
89
+ for(uint i=0;i<TM;i++) {
90
+ #pragma clang loop unroll(full)
91
+ for(uint j=0;j<TN;j++) {
92
+ const uint nj=(i%2)?TN-1-j:j;
93
+ metal::simdgroup_multiply_accumulate(acc[i][nj],a[i],b[nj],acc[i][nj]);
94
+ }
95
+ }
96
+ }
97
+ threadgroup_barrier(metal::mem_flags::mem_threadgroup);
98
+ }
99
+ #pragma clang loop unroll(full)
100
+ for(uint i=0;i<TM;i++) {
101
+ #pragma clang loop unroll(full)
102
+ for(uint j=0;j<TN;j++) {
103
+ const uint m=mbase+sm+i*SM,n=nbase+sn+j*SN;
104
+ if(m<M && n<N)out[(ulong)split*M*N+(ulong)m*N+n]=acc[i][j].thread_elements()[0];
105
+ if(m<M && n+1<N)out[(ulong)split*M*N+(ulong)m*N+n+1]=acc[i][j].thread_elements()[1];
106
+ }
107
+ }
108
+ ` });
109
+ reductionKernel ??= new MetalKernel({ name: "mlx_bun_trellis_splitk_accumulate",
110
+ inputNames: ["partials"], outputNames: ["out"], source: String.raw`
111
+ const uint i = thread_position_in_grid.x;
112
+ if (i >= SIZE) return;
113
+ float total = 0.0f;
114
+ for (uint s = 0; s < SPLITS; s++) total += partials[(ulong)s * SIZE + i];
115
+ out[i] = T(total);
116
+ ` });
117
+ return [partialKernel, reductionKernel];
118
+ }
119
+
120
+ /** Borrow bf16 [M,K] and axis-0 1MAD weights; return owned lazy [M,N].
121
+ * M=5..8, T=256/L=12, k=2/3/4. Match MLX's non-NAX split-K matrix regime;
122
+ * other shapes and hardware require their own dispatch and full-model gates.
123
+ * Peak workspace is SPLITS*M*N float elements, with no dense weight buffer. */
124
+ export function splitKTrellisPrefill(
125
+ x: MlxArray, codes: MlxArray, scales: MlxArray, g: TrellisGeometry,
126
+ ): MlxArray {
127
+ const [m, k] = x.shape, n = g.outFeatures;
128
+ if (x.ndim !== 2 || x.dtype !== Dtype.bfloat16 || !m || m < 5 || m > 8 ||
129
+ k !== g.inFeatures || g.axis !== 0 || g.T !== 256 || g.L !== 12 ||
130
+ ![2, 3, 4].includes(g.k) || g.cols % 256 !== 0 || n < 1 ||
131
+ k < 128 || k < n || Math.ceil(m / 16) * Math.ceil(n / 16) > 1024)
132
+ throw new Error("unsupported split-K trellis prefill geometry or dtype");
133
+ const tilesM = Math.ceil(m / 32), tilesN = Math.ceil(n / 32), tilesK = Math.floor(k / 16);
134
+ const ratio = Math.max(1, Math.floor(tilesK / (tilesM * tilesN)));
135
+ const splits = Math.min(32, Math.max(2, 2 ** Math.ceil(Math.log2(ratio))));
136
+ const partition = Math.floor(tilesK / splits) * 16;
137
+ const [partial, reduce] = kernels();
138
+ const [workspace] = partial.apply([x, codes, scales], {
139
+ outputs: [{ shape: [splits, m, n], dtype: Dtype.float32 }],
140
+ grid: [Math.ceil(n / 32) * 128, 1, splits], threadGroup: [128, 1, 1],
141
+ templateDtypes: { T: x.dtype }, templateInts: { M: m, N: n, KC: k, C: g.cols,
142
+ BITS: g.k, L: g.L, BT: g.T, BM: 8, BN: 32, BK: 16, SPLITS: splits,
143
+ PARTITION: partition, INTERLEAVE: g.blockInterleave ?? 0 },
144
+ });
145
+ try {
146
+ return reduce.apply([workspace!], {
147
+ outputs: [{ shape: [m, n], dtype: x.dtype }],
148
+ grid: [m * n, 1, 1], threadGroup: [256, 1, 1], templateDtypes: { T: x.dtype },
149
+ templateInts: { SIZE: m * n, SPLITS: splits },
150
+ })[0]!;
151
+ } finally { workspace!.dispose(); }
152
+ }