nbxtensor 0.0.1__py3-none-any.whl

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 (291) hide show
  1. nbxtensor/THIRD_PARTY_NOTICES.md +287 -0
  2. nbxtensor/__init__.py +17 -0
  3. nbxtensor/backend/__init__.py +1 -0
  4. nbxtensor/backend/capabilities.py +207 -0
  5. nbxtensor/backend/cpu/__init__.py +1 -0
  6. nbxtensor/backend/cpu/blas.py +102 -0
  7. nbxtensor/backend/cpu/pool.py +204 -0
  8. nbxtensor/backend/cpu_backend.py +162 -0
  9. nbxtensor/backend/device_facts.py +105 -0
  10. nbxtensor/backend/device_files.py +129 -0
  11. nbxtensor/backend/device_names.py +18 -0
  12. nbxtensor/backend/devices/amd/cdna.yml +228 -0
  13. nbxtensor/backend/devices/amd/cdna2.yml +228 -0
  14. nbxtensor/backend/devices/amd/cdna3.yml +227 -0
  15. nbxtensor/backend/devices/apple/apple_m1.yml +266 -0
  16. nbxtensor/backend/devices/apple/apple_m1_max.yml +266 -0
  17. nbxtensor/backend/devices/apple/apple_m1_pro.yml +266 -0
  18. nbxtensor/backend/devices/apple/apple_m1_ultra.yml +266 -0
  19. nbxtensor/backend/devices/apple/apple_m2.yml +266 -0
  20. nbxtensor/backend/devices/apple/apple_m2_max.yml +266 -0
  21. nbxtensor/backend/devices/apple/apple_m2_pro.yml +266 -0
  22. nbxtensor/backend/devices/apple/apple_m2_ultra.yml +266 -0
  23. nbxtensor/backend/devices/apple/apple_m3.yml +266 -0
  24. nbxtensor/backend/devices/apple/apple_m3_max.yml +266 -0
  25. nbxtensor/backend/devices/apple/apple_m3_pro.yml +266 -0
  26. nbxtensor/backend/devices/apple/apple_m3_ultra.yml +266 -0
  27. nbxtensor/backend/devices/apple/apple_m4.yml +266 -0
  28. nbxtensor/backend/devices/apple/apple_m4_max.yml +266 -0
  29. nbxtensor/backend/devices/apple/apple_m4_pro.yml +308 -0
  30. nbxtensor/backend/devices/apple/apple_m5.yml +269 -0
  31. nbxtensor/backend/devices/apple/apple_m5_max.yml +269 -0
  32. nbxtensor/backend/devices/apple/apple_m5_pro.yml +269 -0
  33. nbxtensor/backend/devices/apple/apple_m5_ultra.yml +269 -0
  34. nbxtensor/backend/devices/apple/apple_m6.yml +269 -0
  35. nbxtensor/backend/devices/apple/apple_silicon.yml +263 -0
  36. nbxtensor/backend/devices/nvidia/ampere.yml +214 -0
  37. nbxtensor/backend/devices/nvidia/hopper.yml +213 -0
  38. nbxtensor/backend/devices/nvidia/volta.yml +411 -0
  39. nbxtensor/backend/faults.py +151 -0
  40. nbxtensor/backend/host_memory.py +185 -0
  41. nbxtensor/backend/launcher.py +2350 -0
  42. nbxtensor/backend/launcher_contract.py +429 -0
  43. nbxtensor/backend/metal_backend.py +661 -0
  44. nbxtensor/backend/metal_device.py +1274 -0
  45. nbxtensor/backend/process_memory.py +73 -0
  46. nbxtensor/backend/replay_graph.py +322 -0
  47. nbxtensor/backend/runtime.py +409 -0
  48. nbxtensor/backend/triton_ext_driver.py +735 -0
  49. nbxtensor/dtype/__init__.py +1 -0
  50. nbxtensor/dtype/convert.py +107 -0
  51. nbxtensor/dtype/dtypes.yml +70 -0
  52. nbxtensor/dtype/itemsize.py +166 -0
  53. nbxtensor/dtype/nbx_dtype.py +72 -0
  54. nbxtensor/dtype/operands.py +158 -0
  55. nbxtensor/dtype/outputs.py +64 -0
  56. nbxtensor/dtype/policy.py +155 -0
  57. nbxtensor/dtype/policy.yml +51 -0
  58. nbxtensor/dtype/promotion.py +112 -0
  59. nbxtensor/host.py +55 -0
  60. nbxtensor/io/__init__.py +1 -0
  61. nbxtensor/io/read_rate.py +197 -0
  62. nbxtensor/io/safetensors.py +314 -0
  63. nbxtensor/memory/__init__.py +9 -0
  64. nbxtensor/memory/allocator.py +1988 -0
  65. nbxtensor/memory/arena.py +75 -0
  66. nbxtensor/memory/device_memory.py +150 -0
  67. nbxtensor/memory/device_transfer.py +154 -0
  68. nbxtensor/memory/layout.py +43 -0
  69. nbxtensor/memory/memory_pool.py +191 -0
  70. nbxtensor/memory/metal.py +96 -0
  71. nbxtensor/memory/oom_advice.py +91 -0
  72. nbxtensor/memory/pointer_tables.py +323 -0
  73. nbxtensor/memory/pool.py +507 -0
  74. nbxtensor/memory/shadow.py +43 -0
  75. nbxtensor/memory/slab.py +273 -0
  76. nbxtensor/memory/trace_replay.py +122 -0
  77. nbxtensor/memory/traces/sana-video-2b-720p.16g.2026-11-02.tsv +13610 -0
  78. nbxtensor/memory/vmm.py +118 -0
  79. nbxtensor/ops/__init__.py +1 -0
  80. nbxtensor/ops/_autotune_policy.py +90 -0
  81. nbxtensor/ops/_common.py +32 -0
  82. nbxtensor/ops/_configs.py +1041 -0
  83. nbxtensor/ops/_cost.py +231 -0
  84. nbxtensor/ops/abs.py +17 -0
  85. nbxtensor/ops/adaptive_avg_pool2d.py +161 -0
  86. nbxtensor/ops/add.py +96 -0
  87. nbxtensor/ops/addcdiv.py +29 -0
  88. nbxtensor/ops/addcmul.py +29 -0
  89. nbxtensor/ops/addmv_op.py +64 -0
  90. nbxtensor/ops/addr.py +68 -0
  91. nbxtensor/ops/all_reduce.py +83 -0
  92. nbxtensor/ops/amax.py +40 -0
  93. nbxtensor/ops/any_reduce.py +83 -0
  94. nbxtensor/ops/arange_op.py +27 -0
  95. nbxtensor/ops/argmax.py +107 -0
  96. nbxtensor/ops/argmin.py +93 -0
  97. nbxtensor/ops/atan2.py +71 -0
  98. nbxtensor/ops/attention_wrappers.py +1648 -0
  99. nbxtensor/ops/autotune_bucket.py +137 -0
  100. nbxtensor/ops/autotune_cache.py +430 -0
  101. nbxtensor/ops/autotune_certified.py +1262 -0
  102. nbxtensor/ops/autotune_refusals.py +380 -0
  103. nbxtensor/ops/autotune_settings.py +58 -0
  104. nbxtensor/ops/avg_pool2d.py +73 -0
  105. nbxtensor/ops/baddbmm_op.py +132 -0
  106. nbxtensor/ops/batch_norm.py +163 -0
  107. nbxtensor/ops/binary_strided.py +196 -0
  108. nbxtensor/ops/bitwise_and.py +26 -0
  109. nbxtensor/ops/bitwise_left_shift.py +47 -0
  110. nbxtensor/ops/bitwise_not.py +24 -0
  111. nbxtensor/ops/bitwise_or.py +26 -0
  112. nbxtensor/ops/bitwise_right_shift.py +47 -0
  113. nbxtensor/ops/bucketize.py +37 -0
  114. nbxtensor/ops/cat_op.py +87 -0
  115. nbxtensor/ops/celu.py +20 -0
  116. nbxtensor/ops/clamp.py +24 -0
  117. nbxtensor/ops/clamp_min.py +22 -0
  118. nbxtensor/ops/conv2d.py +265 -0
  119. nbxtensor/ops/conv2d_m8n8k4.py +165 -0
  120. nbxtensor/ops/conv_depthwise2d.py +154 -0
  121. nbxtensor/ops/conv_transpose2d.py +148 -0
  122. nbxtensor/ops/conv_wrappers.py +1482 -0
  123. nbxtensor/ops/copy.py +18 -0
  124. nbxtensor/ops/copy_op.py +39 -0
  125. nbxtensor/ops/cos.py +17 -0
  126. nbxtensor/ops/count_nonzero.py +64 -0
  127. nbxtensor/ops/cross_entropy.py +67 -0
  128. nbxtensor/ops/cummax.py +109 -0
  129. nbxtensor/ops/cummin.py +105 -0
  130. nbxtensor/ops/cumsum.py +244 -0
  131. nbxtensor/ops/decode_attn_vec.py +162 -0
  132. nbxtensor/ops/depthwise_conv2d.py +132 -0
  133. nbxtensor/ops/dequant_gemv.py +190 -0
  134. nbxtensor/ops/dft.py +67 -0
  135. nbxtensor/ops/dispatch.py +1228 -0
  136. nbxtensor/ops/div.py +75 -0
  137. nbxtensor/ops/dot_op.py +67 -0
  138. nbxtensor/ops/dropout.py +23 -0
  139. nbxtensor/ops/dtype_convert.py +42 -0
  140. nbxtensor/ops/elementwise_launch.py +81 -0
  141. nbxtensor/ops/elementwise_wrappers.py +2315 -0
  142. nbxtensor/ops/elu.py +20 -0
  143. nbxtensor/ops/embedding.py +69 -0
  144. nbxtensor/ops/eq.py +32 -0
  145. nbxtensor/ops/erf.py +18 -0
  146. nbxtensor/ops/exp.py +17 -0
  147. nbxtensor/ops/exp2.py +18 -0
  148. nbxtensor/ops/fft_op.py +125 -0
  149. nbxtensor/ops/fill_op.py +20 -0
  150. nbxtensor/ops/flash_attention.py +307 -0
  151. nbxtensor/ops/flash_attention_m8n8k4.py +384 -0
  152. nbxtensor/ops/flash_decode.py +78 -0
  153. nbxtensor/ops/flip_op.py +60 -0
  154. nbxtensor/ops/floor.py +90 -0
  155. nbxtensor/ops/full_op.py +24 -0
  156. nbxtensor/ops/fused_moe.py +417 -0
  157. nbxtensor/ops/fused_moe_m8n8k4.py +99 -0
  158. nbxtensor/ops/fused_upsample_conv.py +413 -0
  159. nbxtensor/ops/gather_op.py +52 -0
  160. nbxtensor/ops/ge.py +32 -0
  161. nbxtensor/ops/gelu.py +31 -0
  162. nbxtensor/ops/gemv_vec.py +80 -0
  163. nbxtensor/ops/glu.py +43 -0
  164. nbxtensor/ops/grid_sampler.py +145 -0
  165. nbxtensor/ops/group_norm_tiled.py +67 -0
  166. nbxtensor/ops/groupnorm.py +123 -0
  167. nbxtensor/ops/gt.py +32 -0
  168. nbxtensor/ops/hardsigmoid.py +18 -0
  169. nbxtensor/ops/hardswish.py +19 -0
  170. nbxtensor/ops/im2col.py +57 -0
  171. nbxtensor/ops/index_add.py +95 -0
  172. nbxtensor/ops/index_put_op.py +92 -0
  173. nbxtensor/ops/index_select.py +121 -0
  174. nbxtensor/ops/index_wrappers.py +770 -0
  175. nbxtensor/ops/isfinite.py +20 -0
  176. nbxtensor/ops/isinf.py +20 -0
  177. nbxtensor/ops/isnan.py +18 -0
  178. nbxtensor/ops/launch_keys.py +1054 -0
  179. nbxtensor/ops/launch_observer.py +54 -0
  180. nbxtensor/ops/layernorm.py +71 -0
  181. nbxtensor/ops/le.py +35 -0
  182. nbxtensor/ops/leaky_relu.py +19 -0
  183. nbxtensor/ops/lerp.py +76 -0
  184. nbxtensor/ops/linalg_wrappers.py +1370 -0
  185. nbxtensor/ops/linspace_op.py +47 -0
  186. nbxtensor/ops/log.py +17 -0
  187. nbxtensor/ops/log_sigmoid.py +23 -0
  188. nbxtensor/ops/logical_and.py +26 -0
  189. nbxtensor/ops/logical_not.py +24 -0
  190. nbxtensor/ops/logical_or.py +26 -0
  191. nbxtensor/ops/logical_xor.py +37 -0
  192. nbxtensor/ops/loss_wrappers.py +282 -0
  193. nbxtensor/ops/lt.py +32 -0
  194. nbxtensor/ops/masked_fill.py +21 -0
  195. nbxtensor/ops/matmul.py +377 -0
  196. nbxtensor/ops/matmul_m8n8k4.py +235 -0
  197. nbxtensor/ops/max_pool2d.py +74 -0
  198. nbxtensor/ops/max_pool3d.py +93 -0
  199. nbxtensor/ops/max_reduce.py +91 -0
  200. nbxtensor/ops/maximum.py +18 -0
  201. nbxtensor/ops/mean.py +40 -0
  202. nbxtensor/ops/min_reduce.py +91 -0
  203. nbxtensor/ops/minimum.py +18 -0
  204. nbxtensor/ops/mish.py +22 -0
  205. nbxtensor/ops/mma_m8n8k4.py +152 -0
  206. nbxtensor/ops/moe_align.py +195 -0
  207. nbxtensor/ops/moe_decode_vec.py +374 -0
  208. nbxtensor/ops/moe_device_residency.py +141 -0
  209. nbxtensor/ops/moe_wrappers.py +345 -0
  210. nbxtensor/ops/mse_loss.py +79 -0
  211. nbxtensor/ops/mul.py +51 -0
  212. nbxtensor/ops/nan_to_num.py +23 -0
  213. nbxtensor/ops/ne.py +32 -0
  214. nbxtensor/ops/neg.py +17 -0
  215. nbxtensor/ops/nllloss.py +124 -0
  216. nbxtensor/ops/nonzero.py +33 -0
  217. nbxtensor/ops/nonzero_op.py +62 -0
  218. nbxtensor/ops/norm_wrappers.py +579 -0
  219. nbxtensor/ops/ones_op.py +20 -0
  220. nbxtensor/ops/oracles/__init__.py +6 -0
  221. nbxtensor/ops/oracles/conv2d_fp64.py +450 -0
  222. nbxtensor/ops/pad_op.py +159 -0
  223. nbxtensor/ops/paged_decode_attn.py +215 -0
  224. nbxtensor/ops/pixel_shuffle.py +144 -0
  225. nbxtensor/ops/pixel_unshuffle.py +72 -0
  226. nbxtensor/ops/pow.py +137 -0
  227. nbxtensor/ops/prod.py +81 -0
  228. nbxtensor/ops/rand_op.py +52 -0
  229. nbxtensor/ops/random_wrappers.py +366 -0
  230. nbxtensor/ops/reciprocal.py +17 -0
  231. nbxtensor/ops/reduction_wrappers.py +845 -0
  232. nbxtensor/ops/relu.py +18 -0
  233. nbxtensor/ops/remainder.py +46 -0
  234. nbxtensor/ops/repeat_interleave.py +48 -0
  235. nbxtensor/ops/repeat_op.py +132 -0
  236. nbxtensor/ops/residual_chain.py +374 -0
  237. nbxtensor/ops/rmsnorm.py +68 -0
  238. nbxtensor/ops/rope.py +142 -0
  239. nbxtensor/ops/rsqrt.py +17 -0
  240. nbxtensor/ops/scaled_softmax.py +96 -0
  241. nbxtensor/ops/scatter_op.py +139 -0
  242. nbxtensor/ops/screen_oracle.py +479 -0
  243. nbxtensor/ops/selu.py +22 -0
  244. nbxtensor/ops/shape_wrappers.py +1032 -0
  245. nbxtensor/ops/sigmoid.py +19 -0
  246. nbxtensor/ops/silu.py +27 -0
  247. nbxtensor/ops/sin.py +17 -0
  248. nbxtensor/ops/softmax.py +169 -0
  249. nbxtensor/ops/softplus.py +27 -0
  250. nbxtensor/ops/sort_op.py +304 -0
  251. nbxtensor/ops/spectral_wrappers.py +481 -0
  252. nbxtensor/ops/sqrt.py +17 -0
  253. nbxtensor/ops/stack_op.py +84 -0
  254. nbxtensor/ops/std.py +113 -0
  255. nbxtensor/ops/strided_copy.py +200 -0
  256. nbxtensor/ops/sub.py +35 -0
  257. nbxtensor/ops/sum.py +40 -0
  258. nbxtensor/ops/tan.py +19 -0
  259. nbxtensor/ops/tanh.py +21 -0
  260. nbxtensor/ops/threshold.py +19 -0
  261. nbxtensor/ops/tiling.yml +91 -0
  262. nbxtensor/ops/tiling_policy.py +43 -0
  263. nbxtensor/ops/tiling_sizes.py +370 -0
  264. nbxtensor/ops/topk.py +267 -0
  265. nbxtensor/ops/trace_op.py +64 -0
  266. nbxtensor/ops/tril.py +64 -0
  267. nbxtensor/ops/triu.py +62 -0
  268. nbxtensor/ops/unfold_op.py +37 -0
  269. nbxtensor/ops/unique_op.py +97 -0
  270. nbxtensor/ops/upsample_bilinear2d.py +106 -0
  271. nbxtensor/ops/upsample_nearest2d.py +52 -0
  272. nbxtensor/ops/upsample_nearest3d.py +61 -0
  273. nbxtensor/ops/var.py +136 -0
  274. nbxtensor/ops/vector_norm.py +216 -0
  275. nbxtensor/ops/weight_norm.py +104 -0
  276. nbxtensor/ops/where.py +39 -0
  277. nbxtensor/ops/wrappers.py +825 -0
  278. nbxtensor/ops/zeros_op.py +20 -0
  279. nbxtensor/quant/__init__.py +1 -0
  280. nbxtensor/quant/quantized_tensor.py +187 -0
  281. nbxtensor/random/__init__.py +1 -0
  282. nbxtensor/random/mt_randn.py +154 -0
  283. nbxtensor/random/rng_pin.py +59 -0
  284. nbxtensor/random/rng_stream.py +118 -0
  285. nbxtensor/random/seeded_draw.py +223 -0
  286. nbxtensor/shape/__init__.py +157 -0
  287. nbxtensor/tensor.py +1867 -0
  288. nbxtensor-0.0.1.dist-info/METADATA +379 -0
  289. nbxtensor-0.0.1.dist-info/RECORD +291 -0
  290. nbxtensor-0.0.1.dist-info/WHEEL +4 -0
  291. nbxtensor-0.0.1.dist-info/licenses/LICENSE +189 -0
@@ -0,0 +1,1054 @@
1
+ """The autotuned kernels' launch decisions as PURE functions of shapes and dtypes.
2
+
3
+ The owner's ruling (2026-09-29 01:37): the census is a DERIVATION from the graphs, never an
4
+ execution. Every key a run forms is a function of the op's operand shapes, operand dtypes and
5
+ attributes, the hardware's `has_native_bf16`, and the profile's bucket ladders — so the key is
6
+ computed here, from those alone, and the wrappers make their launch decisions through the SAME
7
+ functions: one implementation, which the derived census calls without launching anything and the
8
+ wrappers call before they launch. A census shadow run is the proof that the two agree
9
+ (`census.expect_launches`: every recorded key must be one the op's derivation named).
10
+
11
+ Nothing here touches a tensor or a device. The dtypes are `NBXDtype` members; a key's dtype tags
12
+ are the launcher's own spelling (`str` of the Triton dtype, via `_get_tl_dtype`), in the kernel's
13
+ argument order, exactly as `autotune_cache.key_of` appends them.
14
+ """
15
+ from __future__ import annotations
16
+
17
+ from typing import List, Optional, Tuple
18
+
19
+ from nbxtensor.ops import tiling_sizes as _ts
20
+ from nbxtensor.ops.autotune_bucket import bucket_of
21
+ from nbxtensor.dtype.nbx_dtype import NBXDtype
22
+ from nbxtensor.tensor import _get_tl_dtype
23
+
24
+ MATMUL = "nbxtensor.ops.matmul.matmul_kernel"
25
+ ADDMM = "nbxtensor.ops.matmul.addmm_kernel"
26
+ BADDBMM = "nbxtensor.ops.baddbmm_op.baddbmm_kernel"
27
+ CONV2D = "nbxtensor.ops.conv2d.conv2d_forward_kernel"
28
+ DEPTHWISE = "nbxtensor.ops.depthwise_conv2d.depthwise_conv2d_kernel"
29
+ SOFTMAX = "nbxtensor.ops.softmax.softmax_forward_kernel"
30
+ SOFTMAX_LOOPED = "nbxtensor.ops.softmax.softmax_forward_looped_kernel"
31
+ ELEMENTWISE = "nbxtensor.ops.elementwise_launch.ew_launch_kernel"
32
+ GROUP_NORM = "nbxtensor.ops.groupnorm.group_norm_forward_kernel"
33
+ ROW_REDUCE = {"mean": "nbxtensor.ops.mean.mean_forward_kernel",
34
+ "sum": "nbxtensor.ops.sum.sum_forward_kernel",
35
+ "amax": "nbxtensor.ops.amax.amax_forward_kernel"}
36
+ UNIT_FLASH = "nbxtensor.ops.flash_attention_m8n8k4.flash_attention_m8n8k4_kernel"
37
+ FLASH = "nbxtensor.ops.flash_attention.flash_attention_certified_kernel"
38
+ LAYER_NORM = "nbxtensor.ops.layernorm.layer_norm_forward_kernel"
39
+ RMS_NORM = "nbxtensor.ops.rmsnorm.rms_norm_forward_kernel"
40
+ GEMV_VEC = "nbxtensor.ops.gemv_vec.gemv_vec_kernel"
41
+ ADDMV = "nbxtensor.ops.addmv_op.addmv_kernel"
42
+ FUSED_MOE = "nbxtensor.ops.fused_moe.fused_moe_kernel"
43
+ MOE_GATEUP_HALF = "nbxtensor.ops.moe_decode_vec.moe_gateup_vec_half_kernel"
44
+ MOE_DOWN_HALF = "nbxtensor.ops.moe_decode_vec.moe_down_split_vec_half_kernel"
45
+ MOE_PART_REDUCE = "nbxtensor.ops.moe_decode_vec.moe_part_reduce_kernel"
46
+ DECODE_VEC = "nbxtensor.ops.decode_attn_vec.decode_attn_vec_split_kernel"
47
+ PAGED_DECODE = "nbxtensor.ops.paged_decode_attn.paged_decode_attn_split_kernel"
48
+ DECODE_REDUCE = "nbxtensor.ops.flash_decode.flash_decode_reduce_kernel"
49
+ MOE_ALIGN = tuple(f"nbxtensor.ops.moe_align.moe_align_stage{i}_kernel" for i in (1, 2, 3))
50
+
51
+ F32, BF16, F16 = NBXDtype.float32, NBXDtype.bfloat16, NBXDtype.float16
52
+ _HALF = (F16, BF16)
53
+ _WIDEST_FIRST = (F32, BF16, F16)
54
+
55
+ Launch = Tuple[str, tuple] # (kernel qualified name, key tuple as key_of forms it)
56
+
57
+
58
+ def tag(dt: NBXDtype) -> str:
59
+ """A dtype as the autotune key spells it (`str` of the Triton dtype the tensor reports)."""
60
+ return str(_get_tl_dtype(dt))
61
+
62
+
63
+ def _widest(a: NBXDtype, b: NBXDtype) -> NBXDtype:
64
+ return next(d for d in _WIDEST_FIRST if d in (a, b))
65
+
66
+
67
+ def matmul_out_dtype(dt: NBXDtype, M: int, force_fp32: bool, native_bf16: bool,
68
+ force_accum: bool = False, contract_half: bool = False) -> NBXDtype:
69
+ """The store dtype of mm/bmm/addmm/mv/addmv (see `wrappers._matmul_out_dtype` for the why):
70
+ fp32 for any half input under NBX_FORCE_FP32_ACCUM; fp32 for fp16 on hardware without native
71
+ bf16 UNLESS the component's precision contract holds (`contract_half`: the calibration measured
72
+ its activations fp16-safe — the compiled branch stores fp16 there, `_FP16_GEMM_OPS` under the
73
+ contract, and a half graph is served half on both engines, the owner 2026-10-25 20:36); fp32
74
+ for a half input when M <= 4 or when forced, on hardware without native bf16 and no contract;
75
+ otherwise the input dtype. An island's GEMM reaches here with fp32 operands and stores fp32."""
76
+ half = dt in _HALF
77
+ if force_accum and half:
78
+ return F32
79
+ # the contract lifts the store for the product rows the calibration observed — a graph op's prefill or spatial
80
+ # rows; a decode row (M <= 4) keeps the fp32 store that catches decode-loop drift (below): stored fp16 there,
81
+ # MiniCPM-o-4_5 decoded "The!!!!!" and VibeVoice-1.5B said "Thank you." (gate tha3, 2026-10-26; both correct
82
+ # with the decode rows conservative, bisected on a card)
83
+ if dt == F16 and contract_half and M > 4:
84
+ return F16
85
+ if dt == F16 and not native_bf16:
86
+ return F32
87
+ # ONE precision contract (the owner, 2026-10-25 15:26): on hardware that computes bf16 natively a half input
88
+ # stores half — the batched attention GEMM (force_fp32) included; fp32 is stored only for an island or where the
89
+ # hardware has no native half path (above). The compiled branch stores bf16 there (`_wrap_lower_precision`); the
90
+ # Triton branch stored fp32 and spread it (2 017 policy sites on Sana, the Mac). A DECODE ROW (M <= 4) keeps its
91
+ # fp32 store on every hardware: stored half on the M4 Pro (native bf16), whisper-large-v3-turbo's Triton decoder
92
+ # drifted from its first tokens ("Sierrachan... lateral lateral...", stable f8def0b9 -> 58b39d7e; bisected on the
93
+ # Mac 2026-10-28 to d4809a47, this hunk alone) — the same drift the fp16 decode rows showed (MiniCPM-o "The!!!!!").
94
+ if half and (M <= 4 or (force_fp32 and not native_bf16)):
95
+ return F32
96
+ return dt
97
+
98
+
99
+ def mm_dtypes(a: NBXDtype, b: NBXDtype, native_bf16: bool, force_accum: bool = False):
100
+ """`mm`'s operand decisions: (a at launch, b at launch, PROMOTE_A, PROMOTE_B). An fp16
101
+ activation on hardware without native bf16 is widened IN the kernel (PROMOTE_A, a stays fp16
102
+ in memory); a narrow weight under an fp32 activation is widened in the kernel (PROMOTE_B, any
103
+ hardware); any other mismatch widens both in memory to the widest of the pair."""
104
+ if force_accum and a in _HALF:
105
+ a = F32
106
+ if force_accum and b in _HALF:
107
+ b = F32
108
+ promote_a = (not native_bf16) and a == F16
109
+ a_eff = F32 if promote_a else a
110
+ promote_b = a_eff == F32 and b in _HALF
111
+ if a_eff != b and not promote_b:
112
+ if promote_a:
113
+ a, promote_a = F32, False
114
+ w = _widest(a, b)
115
+ a, b = w, w
116
+ return a, b, promote_a, promote_b
117
+
118
+
119
+ def addmm_dtypes(a: NBXDtype, b: NBXDtype, bias: NBXDtype, native_bf16: bool,
120
+ force_accum: bool = False):
121
+ """`addmm`'s operand decisions: (a, b, bias at launch, PROMOTE_A, PROMOTE_B, PROMOTE_BIAS).
122
+ As `mm`, except PROMOTE_B is gated on hardware without native bf16 and on an fp16 weight
123
+ only; the bias is widened in the kernel under an fp32 activation, else cast to a's dtype."""
124
+ if force_accum and a in _HALF:
125
+ a = F32
126
+ if force_accum and b in _HALF:
127
+ b = F32
128
+ promote_a = (not native_bf16) and a == F16
129
+ a_eff = F32 if promote_a else a
130
+ promote_b = (not native_bf16) and a_eff == F32 and b == F16
131
+ if a_eff != b and not promote_b:
132
+ if promote_a:
133
+ a, promote_a = F32, False
134
+ w = _widest(a, b)
135
+ a, b = w, w
136
+ a_eff = a
137
+ promote_bias = bias != a_eff and a_eff == F32 and bias in _HALF
138
+ if bias != a_eff and not promote_bias:
139
+ bias = a_eff
140
+ return a, b, bias, promote_a, promote_b, promote_bias
141
+
142
+
143
+ def bmm_dtypes(a: NBXDtype, b: NBXDtype, native_bf16: bool, force_accum: bool = False):
144
+ """`bmm`'s operand decisions: (a, b at launch, PROMOTE_B). An fp16 activation on hardware
145
+ without native bf16 is widened in memory (bmm has no PROMOTE_A); an fp16 weight under fp32 is
146
+ widened in the kernel on that hardware; any other mismatch widens both to the widest."""
147
+ if force_accum and a in _HALF:
148
+ a = F32
149
+ if force_accum and b in _HALF:
150
+ b = F32
151
+ if (not native_bf16) and a == F16:
152
+ a = F32
153
+ promote_b = (not native_bf16) and a == F32 and b == F16
154
+ if a != b and not promote_b:
155
+ w = _widest(a, b)
156
+ a, b = w, w
157
+ return a, b, promote_b
158
+
159
+
160
+ def matrix_unit_operands(a: NBXDtype, b: NBXDtype, M: int, unit: Optional[dict] = None):
161
+ """(rep_a, rep_b): how the profile's matrix unit carries each operand of a GEMM with M output rows, as they are
162
+ in memory — the DtypeEngine's `matrix_unit_representation` ("native", "split") — or None: either operand has
163
+ none, or M does not fill the smallest tile the profile lists for that representation (a row band mostly empty
164
+ leaves the unit idle; the GEMV / batched kernels own those rows, and a row's reduction order then never
165
+ depends on how many rows share its launch). The wrappers' `_gemm_unit_tile` asks this same function. `unit`: a
166
+ matrix unit already read (a planner's, for the device it plans); the profile in force's when None."""
167
+ from nbxtensor.ops._configs import matrix_unit
168
+ from nbxtensor.dtype.operands import matrix_unit_representation # the library's operand rules
169
+ mu = matrix_unit() if unit is None else unit
170
+ ra, rb = matrix_unit_representation(a.name, mu), matrix_unit_representation(b.name, mu)
171
+ if not (ra and rb):
172
+ return None
173
+ rows = (mu["fp32_split"] if "split" in (ra, rb) else mu)["mm"]
174
+ return (ra, rb) if M >= min(int(r["block_m"]) for r in rows) else None
175
+
176
+
177
+ def matrix_unit_takes(a: NBXDtype, b: NBXDtype, M: int) -> bool:
178
+ """The profile's matrix unit can run this GEMM (`matrix_unit_operands`). A batched product on it has NO autotune
179
+ key (`bmm_launches`, `baddbmm_launches` return []); `mm` and `addmm` keep their FMA key, whose certificate chose
180
+ between the two routes."""
181
+ return matrix_unit_operands(a, b, M) is not None
182
+
183
+
184
+ def gemm_row_representative(m_bucket: int, a: NBXDtype, b: NBXDtype, unit_keyed: bool = False) -> Optional[int]:
185
+ """The largest row count M whose GEMM launch forms the autotune key of M bucket `m_bucket`: its bucket is
186
+ `m_bucket` (`bucket_of`) and the matrix unit does not take it (`matrix_unit_takes`). A bucket's top is not always
187
+ one: on Volta the class 57..64 of an fp32 GEMM keys M_BUCKET 64, and at 64 itself the split matrix unit takes the
188
+ GEMM (no key) — a certification synthesising M=64 never reached the autotuner (2026-10-19, 172 keys). Every row
189
+ count down to one is a candidate: a batched GEMM keys its rows however few (`bmm_launches`, no GEMV below five rows
190
+ as `mm` has) — stopping at five refused every bmm key of buckets 1-4 as a census defect (80 attention keys on the
191
+ Mac, 2026-10-20). `unit_keyed`: a GEMM whose key the unit's route keeps (mm, addmm: `mm_launches`) — every row
192
+ count of the bucket forms it. None: no row count forms the key."""
193
+ m = int(m_bucket)
194
+ while m >= 1 and bucket_of("M", m) == m_bucket:
195
+ if unit_keyed or not matrix_unit_takes(a, b, m):
196
+ return m
197
+ m -= 1
198
+ return None
199
+
200
+
201
+ def matrix_unit_conv_operands(x: NBXDtype, w: NBXDtype, M: int, N: int, kh: int, kw: int,
202
+ unit: Optional[dict] = None):
203
+ """(the operands' representations, the tile rows) of a convolution's implicit GEMM on the profile's matrix unit
204
+ (M output positions, N output channels per group, a kh x kw window), or None: the GEMM's own rule
205
+ (`matrix_unit_operands`) and, for a split operand, a `matrix_unit.fp32_split.conv` row for that window whose tile
206
+ the GEMM fills (M >= block_m, N >= block_n) — the split was measured faster than the FMA path only there (a 3x3 is
207
+ slower at every tile: volta.yml). Native operands take the `mm` rows (rows None). The wrappers, their cost and the
208
+ census ask this one function."""
209
+ from nbxtensor.ops._configs import matrix_unit
210
+ reps = matrix_unit_operands(x, w, M, unit)
211
+ if reps is None or "split" not in reps:
212
+ return None if reps is None else (reps, None)
213
+ mu = matrix_unit() if unit is None else unit
214
+ rows = [r for r in ((mu.get("fp32_split") or {}).get("conv") or [])
215
+ if [int(v) for v in r["kernel"]] == [int(kh), int(kw)] and M >= int(r["block_m"]) and N >= int(r["block_n"])]
216
+ return (reps, rows) if rows else None
217
+
218
+
219
+ def mv_launches(N: int, K: int, mat: NBXDtype, vec: NBXDtype, native_bf16: bool,
220
+ force_accum: bool = False, contract_half: bool = False) -> List[Launch]:
221
+ """`mv_wrapper` on a [N, K] matrix and a [K] vector: the SIMT GEMV's key — the N and K buckets, then the dtype
222
+ tags of the matrix, the vector and the output (`matmul_out_dtype` of the matrix at one row)."""
223
+ out = matmul_out_dtype(mat, 1, False, native_bf16, force_accum, contract_half)
224
+ return [(GEMV_VEC, (bucket_of("N", N), bucket_of("K", K), tag(mat), tag(vec), tag(out)))]
225
+
226
+
227
+ def addmv_launches(N: int, K: int, mat: NBXDtype, vec: NBXDtype, bias: NBXDtype, native_bf16: bool,
228
+ force_accum: bool = False, contract_half: bool = False) -> List[Launch]:
229
+ """`addmv_wrapper` on a [N, K] matrix, a [K] vector and a [N] bias: the key — the N and K buckets (K the kernel's
230
+ `M`), then the dtype tags of the matrix, the vector, the bias and the output (`matmul_out_dtype` at one row)."""
231
+ out = matmul_out_dtype(mat, 1, False, native_bf16, force_accum, contract_half)
232
+ return [(ADDMV, (bucket_of("N", N), bucket_of("M", K), tag(mat), tag(vec), tag(bias), tag(out)))]
233
+
234
+
235
+ def mm_launches(M: int, K: int, N: int, a: NBXDtype, b: NBXDtype, native_bf16: bool,
236
+ force_accum: bool = False, contract_half: bool = False) -> List[Launch]:
237
+ """`mm` (and `mm_epilogue`): M <= 4 runs one GEMV per row on the operands as `mm_dtypes` casts them (the weight
238
+ transposed to [N, K], each activation row the vector) — one key; otherwise one key, matrix unit or not — row bands
239
+ above 2^31 output elements keep the whole shape's M bucket."""
240
+ a, b, promote_a, promote_b = mm_dtypes(a, b, native_bf16, force_accum)
241
+ if M <= 4:
242
+ return mv_launches(N, K, b, a, native_bf16, force_accum, contract_half)
243
+ # where the matrix unit can take it too, the key is the FMA launch's: its certificate measured both routes and
244
+ # names the faster (`linalg_wrappers._gemm_route`), the unit's tile included
245
+ out = matmul_out_dtype(a, M, promote_a, native_bf16, force_accum, contract_half)
246
+ ieee = (not native_bf16) and out == F32
247
+ return [(MATMUL, (bucket_of("M", M), N, K, ieee, promote_b, tag(a), tag(b), tag(out)))]
248
+
249
+
250
+ def addmm_launches(M: int, K: int, N: int, a: NBXDtype, b: NBXDtype, bias: NBXDtype,
251
+ native_bf16: bool, force_accum: bool = False, contract_half: bool = False, bias_row: bool = True) -> List[Launch]:
252
+ """`addmm` on a 2-D activation (an N-D one is flattened to (numel/K, K) first): M <= 4 runs
253
+ per-row addmv; otherwise one key, whose certificate decides the matrix unit or the FMA kernel where a [N] / [1, N]
254
+ bias (`bias_row`) lets the unit take it."""
255
+ a, b, bias, promote_a, promote_b, _ = addmm_dtypes(a, b, bias, native_bf16, force_accum)
256
+ if M <= 4:
257
+ # one addmv per row on the operands as cast, the weight transposed to [N, K], the bias its row or the shared one
258
+ return addmv_launches(N, K, b, a, bias, native_bf16, force_accum, contract_half)
259
+ out = matmul_out_dtype(a, M, promote_a, native_bf16, force_accum, contract_half)
260
+ ieee = (not native_bf16) and out == F32
261
+ return [(ADDMM, (bucket_of("M", M), N, K, ieee, promote_b, tag(a), tag(b), tag(bias), tag(out)))]
262
+
263
+
264
+ def bmm_launches(M: int, K: int, N: int, a: NBXDtype, b: NBXDtype, native_bf16: bool,
265
+ force_accum: bool = False, contract_half: bool = False) -> List[Launch]:
266
+ """`bmm`: always one batched launch through `baddbmm_kernel` (HAS_BIAS False, the output
267
+ passed as the bias pointer), every dim bucketed, the output fp32 for any half input; on the matrix unit
268
+ (M > 4, operands taken as they are in memory, before the widening) no key."""
269
+ if matrix_unit_takes(a, b, M):
270
+ return []
271
+ a, b, promote_b = bmm_dtypes(a, b, native_bf16, force_accum)
272
+ out = matmul_out_dtype(a, M, True, native_bf16, force_accum, contract_half)
273
+ ieee = (not native_bf16) and out == F32
274
+ return [(BADDBMM, (bucket_of("M", M), bucket_of("N", N), bucket_of("K", K),
275
+ ieee, promote_b, False, tag(a), tag(b), tag(out), tag(out)))]
276
+
277
+
278
+ def baddbmm_launches(M: int, K: int, N: int, a: NBXDtype, b: NBXDtype, bias: NBXDtype) -> List[Launch]:
279
+ """`baddbmm_wrapper`: one batched launch at the operands' own dtypes (no promotion, no
280
+ widened store: the output is batch1's dtype), IEEE_PRECISION and HAS_BIAS set, PROMOTE_B
281
+ off, every dim bucketed; the bias pointer keyed at its own dtype. On the matrix unit (M > 4) no key."""
282
+ if matrix_unit_takes(a, b, M):
283
+ return []
284
+ return [(BADDBMM, (bucket_of("M", M), bucket_of("N", N), bucket_of("K", K),
285
+ True, False, True, tag(a), tag(b), tag(a), tag(bias)))]
286
+
287
+
288
+ def mm_out(M: int, a: NBXDtype, b: NBXDtype, native_bf16: bool, force_accum: bool = False, contract_half: bool = False) -> NBXDtype:
289
+ """The dtype `mm` stores for these operands (its launch or its per-row GEMV alike)."""
290
+ a, b, promote_a, _ = mm_dtypes(a, b, native_bf16, force_accum)
291
+ return matmul_out_dtype(a, M, promote_a, native_bf16, force_accum, contract_half)
292
+
293
+
294
+ def bmm_out(M: int, a: NBXDtype, b: NBXDtype, native_bf16: bool, force_accum: bool = False, contract_half: bool = False) -> NBXDtype:
295
+ """The dtype `bmm` stores for these operands: on the matrix unit the operands are taken as they are in memory
296
+ (no widening, `wrappers.bmm`'s unit branch), elsewhere as `bmm_dtypes` widens them — under the fp16 contract the
297
+ two differ (fp16 on the unit, fp32 off it on hardware without native bf16)."""
298
+ if matrix_unit_takes(a, b, M):
299
+ return matmul_out_dtype(a, M, True, native_bf16, force_accum, contract_half)
300
+ a, b, _ = bmm_dtypes(a, b, native_bf16, force_accum)
301
+ return matmul_out_dtype(a, M, True, native_bf16, force_accum, contract_half)
302
+
303
+
304
+ def row_breakpoints(lo: int, hi: int) -> List[int]:
305
+ """The row counts M in (lo, hi] at which a GEMM's launch CLASS changes on the bound profile: the GEMV bound
306
+ (M <= 4 launches no autotuned kernel), the M bucket (`bucket_of("M", M)`: exact below the matrix unit's smallest
307
+ tile, bucketed above), and the matrix unit's take-over for the native and the split operand representations
308
+ (no key from there on). A census that walks a token axis (a prompt's length) derives at every breakpoint and
309
+ bisects between two: the key set at M is a step function of M only between breakpoints — below and above the
310
+ keyed band it is empty at both ends, which a bisection alone takes for one class (TinyLlama, 2026-10-19:
311
+ a 31-token prompt's matmul key missed under certified-only). One source: the launcher's own functions."""
312
+ lo, hi = int(lo), int(hi)
313
+ if hi <= lo:
314
+ return []
315
+ half, single = NBXDtype.float16, NBXDtype.float32
316
+ def klass(m: int):
317
+ return (m <= 4, bucket_of("M", m), matrix_unit_takes(half, half, m), matrix_unit_takes(single, half, m))
318
+ out: List[int] = []
319
+ prev = klass(max(lo, 1))
320
+ for m in range(max(lo, 1) + 1, hi + 1):
321
+ k = klass(m)
322
+ if k != prev:
323
+ out.append(m)
324
+ prev = k
325
+ return out
326
+
327
+
328
+ def matmul_route(a_rank: int, b_rank: int) -> str:
329
+ """`matmul_wrapper`'s route by operand ranks (torch.matmul semantics): "mm" (2-D x 2-D), "bmm"
330
+ (3-D x 3-D), "mv" (2-D x 1-D, the SIMT GEMV), "batched" (N-D x 2-D:
331
+ the leading dims folded into bmm's batch), "general" (N-D x N-D: both batches collapsed)."""
332
+ if a_rank == 2 and b_rank == 2:
333
+ return "mm"
334
+ if a_rank == 3 and b_rank == 3:
335
+ return "bmm"
336
+ if a_rank == 2 and b_rank == 1:
337
+ return "mv"
338
+ if a_rank >= 3 and b_rank == 2:
339
+ return "batched"
340
+ if a_rank >= 3 and b_rank >= 3:
341
+ return "general"
342
+ raise ValueError(f"matmul: unsupported ranks {a_rank} x {b_rank}")
343
+
344
+
345
+ def matmul_launches(a_shape, b_shape, a: NBXDtype, b: NBXDtype, native_bf16: bool,
346
+ force_accum: bool = False, contract_half: bool = False) -> List[Launch]:
347
+ """`matmul_wrapper` (and `linear_wrapper`, which calls it with the transposed weight): the
348
+ launch of the route `matmul_route` names — bmm's key carries no batch."""
349
+ route = matmul_route(len(a_shape), len(b_shape))
350
+ if route == "mm":
351
+ return mm_launches(a_shape[0], a_shape[1], b_shape[1], a, b, native_bf16, force_accum, contract_half)
352
+ if route == "mv":
353
+ return mv_launches(a_shape[0], a_shape[1], a, b, native_bf16, force_accum, contract_half)
354
+ return bmm_launches(a_shape[-2], a_shape[-1], b_shape[-1], a, b, native_bf16, force_accum, contract_half)
355
+
356
+
357
+ # ---------------------------------------------------------------------------------------------
358
+ # Recurrence and spectra: `lstm_wrapper` and the DFT route of the FFT wrappers, as the matmul
359
+ # launches their generic calls make.
360
+ # ---------------------------------------------------------------------------------------------
361
+
362
+ def lstm_launches(B: int, T: int, I: int, H: int, num_layers: int, bidirectional: bool,
363
+ x: NBXDtype, native_bf16: bool) -> List[Launch]:
364
+ """`lstm_wrapper` -> `_lstm_run_direction`, per layer and direction: the input projection
365
+ x[B,T,I] @ W_ih^T (matmul's N-D x 2-D route: `bmm` over B batches of [T, I]), then one
366
+ h[B,H] @ W_hh^T `mm` per step. The weights and the initial state are cast to the input's
367
+ dtype `x` (`cdt`, read once); the elementwise gate arithmetic promotes to the wider operand,
368
+ so the state after a step is the widest of the projection's, the step mm's and `x`, and a
369
+ later layer reads the concatenation at its FIRST operand's dtype (`NBXTensor.cat`): the
370
+ forward direction's first step. The state's dtype is iterated to its fixed point (it can
371
+ only widen), so the step keys are every dtype the state takes."""
372
+ nd = 2 if bidirectional else 1
373
+ out: List[Launch] = []
374
+ layer_in = x
375
+ for layer in range(int(num_layers)):
376
+ first_fwd = None
377
+ for d in range(nd):
378
+ out += bmm_launches(T, I if layer == 0 else H * nd, 4 * H, layer_in, x, native_bf16) # never the contract
379
+ wx = bmm_out(T, layer_in, x, native_bf16)
380
+ h, seen, first = x, set(), None
381
+ for _step in range(max(int(T), 0)):
382
+ if h in seen:
383
+ break
384
+ seen.add(h)
385
+ out += mm_launches(B, H, 4 * H, h, x, native_bf16) # the recurrence: never the contract
386
+ h = _widest(_widest(wx, mm_out(B, h, x, native_bf16)), x)
387
+ first = h if first is None else first
388
+ if d == 0:
389
+ first_fwd = first if first is not None else x
390
+ layer_in = first_fwd
391
+ return list(dict.fromkeys(out))
392
+
393
+
394
+ def dft_r2c_launches(M: int, N: int, onesided: bool, native_bf16: bool) -> List[Launch]:
395
+ """`fft_r2c_wrapper` on a length that is not a power of two: `_dft_r2c`, the frames flattened
396
+ to [M, N] and widened to fp32, times the fp32 cos and -sin matrices (two `mm`). A power of
397
+ two runs the radix-2 butterfly (no autotuned kernel)."""
398
+ if N > 1 and (N & (N - 1)) == 0:
399
+ return []
400
+ bins = N // 2 + 1 if onesided else N
401
+ return mm_launches(M, N, bins, F32, F32, native_bf16)
402
+
403
+
404
+ def dft_c2r_launches(M: int, bins: int, N: int, native_bf16: bool) -> List[Launch]:
405
+ """`fft_c2r_wrapper` -> `_dft_c2r`, any length: the complex64 spectrum's real and imaginary
406
+ parts [M, bins] times the fp32 inverse matrices [bins, N] (two `mm`, one key)."""
407
+ return mm_launches(M, bins, N, F32, F32, native_bf16)
408
+
409
+
410
+ def stft_launches(lead: int, length: int, n_fft: int, hop_length: Optional[int],
411
+ win_length: Optional[int], onesided: Optional[bool],
412
+ native_bf16: bool) -> List[Launch]:
413
+ """`stft_wrapper` on a signal of `lead` rows x `length` samples: frames of win_length every
414
+ hop_length (`unfold`, defaults n_fft // 4 and n_fft as the wrapper's), each zero-padded to
415
+ n_fft, then `fft_r2c_wrapper` over [lead x frames, n_fft] — `dft_r2c_launches`'s rule (a
416
+ power-of-two n_fft runs the butterfly: no autotuned key)."""
417
+ hop = (n_fft // 4) if hop_length in (None, 0) else int(hop_length)
418
+ win = n_fft if win_length in (None, 0) else int(win_length)
419
+ frames = (int(length) - win) // hop + 1
420
+ return dft_r2c_launches(int(lead) * frames, int(n_fft),
421
+ True if onesided is None else bool(onesided), native_bf16)
422
+
423
+
424
+ def istft_launches(batch: int, bins: int, frames: int, n_fft: int,
425
+ native_bf16: bool) -> List[Launch]:
426
+ """`istft_wrapper` on a [batch, bins, frames] spectrum: `fft_c2r_wrapper` over the frames
427
+ [batch x frames, bins] to n_fft samples each (`dft_c2r_launches`); the overlap-add and the
428
+ window envelope launch no autotuned kernel."""
429
+ return dft_c2r_launches(int(batch) * int(frames), int(bins), int(n_fft), native_bf16)
430
+
431
+
432
+ # ---------------------------------------------------------------------------------------------
433
+ # Attention (scaled_dot_product_attention): the route, then the math route's two bmm launches.
434
+ # ---------------------------------------------------------------------------------------------
435
+
436
+ def sdpa_operand_dtypes(q: NBXDtype, k: NBXDtype, v: NBXDtype,
437
+ q_round: Optional[NBXDtype] = None, *, alignment: Optional[str] = None):
438
+ """The (q, k, v, q_round) dtypes `scaled_dot_product_attention_wrapper` computes attention
439
+ with: the DtypeEngine's decision (`nbxtensor/dtype/operands.attention_operand_dtypes`) under
440
+ `alignment` — `precision.attention_operands` of the hardware the attention runs on. The
441
+ wrapper and the derived census run ON that hardware and leave it None (the active profile);
442
+ Prism plans for a profile that need not be the process's and passes that profile's answer
443
+ (`Profile.attention_operands`, read by `triton/dtype.profile_attention_operand_alignment`). All three ask this one function, so none holds a rule of
444
+ its own."""
445
+ from nbxtensor.dtype.operands import attention_operand_alignment, attention_operand_dtypes # the library's operand rules
446
+ qj = q_round if q_round is not None else q
447
+ if qj == k == v:
448
+ return q, k, v, q_round
449
+ if alignment is None:
450
+ from nbxtensor.ops._configs import active_vendor_profile
451
+ alignment = attention_operand_alignment(active_vendor_profile())
452
+ out = attention_operand_dtypes(q.name, k.name, v.name, alignment,
453
+ q_round.name if q_round is not None else None)
454
+ return tuple(None if d is None else NBXDtype[d] for d in out)
455
+
456
+
457
+ def decode_vec_takes(headdim: int, headdim_v: int, mask_numel: Optional[int], seqlen_k: int) -> bool:
458
+ """Whether a single-query attention on the math route runs the vector decode kernel
459
+ (`decode_vec_launches`) — `_try_decode_vec`'s contract: equal head dims, and a mask that is one bias
460
+ per key (or none). Outside it, the math route's two bmm launches."""
461
+ if headdim != headdim_v:
462
+ return False
463
+ return mask_numel is None or mask_numel == seqlen_k
464
+
465
+
466
+ def _pow2(n: int) -> bool:
467
+ return n > 0 and (n & (n - 1)) == 0
468
+
469
+
470
+ def flash_any_head_dim() -> bool:
471
+ """The arch's profile MEASURED the tl.dot flash kernel correct at every head dim (`flash.any_head_dim_correct`):
472
+ a head dim that is not a power of two runs in the kernel's power-of-two head-dim block, the columns past it masked
473
+ to zero on load (`EVEN_HEADDIM` False), so it routes like a power of two — on the device's scores budget — instead
474
+ of on `sdpa.non_pow2_head_scores_bytes` to the math attention, which writes the scores. An arch that has not
475
+ measured it keeps the math route."""
476
+ from nbxtensor.ops._configs import active_vendor_profile
477
+ return ((active_vendor_profile().get("flash") or {}).get("any_head_dim_correct")) is True
478
+
479
+
480
+ def flash_tiles_certified() -> bool:
481
+ """The tl.dot flash's tile is certified per key (workstream 1) where the profile declares no hand table of tiles
482
+ (`sdpa_thresholds`); a profile that declares one launches its rows as before."""
483
+ from nbxtensor.ops._configs import active_vendor_profile
484
+ return not active_vendor_profile().get("sdpa_thresholds")
485
+
486
+
487
+ def flash_launches(Tq: int, Tk: int, D: int, q: NBXDtype, k: NBXDtype, v: NBXDtype,
488
+ bias: Optional[NBXDtype] = None) -> List[Launch]:
489
+ """The tl.dot flash where its tile is certified (`flash_tiles_certified`): its autotune key — the query rows'
490
+ bucket, the keys' bucket, the head dim — then, as Triton appends them, the dtypes of its seven tensors (Q, K, V, the
491
+ bias — the mask's, or Q's for the zero / causal bias the wrapper builds —, the output like Q, the fp32 log-sum-exp
492
+ and its fp32 scratch). No key where the profile's hand table chooses the tile."""
493
+ if not flash_tiles_certified():
494
+ return []
495
+ return [(FLASH, (bucket_of("M", Tq), bucket_of("N", Tk), int(D),
496
+ tag(q), tag(k), tag(v), tag(bias if bias is not None else q), tag(q), tag(F32), tag(F32)))]
497
+
498
+
499
+ def sdpa_chunk_rows(bound: int, batch: int, nheads: int, Tq: int, Tk: int,
500
+ min_chunk_rows: int, max_chunks: int) -> int:
501
+ """Query rows per chunk that keep each chunk's fp32 scores within `bound`, aligned to the
502
+ arch's row block (`memory.sdpa_math_min_chunk_rows`); 0 when the shape cannot chunk within
503
+ the arch's chunk ceiling (`memory.sdpa_math_max_chunks`). The TilingEngine sizes it
504
+ (`tiling_sizes.sdpa_chunk_rows`)."""
505
+ return _ts.sdpa_chunk_rows(bound, batch, nheads, Tq, Tk, min_chunk_rows, max_chunks)
506
+
507
+
508
+ def flash_headdim_detour(D: int, enabled: bool = True) -> int:
509
+ """The head dim the flash route runs at: a power of two >= 128 is zero-padded by one
510
+ (`scaled_dot_product_attention_wrapper`'s detour around the flash kernel's wrong answers at
511
+ those dims), and the padded call re-enters the wrapper — routed afresh at D + 1 (and V's head
512
+ dim + 1). `enabled` False is the wrapper's diagnostic `NBX_D128_DETOUR=0`."""
513
+ if not (enabled and D >= 128 and (D & (D - 1)) == 0):
514
+ return D
515
+ # An arch whose profile MEASURED the flash kernel correct at these dims on its stack runs them
516
+ # as they are: the defect was a code-generation one of an older Triton (P-FLASH-D128-CORRECTNESS,
517
+ # Volta; Dao-AILab names the class on A100), and on Triton 3.8 the 33-case attention oracle
518
+ # passes with the detour off on a V100 (2026-10-03). Every arch that has not measured it keeps
519
+ # the detour.
520
+ from nbxtensor.ops._configs import active_vendor_profile
521
+ if ((active_vendor_profile().get("flash") or {}).get("pow2_head_dim_correct")) is True:
522
+ return D
523
+ return D + 1
524
+
525
+
526
+ CONV_WEIGHT_LAYOUTS = ("KCRS", "KRSC")
527
+
528
+
529
+ def conv_weight_layout() -> str:
530
+ """The order a convolution weight is stored in on this arch: the hardware profile's
531
+ `conv.weight_layout`, "KCRS" (the container's own) or "KRSC" (channels innermost: the 3x3
532
+ taps of one output read one contiguous channel run; +46-63 % on the M4 Pro, 2026-10-07). A
533
+ profile that does not state it is refused by name; with no profile in force (no device) the
534
+ weights stay in the container's order."""
535
+ from nbxtensor.ops._configs import active_vendor_profile
536
+ profile = active_vendor_profile()
537
+ if not profile:
538
+ return "KCRS"
539
+ layout = (profile.get("conv") or {}).get("weight_layout")
540
+ if layout not in CONV_WEIGHT_LAYOUTS:
541
+ raise ValueError(f"the hardware profile states conv.weight_layout={layout!r}; every profile "
542
+ f"states one of {CONV_WEIGHT_LAYOUTS}")
543
+ return layout
544
+
545
+
546
+ def conv_weight_krsc(w_shape, groups: int, transposed: bool, layout: str) -> bool:
547
+ """Whether a convolution weight of this shape is stored KRSC under `layout`: a 2-D, not
548
+ transposed convolution with a spatial extent (a 1x1 weight is the same memory in both
549
+ orders) that is not depthwise (one channel a group and a group per output: its kernel reads
550
+ no channel stride)."""
551
+ if layout != "KRSC" or transposed or len(w_shape) != 4:
552
+ return False
553
+ K, Cg, kh, kw = w_shape
554
+ return kh * kw > 1 and not (Cg == 1 and groups == K)
555
+
556
+
557
+ def krsc_conv_weights(dag: dict, layout: str) -> set:
558
+ """The tensor ids of the graph weights stored KRSC: every reader of the weight is a
559
+ convolution that takes it (`conv_weight_krsc`); a weight any other op reads keeps the order
560
+ that op expects."""
561
+ tensors, ops = dag.get("tensors") or {}, dag.get("ops") or {}
562
+ taken, refused = set(), set()
563
+ for uid in dag.get("execution_order") or []:
564
+ o = ops.get(uid) or {}
565
+ ins = o.get("input_tensor_ids") or []
566
+ if o.get("op_type") == "aten::convolution" and len(ins) > 1:
567
+ at = o.get("attributes") or {}
568
+ meta = tensors.get(ins[1]) or {}
569
+ ok = conv_weight_krsc(meta.get("shape") or [], int(at.get("groups", 1)),
570
+ bool(at.get("transposed", False)), layout)
571
+ (taken if ok else refused).add(ins[1])
572
+ rest = ins[:1] + ins[2:]
573
+ else:
574
+ rest = ins
575
+ refused.update(rest)
576
+ return {t for t in taken - refused if t.startswith(("param::", "buffer::"))}
577
+
578
+
579
+ def is_krsc_weight(w) -> bool:
580
+ """A logical (K, C, R, S) weight whose memory is (K, R, S, C), contiguous."""
581
+ if len(w.shape) != 4:
582
+ return False
583
+ K, C, R, S = w.shape
584
+ return tuple(w.stride()) == (R * S * C, 1, S * C, C)
585
+
586
+
587
+ def unit_flash(D: int, q: NBXDtype, k: NBXDtype, v: NBXDtype,
588
+ unit: Optional[dict] = None) -> Optional[Tuple[str, dict]]:
589
+ """(representation, tile) of this attention's flash on the profile's matrix unit, or None: the DtypeEngine's
590
+ `matrix_unit_flash_representation` ("native": the three operands are the unit's operand dtype; "split": they are
591
+ among `fp32_split.operands`, carried as hi + lo) and the first row of `matrix_unit.flash` — or of
592
+ `matrix_unit.fp32_split.flash` for the split — holding head dim D. The wrapper launches with this function.
593
+ `unit`: a matrix unit already read (`_configs.matrix_unit(vendor_profile)`: Prism, for the device it plans); the
594
+ profile in force's when None."""
595
+ from nbxtensor.ops._configs import matrix_unit, matrix_unit_flash_tile
596
+ from nbxtensor.dtype.operands import matrix_unit_flash_representation # the library's operand rules
597
+ mu = matrix_unit() if unit is None else unit
598
+ rep = matrix_unit_flash_representation(q.name, k.name, v.name, mu)
599
+ if rep is None:
600
+ return None
601
+ tile = matrix_unit_flash_tile(D, mu["fp32_split"] if rep == "split" else mu)
602
+ return (rep, tile) if tile is not None else None
603
+
604
+
605
+ def unit_flash_takes(D: int, q: NBXDtype, k: NBXDtype, v: NBXDtype, unit: Optional[dict] = None) -> bool:
606
+ """The profile's matrix unit runs this attention's flash (`unit_flash`) — the wrappers' route, the derived
607
+ census and Prism's priced scratch ask this same function."""
608
+ return unit_flash(D, q, k, v, unit) is not None
609
+
610
+
611
+ def unit_flash_launches(Tq: int, Tk: int, D: int, q: NBXDtype, k: NBXDtype, v: NBXDtype,
612
+ bias: Optional[NBXDtype] = None) -> List[Launch]:
613
+ """The flash on the profile's matrix unit (`unit_flash`, ops/flash_attention_m8n8k4.py): its autotune key — the
614
+ query rows' bucket, the keys' bucket, the head dim, the split representation — then, as Triton appends them, the
615
+ dtypes of its six tensors (Q, K, V, the bias — the mask's, or Q's for the zero / causal bias the wrapper builds —,
616
+ the output like Q, the fp32 log-sum-exp). Its tile (query rows, keys per step, warps) is certified per key
617
+ (workstream 1: the profile's hand table of tiles per head dim retired). No key where the unit does not take it."""
618
+ got = unit_flash(D, q, k, v)
619
+ if got is None:
620
+ return []
621
+ return [(UNIT_FLASH, (bucket_of("M", Tq), bucket_of("N", Tk), int(D), got[0] == "split",
622
+ tag(q), tag(k), tag(v), tag(bias if bias is not None else q), tag(q), tag(F32)))]
623
+
624
+
625
+ def sdpa_route(batch: int, nheads: int, Tq: int, Tk: int, D: int, Dv: int, budget_bytes: int,
626
+ min_chunk_rows: int, max_chunks: int, force_math: bool = False,
627
+ unit_flash: bool = False) -> Tuple[str, int]:
628
+ """The attention route: ("math", 0), ("chunked", rows) or ("flash", 0). Math when forced or
629
+ when the value head dim differs; else by the fp32 scores' size against the executing device's
630
+ budget — a non-power-of-two head dim routes on `sdpa.non_pow2_head_scores_bytes` (config/
631
+ tiling.yml) when the arch declares none and has not measured the flash at every head dim (`flash_any_head_dim`);
632
+ over the bound, flash when the profile's matrix unit takes it (`unit_flash_takes`: the
633
+ deterministic m8n8k4 kernel), else chunked when the rows fit the arch's ceiling; otherwise flash."""
634
+ if force_math or Dv != D:
635
+ return ("math", 0)
636
+ scores = _ts.sdpa_scores_bytes(batch, nheads, Tq, Tk)
637
+ bound = _ts.sdpa_scores_bound(budget_bytes, _pow2(D) or flash_any_head_dim())
638
+ if scores <= bound:
639
+ return ("math", 0)
640
+ if unit_flash:
641
+ return ("flash", 0)
642
+ if bound:
643
+ rows = sdpa_chunk_rows(bound, batch, nheads, Tq, Tk, min_chunk_rows, max_chunks)
644
+ if rows:
645
+ return ("chunked", rows)
646
+ return ("flash", 0)
647
+
648
+
649
+ def math_attention_launches(B: int, H: int, Hk: int, Tq: int, Tk: int, D: int, Dv: int,
650
+ q: NBXDtype, k: NBXDtype, v: NBXDtype, native_bf16: bool,
651
+ force_accum: bool = False, contract_half: bool = False) -> List[Launch]:
652
+ """`_math_attention`: scores = bmm(q as [B*Hk, groups*Tq, D], k^T) — q in its (possibly
653
+ rounded) dtype, k in its own; then p = softmax(scores) cast to v's dtype and bmm(p, v)."""
654
+ M = (H // Hk) * Tq
655
+ # the scores are the first product's output (`bmm_out`: on the matrix unit the operands as they are in memory,
656
+ # elsewhere widened — fp32 for any half input without the fp16 contract, fp16 on the unit under it): the route's
657
+ # softmax runs on B * H * Tq rows of Tk columns at that dtype (`wrappers.softmax`, workstream 1)
658
+ scores = bmm_out(M, q, k, native_bf16, force_accum, contract_half)
659
+ return (bmm_launches(M, D, Tk, q, k, native_bf16, force_accum, contract_half)
660
+ + softmax_launches(B * H * Tq, Tk, False, scores, scores)
661
+ + bmm_launches(M, Tk, Dv, v, v, native_bf16, force_accum, contract_half))
662
+
663
+
664
+ def chunked_math_attention_launches(B: int, H: int, Hk: int, Tq: int, Tk: int, D: int, Dv: int,
665
+ q: NBXDtype, k: NBXDtype, v: NBXDtype, native_bf16: bool,
666
+ rows: int, force_accum: bool = False, contract_half: bool = False) -> List[Launch]:
667
+ """`_math_attention_chunked`: the math route over query-row chunks of `rows`, the last one the
668
+ remainder — each chunk forms its own pair of keys."""
669
+ out: List[Launch] = []
670
+ for c in {min(rows, Tq)} | ({Tq % rows} if Tq % rows else set()):
671
+ out += math_attention_launches(B, H, Hk, c, Tk, D, Dv, q, k, v, native_bf16, force_accum, contract_half)
672
+ return out
673
+
674
+
675
+ # ---------------------------------------------------------------------------------------------
676
+ # Convolutions: conv2d (and conv1d as H=1, conv3d as kt conv2d launches), depthwise, bands.
677
+ # ---------------------------------------------------------------------------------------------
678
+
679
+ _NARROWEST_FIRST = (F16, BF16, F32)
680
+
681
+
682
+ def conv_width_key(in_h: int, out_h: int, in_w: int, out_w: int, kw: int, stride_w: int, pad_w: int,
683
+ dil_w: int) -> Tuple[int, int]:
684
+ """The width a convolution's key carries: a ONE-ROW convolution (a 1-D conv over a sequence)
685
+ keys its width on the profile's W ladder, the output width derived from the input's top by the
686
+ convolution's arithmetic; a 2-D convolution keeps its exact extents."""
687
+ if int(in_h) == 1 and int(out_h) == 1:
688
+ top = int(bucket_of("W", int(in_w)))
689
+ return top, (top + 2 * int(pad_w) - int(dil_w) * (int(kw) - 1) - 1) // int(stride_w) + 1
690
+ return int(in_w), int(out_w)
691
+
692
+
693
+ def conv_dtypes(x: NBXDtype, w: NBXDtype) -> Tuple[NBXDtype, NBXDtype]:
694
+ """A convolution's operands, narrowed to the narrowest of the pair when they differ."""
695
+ if x != w:
696
+ n = next(d for d in _NARROWEST_FIRST if d in (x, w))
697
+ return n, n
698
+ return x, w
699
+
700
+
701
+ def conv_out_hw(in_h, in_w, kh, kw, sh, sw, ph, pw, dh, dw) -> Tuple[int, int]:
702
+ return ((in_h + 2 * ph - dh * (kh - 1) - 1) // sh + 1,
703
+ (in_w + 2 * pw - dw * (kw - 1) - 1) // sw + 1)
704
+
705
+
706
+ def conv2d_route(N: int, in_c: int, out_c: int, out_h: int, out_w: int, dh: int, dw: int, groups: int,
707
+ x: NBXDtype, band_bytes: int, depthwise_enabled: bool = True) -> str:
708
+ """"depthwise" (groups == in_c == out_c at dilation 1), "band" (the output, sized at the
709
+ input's dtype, over `band_bytes`) or "plain" — the order the wrapper tests them in."""
710
+ from nbxtensor.dtype.nbx_dtype import dtype_size
711
+ if depthwise_enabled and groups == in_c and groups == out_c and dh == 1 and dw == 1:
712
+ return "depthwise"
713
+ if N * out_c * out_h * out_w * dtype_size(x) > band_bytes:
714
+ return "band"
715
+ return "plain"
716
+
717
+
718
+ class ConvRowOverBand(ValueError):
719
+ """A convolution whose single output row is over the band budget: band streaming cannot split
720
+ it, and the per-band recursion would call itself on the same row without end."""
721
+
722
+
723
+ def conv2d_band_rows(N: int, out_c: int, out_h: int, out_w: int, out_bytes: int, band_bytes: int) -> int:
724
+ """The output rows of one band of `conv2d_wrapper`'s band streaming (`_conv2d_band_streamed`):
725
+ bands of about `conv2d.band_budget_divisor` of the budget, evenly cut, sized by the
726
+ TilingEngine (`tiling_sizes.conv2d_band_rows`). A band that cannot be smaller than the output —
727
+ one row already over the budget — is refused by name: the recursion it would start calls the
728
+ same row forever (a 1-row codec conv, found by the derived census 2026-09-29)."""
729
+ band_oh, row_bytes = _ts.conv2d_band_rows(N, out_c, out_h, out_w, out_bytes, band_bytes)
730
+ if band_oh >= out_h:
731
+ raise ConvRowOverBand(
732
+ f"conv2d output [{N}, {out_c}, {out_h}, {out_w}]: one row is {row_bytes} bytes, over "
733
+ f"the band budget {band_bytes}; band streaming cannot split it")
734
+ return band_oh
735
+
736
+
737
+ def conv2d_launches(N: int, in_c: int, in_h: int, in_w: int, out_c: int, kh: int, kw: int,
738
+ sh: int, sw: int, ph: int, pw: int, dh: int, dw: int, groups: int,
739
+ x: NBXDtype, w: NBXDtype, compute: Optional[NBXDtype], band_bytes: int,
740
+ depthwise_enabled: bool = True, unit: Optional[dict] = None) -> List[Launch]:
741
+ """`conv2d_wrapper` on a 4-D weight: narrowing; the depthwise stencil when groups == in_c ==
742
+ out_c at dilation 1; band streaming (per-band recursion at the original padding) when the
743
+ output, sized at the INPUT's dtype, exceeds `band_bytes`; otherwise one `conv2d_forward_kernel`
744
+ launch. The output dtype is the run's compute dtype when set (`_NBX_COMPUTE_DTYPE`), else the
745
+ input's. The `fp16` key flag names an fp16 input (fixed 2026-09-29, aaad1c48; the entries were
746
+ re-keyed in place)."""
747
+ from nbxtensor.dtype.nbx_dtype import dtype_size
748
+ out_h, out_w = conv_out_hw(in_h, in_w, kh, kw, sh, sw, ph, pw, dh, dw)
749
+ if out_h <= 0 or out_w <= 0:
750
+ return []
751
+ x, w = conv_dtypes(x, w)
752
+ out = compute if compute is not None else x
753
+ route = conv2d_route(N, in_c, out_c, out_h, out_w, dh, dw, groups, x, band_bytes, depthwise_enabled)
754
+ if route == "depthwise":
755
+ iw_k, ow_k = conv_width_key(in_h, out_h, in_w, out_w, kw, sw, pw, 1)
756
+ return [(DEPTHWISE, (in_c, in_h, iw_k, out_h, ow_k, kh, kw, sh, sw, ph, pw, x == F16,
757
+ tag(x), tag(w), tag(out)))]
758
+ xb = dtype_size(x)
759
+ if route == "band":
760
+ band_oh = conv2d_band_rows(N, out_c, out_h, out_w, xb, band_bytes)
761
+ out_launches: List[Launch] = []
762
+ for oh0 in range(0, out_h, band_oh):
763
+ oh1 = min(oh0 + band_oh, out_h)
764
+ ih0 = max(0, oh0 * sh - ph)
765
+ ih1 = min(in_h, (oh1 - 1) * sh + dh * (kh - 1) + 1 - ph)
766
+ if ih1 <= ih0:
767
+ continue
768
+ for l in conv2d_launches(N, in_c, ih1 - ih0, in_w, out_c, kh, kw, sh, sw, ph, pw, dh, dw,
769
+ groups, x, w, compute, band_bytes, depthwise_enabled, unit):
770
+ if l not in out_launches:
771
+ out_launches.append(l)
772
+ return out_launches
773
+ if matrix_unit_conv_operands(x, w, N * out_h * out_w, out_c // max(1, groups), kh, kw, unit) is not None: # on the matrix unit: no key
774
+ return []
775
+ iw_k, ow_k = conv_width_key(in_h, out_h, in_w, out_w, kw, sw, pw, dw)
776
+ return [(CONV2D, (N, in_c, in_h, iw_k, out_c, out_h, ow_k, kh, kw, sh, sw, ph, pw, dh, dw, groups,
777
+ x == F16, tag(x), tag(w), tag(out)))]
778
+
779
+
780
+ def tiled_conv2d_bands(IH: int, out_h: int, kh: int, sh: int, dh: int, pad_h: int, tile_factor: int):
781
+ """The bands of Prism's op-level tiled conv — `tiling_sizes.tiled_conv2d_bands`, the one cut the run, the census
782
+ and Prism's price of the band read."""
783
+ return _ts.tiled_conv2d_bands(IH, out_h, kh, sh, dh, pad_h, tile_factor)
784
+
785
+
786
+ def tiled_conv2d_launches(N: int, in_c: int, IH: int, IW: int, out_c: int, kh: int, kw: int,
787
+ sh: int, sw: int, ph: int, pw: int, dh: int, dw: int, groups: int,
788
+ x: NBXDtype, w: NBXDtype, compute: Optional[NBXDtype], band_bytes: int,
789
+ tile_factor: int) -> List[Launch]:
790
+ """The launches of an op-level tiled conv: per band of `tiled_conv2d_bands`, the band's rows
791
+ (padded by the image-edge rows, and by pad_w on both sides whenever any padding applies) run
792
+ through `conv2d_wrapper` at padding 0."""
793
+ out_h = (IH + 2 * ph - dh * (kh - 1) - 1) // sh + 1
794
+ out: List[Launch] = []
795
+ for _o0, _o1, start, end, pt, pb, _ht in tiled_conv2d_bands(IH, out_h, kh, sh, dh, ph, tile_factor):
796
+ padded = pt > 0 or pb > 0 or pw > 0
797
+ bh = end - start + pt + pb
798
+ bw = IW + 2 * pw if padded else IW
799
+ for l in conv2d_launches(N, in_c, bh, bw, out_c, kh, kw, sh, sw, 0, 0, dh, dw, groups,
800
+ x, w, compute, band_bytes):
801
+ if l not in out:
802
+ out.append(l)
803
+ return out
804
+
805
+
806
+ def conv_launches(x_shape, w_shape, stride, padding, dilation, transposed: bool, groups: int,
807
+ x: NBXDtype, w: NBXDtype, compute: Optional[NBXDtype], band_bytes: int,
808
+ depthwise_enabled: bool = True, native_bf16: Optional[bool] = None, contract_half: bool = False,
809
+ output_padding=0) -> List[Launch]:
810
+ """`conv2d_wrapper` by the weight's rank: a transposed convolution forms no autotuned key; a
811
+ 3-D weight is conv1d as conv2d at H = 1; a 5-D weight is conv3d as kt conv2d launches over
812
+ [B*T_out, Cin, H, W] (identical keys). REPRODUCED as the census forms it: the chunked conv3d
813
+ variant is gated by the driver's free bytes, which a census answers -1 — a live run can chunk
814
+ and form keys this derivation does not (named)."""
815
+ def _n(v, n):
816
+ v = list(v) if isinstance(v, (list, tuple)) else [v]
817
+ return v + [v[-1]] * (n - len(v)) if len(v) < n else v[:n]
818
+ if transposed:
819
+ # a 1-D transposed conv of groups 1, dilation 1, no output padding runs a GEMM x^T [L, C_in] @ W [C_in, C_out * K]
820
+ # per batch sample (`conv_wrappers._conv_transpose1d_gemm`) and an overlap-add with no key; any other keeps the
821
+ # scatter kernel, which has no key
822
+ if len(w_shape) == 3 and groups == 1 and _n(dilation, 1)[0] == 1 and _n(output_padding, 1)[0] == 0:
823
+ if native_bf16 is None:
824
+ raise ValueError("ZERO FALLBACK: conv_launches of a 1-D transposed conv needs native_bf16 (its GEMM's key)")
825
+ narrowest = next(d for d in (F16, NBXDtype.bfloat16, F32) if d in (x, w)) if x != w else x
826
+ return mm_launches(int(x_shape[2]), int(w_shape[0]), int(w_shape[1]) * int(w_shape[2]), narrowest, narrowest,
827
+ native_bf16, contract_half=contract_half)
828
+ return []
829
+ if len(w_shape) == 3:
830
+ N, C, L = x_shape
831
+ Co, Cg, K = w_shape
832
+ s, p, d = _n(stride, 1)[0], _n(padding, 1)[0], _n(dilation, 1)[0]
833
+ return conv2d_launches(N, C, 1, L, Co, 1, K, 1, s, 0, p, 1, d, groups, x, w, compute,
834
+ band_bytes, depthwise_enabled)
835
+ if len(w_shape) == 5:
836
+ B, Cin, T, H, W = x_shape
837
+ Cout, Cg, kt, kh, kw = w_shape
838
+ st, sh, sw = _n(stride, 3)
839
+ pt, ph, pw = _n(padding, 3)
840
+ dt, dh, dw = _n(dilation, 3)
841
+ T_out = (T + 2 * pt - dt * (kt - 1) - 1) // st + 1
842
+ if T_out <= 0:
843
+ return []
844
+ # temporal stride 1: every tap read and written in place, ONE conv2d per batch sample over its frames
845
+ # [T_out, Cin, H, W] (`wrappers.conv3d_wrapper`, the taps-in-place path) — the key's batch is T_out; other
846
+ # strides: the frames of every sample stacked, [B*T_out, Cin, H, W]. Keyed B*T_out for both, a guidance-batch
847
+ # conv3d (SANA-Video's patch embed, B=2) formed a key the census never derived (W1+Apple gate, 2026-10-22).
848
+ return conv2d_launches(T_out if st == 1 else B * T_out, Cin, H, W, Cout, kh, kw, sh, sw, ph, pw, dh, dw,
849
+ groups, x, w, compute, band_bytes, depthwise_enabled)
850
+ N, C, H, W = x_shape
851
+ Co, Cg, kh, kw = w_shape
852
+ sh, sw = _n(stride, 2)
853
+ ph, pw = _n(padding, 2)
854
+ dh, dw = _n(dilation, 2)
855
+ return conv2d_launches(N, C, H, W, Co, kh, kw, sh, sw, ph, pw, dh, dw, groups, x, w, compute,
856
+ band_bytes, depthwise_enabled)
857
+
858
+
859
+ #: The longest row the single-program softmax holds (a row's padded length in registers); a longer one runs the looped
860
+ #: kernel (`softmax_forward_looped_kernel`, one tile at a time, keyed as the single-program one). Moved here from the
861
+ #: wrapper so the wrapper and the census read ONE value.
862
+ SOFTMAX_FUSED_MAX_FEAT = 16384
863
+
864
+
865
+ def softmax_feat_bucket(feat: int) -> int:
866
+ """The row length's class in a softmax key: the padded row the program holds (`BLOCK_SIZE_FEAT`, the next power of
867
+ two) — every config's tile, its register budget and its candidates' pruning are those of the padded row, so one
868
+ certified entry serves every length that pads to it (keyed by the exact length, a decoder's KV positions made one
869
+ key per position: 11 504 keys on 16 GB, 2026-10-20)."""
870
+ return 1 << max(0, int(feat) - 1).bit_length()
871
+
872
+
873
+ def softmax_launches(rows: int, feat: int, log: bool, x: NBXDtype, out: NBXDtype) -> List[Launch]:
874
+ """`softmax` / `log_softmax` over a row of `feat` (rows = every other element): the single-program kernel's key —
875
+ the rows' bucket (`bucket_of("M")`), the padded row length (`softmax_feat_bucket`), the log flag, the input's and the output's dtype;
876
+ a row longer than the single program holds (`SOFTMAX_FUSED_MAX_FEAT`) the looped kernel's, keyed alike (workstream
877
+ 1: rows per program and warps certified per key; chantier 1: the looped kernel's tile and warps)."""
878
+ if rows < 1:
879
+ return []
880
+ kernel = SOFTMAX_LOOPED if feat > SOFTMAX_FUSED_MAX_FEAT else SOFTMAX
881
+ return [(kernel, (bucket_of("M", rows), softmax_feat_bucket(feat), bool(log), tag(x), tag(out)))]
882
+
883
+
884
+ def layer_norm_launches(rows: int, feat: int, has_weight: bool, has_bias: bool, x: NBXDtype,
885
+ w: Optional[NBXDtype], b: Optional[NBXDtype], out: NBXDtype) -> List[Launch]:
886
+ """`wrappers.native_layer_norm` over rows of `feat` (the normalized extent; every other element a row): the key —
887
+ the rows' bucket (`bucket_of("M")`), the padded row (`softmax_feat_bucket`: the program holds the next power of
888
+ two, one certified entry per padding), the weight and bias flags (a bias without a weight is not applied, as the
889
+ wrapper reads it), the statistics always saved — then the dtype tags of its tensor arguments in order: input,
890
+ weight (the input standing in when there is none), bias (likewise), mean and inverse deviation (fp32), output."""
891
+ if rows < 1 or feat < 1:
892
+ return []
893
+ bias = bool(has_bias and has_weight)
894
+ wt = w if has_weight else x
895
+ bt = b if bias else x
896
+ return [(LAYER_NORM, (bucket_of("M", rows), softmax_feat_bucket(feat), bool(has_weight), bias, True,
897
+ tag(x), tag(wt), tag(bt), tag(F32), tag(F32), tag(out)))]
898
+
899
+
900
+ def rms_norm_launches(rows: int, feat: int, has_weight: bool, x: NBXDtype, w: Optional[NBXDtype],
901
+ out: NBXDtype) -> List[Launch]:
902
+ """`wrappers.rms_norm` over rows of `feat` (the last dim): the key — the rows' bucket, the padded row, the weight
903
+ flag, the protected fp16 store (`nbx_tensor._saturating_cast` from fp32, the kernel's accumulator, to the output's
904
+ dtype) — then the dtype tags of input, weight (the input standing in when there is none), output."""
905
+ if rows < 1 or feat < 1:
906
+ return []
907
+ from nbxtensor.tensor import _saturating_cast
908
+ return [(RMS_NORM, (bucket_of("M", rows), softmax_feat_bucket(feat), bool(has_weight),
909
+ bool(_saturating_cast(F32, out)), tag(x), tag(w if has_weight else x), tag(out)))]
910
+
911
+
912
+ def elementwise_classes(largest: int) -> List[Launch]:
913
+ """Every element-wise class (`ops/elementwise_launch.ew_bucket`: the profile's `elements` ladder, else its
914
+ `default`) a component can launch: each class whose floor is at most `largest`, the most elements any tensor of
915
+ the component holds — an element-wise launch writes or reads at most one tensor's elements (an op's output, a
916
+ copy, a cast, a weight converted at load). Keyed as the shared copy is (`ew_launch_kernel`: the class's top and
917
+ its two fp32 operands)."""
918
+ from nbxtensor.ops.autotune_bucket import ladder_for
919
+ largest = max(1, int(largest))
920
+ out, prev = [], 0
921
+ for bound, step in ladder_for("elements"):
922
+ hi = largest if bound is None else min(bound, largest)
923
+ top = -(-(prev + 1) // step) * step
924
+ while prev < hi and top - step < hi:
925
+ out.append((ELEMENTWISE, (top, "fp32", "fp32")))
926
+ top += step
927
+ if bound is not None and top > bound:
928
+ break
929
+ if bound is None or largest <= bound:
930
+ break
931
+ prev = bound
932
+ return out
933
+
934
+
935
+ def group_norm_launches(N: int, C: int, HxW: int, groups: int, has_weight: bool, has_bias: bool, x: NBXDtype,
936
+ w: Optional[NBXDtype], b: Optional[NBXDtype]) -> List[Launch]:
937
+ """`wrappers.group_norm_wrapper` (one program per batch x group, the group's channel x spatial extent walked in
938
+ chunks): the key — the programs' bucket (`bucket_of("M")`), the group's padded extent (`softmax_feat_bucket`),
939
+ the weight and bias flags — then the dtype tags of its tensor arguments in order: input, output (the input's),
940
+ weight and bias (the input standing in for an absent one), mean and inverse deviation (fp32)."""
941
+ if N < 1 or C < 1 or HxW < 1 or groups < 1:
942
+ return []
943
+ hidden = (C // groups) * HxW
944
+ return [(GROUP_NORM, (bucket_of("M", N * groups), softmax_feat_bucket(hidden), bool(has_weight), bool(has_bias),
945
+ tag(x), tag(x), tag(w if has_weight else x), tag(b if has_bias else x),
946
+ tag(F32), tag(F32)))]
947
+
948
+
949
+ def row_reduce_launches(kind: str, rows: int, feat: int, x: NBXDtype) -> List[Launch]:
950
+ """`wrappers.mean_wrapper` / `sum_wrapper` / `amax_wrapper` over rows of `feat` (the reduced elements: one dim, a
951
+ list flattened by `_reduce_over_dims`, or all of them; every other element a row): the key — the rows' bucket
952
+ (`bucket_of("M")`), the padded row (`softmax_feat_bucket`) — then the input's dtype tag (after the `dtype` keyword's
953
+ cast) and the output's: fp32 for mean and sum (cast after), the input's for amax."""
954
+ if rows < 1 or feat < 1:
955
+ return []
956
+ out = x if kind == "amax" else F32
957
+ return [(ROW_REDUCE[kind], (bucket_of("M", rows), softmax_feat_bucket(feat), tag(x), tag(out)))]
958
+
959
+
960
+ def fused_moe_launches(tokens: int, top_k: int, experts: int, hidden: int, inter: int, w: NBXDtype) -> List[Launch]:
961
+ """A fused MoE layer's three grouped GEMMs (`moe_wrappers.invoke_fused_moe`, `triton/moe._fused_moe_pass` and its
962
+ multi-card and expert-store forms): gate and up [hidden -> inter], down [inter -> hidden] with the routing weight
963
+ and no top-k division. Every float operand is in the experts' dtype `w` (the layer casts the hidden states and the
964
+ scores to it), the routing tables int64. The key's length class is the valid (token, expert) pairs' bucket,
965
+ `tokens * top_k` — the same for every launch of the layer, whatever the routing (the padded extent is not keyed) —
966
+ and `experts` the pointer table's size (the layer's experts)."""
967
+ if tokens < 1:
968
+ return []
969
+ nv = bucket_of("M", int(tokens) * int(top_k))
970
+ t, i64 = tag(w), tag(NBXDtype.int64)
971
+ dts = (t, i64, t, t, i64, i64, i64) # a, expert_ptrs, c, topk_weights, sorted ids, expert ids, padded count
972
+ return [(FUSED_MOE, (int(inter), int(hidden), nv, int(experts), False, True) + dts),
973
+ (FUSED_MOE, (int(hidden), int(inter), nv, int(experts), True, False) + dts)]
974
+
975
+
976
+ def moe_align_classes(experts: int, pairs: int) -> Tuple[int, int]:
977
+ """The MoE alignment's padded expert count (a power of two, at least 16) and its key's length class: the layer's
978
+ (token, expert) pairs in the profile's `elements` ladder — the alignment is integer bookkeeping over a few
979
+ thousand ids, launch-dominated as an element-wise launch is (the ladder's own measurement: at or under 65 536
980
+ elements the launch dominates whatever the tile), so its classes are those few, certified at their floor
981
+ (`autotune_bucket.class_floor`); the GEMM's row ladder made ~300 classes of it a memory class."""
982
+ from triton import next_power_of_2
983
+ return max(next_power_of_2(int(experts)), 16), bucket_of("elements", int(pairs))
984
+
985
+
986
+ def moe_align_launches(tokens: int, top_k: int, experts: int, w: NBXDtype) -> List[Launch]:
987
+ """The three alignment stages a fused MoE layer launches (`triton/moe.moe_align_block_size`), the routing ids
988
+ int64: at the FMA kernel's block (`moe_wrappers._MOE_BM`) and, on a matrix unit that takes the experts' dtype,
989
+ at every unit tile's rows (`fused_moe_unit_tiles` — the layer aligns again at the tile its certificate chose,
990
+ one of these)."""
991
+ if tokens < 1:
992
+ return []
993
+ from nbxtensor.ops.moe_wrappers import _MOE_BM
994
+ from nbxtensor.ops._configs import matrix_unit
995
+ be, nb = moe_align_classes(experts, int(tokens) * int(top_k))
996
+ e, i64 = int(experts), tag(NBXDtype.int64)
997
+ blocks = [_MOE_BM]
998
+ if w == F16:
999
+ blocks += sorted({int(r["block_m"]) for r in ((matrix_unit() or {}).get("mm") or [])} - {_MOE_BM})
1000
+ out: List[Launch] = []
1001
+ for bs in blocks:
1002
+ out += [(MOE_ALIGN[0], (bs, be, e, nb, i64, i64, i64, i64)),
1003
+ (MOE_ALIGN[1], (bs, be, e, nb, i64, i64, i64, i64))]
1004
+ return out + [(MOE_ALIGN[2], (e, nb, i64, i64, i64))]
1005
+
1006
+
1007
+ def moe_decode_vec_half_launches(top_k: int, hidden: int, inter: int, w: NBXDtype) -> List[Launch]:
1008
+ """A one-token MoE layer on half-precision experts held on one card (`triton/moe._moe_decode_vec_half_pass`): the
1009
+ gateup with SwiGLU [hidden -> inter], the down projection's router-weighted partials [inter -> hidden], their
1010
+ fixed-order sum. The routed expert ids int64, the tables int64, the partials fp32; the activation and the router
1011
+ weights in the experts' dtype `w`."""
1012
+ if w not in (NBXDtype.float16, NBXDtype.bfloat16):
1013
+ return []
1014
+ t, i64, f32 = tag(w), tag(NBXDtype.int64), tag(F32)
1015
+ bf = w == NBXDtype.bfloat16
1016
+ return [(MOE_GATEUP_HALF, (int(hidden), int(inter), int(top_k), bf, t, i64, i64, i64, f32)),
1017
+ (MOE_DOWN_HALF, (int(inter), int(hidden), int(top_k), bf, f32, i64, t, i64, f32)),
1018
+ (MOE_PART_REDUCE, (int(hidden), int(top_k), f32, f32))]
1019
+
1020
+
1021
+ def decode_reduce_launch(splits: int, Dv: int, out: NBXDtype) -> Launch:
1022
+ """`attention_wrappers.decode_reduce`'s launch, the fixed-order combine after both split decodes: keyed by the
1023
+ splits, one row per program (GROUPS 1) and the value head dim; the partials fp32, the output in `out`."""
1024
+ f32 = tag(F32)
1025
+ return (DECODE_REDUCE, (int(splits), 1, int(Dv), f32, f32, f32, tag(out)))
1026
+
1027
+
1028
+ def decode_vec_launches(H: int, Hk: int, Tk: int, D: int, Dv: int, q: NBXDtype, k: NBXDtype, v: NBXDtype,
1029
+ bias: Optional[NBXDtype], q_round: Optional[NBXDtype] = None) -> List[Launch]:
1030
+ """`attention_wrappers._decode_attn_vec`'s split launch: one query row per program, keyed by the keys' bucket, the
1031
+ head dims, the GQA group and the bias; Q as it arrives (the kernel rounds it to `q_round`, the cache's dtype, on
1032
+ load), the partials fp32; then the shared reduce over its splits (`decode_vec_splits`), written in `q_round`, else
1033
+ in Q's dtype."""
1034
+ from nbxtensor.ops.decode_attn_vec import decode_vec_splits
1035
+ f32 = tag(F32)
1036
+ return [(DECODE_VEC, (bucket_of("N", Tk), int(D), int(Dv), int(H) // max(1, int(Hk)), bias is not None,
1037
+ tag(q), tag(k), tag(v), tag(bias if bias is not None else q), f32, f32, f32)),
1038
+ decode_reduce_launch(decode_vec_splits(Tk), Dv, q_round if q_round is not None else q)]
1039
+
1040
+
1041
+ def paged_decode_launches(H: int, Hk: int, Tk: int, D: int, Dv: int, q: NBXDtype, kv: NBXDtype,
1042
+ page_tokens: int) -> List[Launch]:
1043
+ """`attention_wrappers.paged_decode_attention`'s split launch (a decode step through the paged KV cache, the Triton
1044
+ engine's every cached decode): keyed by the splits the longest sequence makes (`paged_decode_splits`, the replayed
1045
+ decode's bucket too), the page, the head dims and the GQA group;
1046
+ Q as it arrives (rounded to the cache's dtype on load), the pools in the cache's, the tables int32, the partials
1047
+ fp32; then the shared reduce over those splits, written in the cache's dtype (the cache's decode rounds Q to it,
1048
+ `kv_cache.intercept`)."""
1049
+ f32, i32, c = tag(F32), tag(NBXDtype.int32), tag(kv)
1050
+ from nbxtensor.ops.paged_decode_attn import paged_decode_splits
1051
+ return [(PAGED_DECODE, (paged_decode_splits(Tk), int(page_tokens), int(D), int(Dv), int(H) // max(1, int(Hk)),
1052
+ tag(q), c, c, i32, i32, f32, f32, f32)),
1053
+ decode_reduce_launch(paged_decode_splits(Tk), Dv, kv)]
1054
+