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,450 @@
1
+ """The convolution family's float64 reference — the screen's uncovered 11.5%.
2
+
3
+ WHY THIS FAMILY AND NOT ANOTHER
4
+ --------------------------------
5
+ Measured 2026-09-12 against this rack's certified directory: of 7 158 certified
6
+ keys the screen oracle covers 6 336 (88.5%), and the 822 it does not are exactly
7
+ `conv2d_forward_kernel` (770) and `depthwise_conv2d_kernel` (52). Nothing else.
8
+ Full count: `docs/reference/owed-proofs.md` item 3.
9
+
10
+ Without a reference, those keys are decided by a consensus vote, and a vote has
11
+ two failure modes it cannot see — a majority wrong in the same way, and a
12
+ unanimous space that is wrong. Both were measured on another backend: four
13
+ `addmm` shapes where the emitted code declared `alpha`/`beta` as `int`, every
14
+ candidate wrong identically, the vote unanimous, and the bare screen seating a
15
+ wrong configuration every time while the same screen with an oracle refused every
16
+ time.
17
+
18
+ WHAT MAKES A REFERENCE A REFERENCE
19
+ -----------------------------------
20
+ It must not share an implementation with the thing it checks. So: pure numpy in
21
+ float64, no Triton, no torch, and the arithmetic written out rather than
22
+ delegated. It is slow and that is irrelevant — it runs once per shape, inside a
23
+ screen that already refuses to look at anything over the profile's byte budget.
24
+
25
+ The kernels' signatures make this tractable: every dimension, every stride and
26
+ every compile-time parameter is a NAMED argument, so nothing is inferred.
27
+
28
+ conv2d_forward_kernel(input, weight, output, N, Cin, H, W, Cout, Hout, Wout,
29
+ <12 strides>, kernel_h/w, stride_h/w, padding_h/w,
30
+ groups, fp16, dilation_h/w, <3 block sizes>)
31
+ depthwise_conv2d_kernel(x, w, out, N, C, H_in, W_in, H_out, W_out,
32
+ <11 strides>, kh, kw, stride_h/w, pad_h/w, fp16,
33
+ <2 block sizes>)
34
+
35
+ Neither takes a bias, so the reference is the convolution alone.
36
+
37
+ HOW IT REFUSES
38
+ --------------
39
+ Silence, never a guess. An operand that cannot be read here, a declared extent
40
+ that contradicts the array it names, an output extent that does not follow from
41
+ the inputs — each returns None, and the screen then says out loud that this key
42
+ is unscreened. A reference that answers when it should not is worse than none:
43
+ it turns healthy work into a loud stop, and a refusal reads as vigilance.
44
+ """
45
+ from __future__ import annotations
46
+
47
+ from typing import Any, NamedTuple, Optional, Sequence
48
+
49
+ import numpy as np
50
+
51
+
52
+ def _out_extent(size: int, pad: int, dilation: int, kernel: int, stride: int) -> int:
53
+ """The spatial extent a convolution produces, by the standard formula."""
54
+ return (size + 2 * pad - dilation * (kernel - 1) - 1) // stride + 1
55
+
56
+
57
+ def conv2d_reference(x: np.ndarray, w: np.ndarray, *,
58
+ stride: Sequence[int], padding: Sequence[int],
59
+ dilation: Sequence[int], groups: int) -> np.ndarray:
60
+ """`[N, Cin, H, W]` ⊛ `[Cout, Cin//groups, KH, KW]` → `[N, Cout, Ho, Wo]`, fp64.
61
+
62
+ Written as an accumulation over the KH·KW taps rather than an im2col: the
63
+ strided view per tap is exact and allocates nothing, and the loop makes the
64
+ padding and dilation arithmetic visible instead of hidden in a reshape.
65
+ """
66
+ x = np.asarray(x, dtype=np.float64)
67
+ w = np.asarray(w, dtype=np.float64)
68
+ if x.ndim != 4 or w.ndim != 4:
69
+ raise ValueError(f"expected 4-D input and weight, got {x.shape} {w.shape}")
70
+ n, c_in, h, width = x.shape
71
+ c_out, c_in_group, k_h, k_w = w.shape
72
+ if groups < 1 or c_in % groups or c_out % groups:
73
+ raise ValueError(f"{c_in} in / {c_out} out do not divide into {groups} groups")
74
+ if c_in // groups != c_in_group:
75
+ raise ValueError(f"weight declares {c_in_group} input channels per group, "
76
+ f"the input has {c_in // groups}")
77
+ s_h, s_w = int(stride[0]), int(stride[1])
78
+ p_h, p_w = int(padding[0]), int(padding[1])
79
+ d_h, d_w = int(dilation[0]), int(dilation[1])
80
+
81
+ out_h = _out_extent(h, p_h, d_h, k_h, s_h)
82
+ out_w = _out_extent(width, p_w, d_w, k_w, s_w)
83
+ if out_h <= 0 or out_w <= 0:
84
+ raise ValueError(f"the geometry produces a {out_h}x{out_w} output")
85
+
86
+ padded = np.pad(x, ((0, 0), (0, 0), (p_h, p_h), (p_w, p_w)))
87
+ out = np.zeros((n, c_out, out_h, out_w), dtype=np.float64)
88
+ per_in, per_out = c_in // groups, c_out // groups
89
+ for g in range(groups):
90
+ x_g = padded[:, g * per_in:(g + 1) * per_in]
91
+ w_g = w[g * per_out:(g + 1) * per_out]
92
+ acc = out[:, g * per_out:(g + 1) * per_out]
93
+ for i in range(k_h):
94
+ top = i * d_h
95
+ rows = slice(top, top + (out_h - 1) * s_h + 1, s_h)
96
+ for j in range(k_w):
97
+ left = j * d_w
98
+ cols = slice(left, left + (out_w - 1) * s_w + 1, s_w)
99
+ acc += np.einsum("nchw,oc->nohw", x_g[:, :, rows, cols],
100
+ w_g[:, :, i, j])
101
+ return out
102
+
103
+
104
+ def receptive_slab(h: int, wd: int, k_h: int, k_w: int, *, stride, padding, dilation, window):
105
+ """The input slab an output window `(r0, r1, c0, c1)` reads, and the padding it still needs.
106
+
107
+ Returns `((u0, u1, v0, v1), (top, bottom, left, right))`: the UNPADDED input rows `u0:u1`
108
+ and columns `v0:v1` the window's receptive field covers, and the zero padding to put back
109
+ around that slab so the tap loop below sees the same coordinates it would see on the whole
110
+ padded input. One arithmetic for the certifier and the runtime screen — written twice it
111
+ would be two places to be wrong.
112
+ """
113
+ r0, r1, c0, c1 = window
114
+ s_h, s_w = int(stride[0]), int(stride[1])
115
+ p_h, p_w = int(padding[0]), int(padding[1])
116
+ d_h, d_w = int(dilation[0]), int(dilation[1])
117
+ R0, R1 = r0 * s_h, (r1 - 1) * s_h + d_h * (k_h - 1) + 1 # padded coordinates
118
+ C0, C1 = c0 * s_w, (c1 - 1) * s_w + d_w * (k_w - 1) + 1
119
+ u0, u1 = max(0, R0 - p_h), min(h, R1 - p_h)
120
+ v0, v1 = max(0, C0 - p_w), min(wd, C1 - p_w)
121
+ top, bottom = max(0, p_h - R0), max(0, (R1 - p_h) - h)
122
+ left, right = max(0, p_w - C0), max(0, (C1 - p_w) - wd)
123
+ return (u0, u1, v0, v1), (top, bottom, left, right)
124
+
125
+
126
+ def conv2d_reference_window(x, w: np.ndarray, *, stride: Sequence[int], padding: Sequence[int],
127
+ dilation: Sequence[int], groups: int, window=None,
128
+ shape: Optional[Sequence[int]] = None, slab_of=None) -> np.ndarray:
129
+ """`conv2d_reference` on one output block only: `window` = `(n_idx, r0, r1, c0, c1)` selects
130
+ `out[n_idx, :, r0:r1, c0:c1]`, exact on every position of it, reading ONLY its receptive
131
+ field. `window=None` is the whole output.
132
+
133
+ The input arrives either as a host array `x` or — when `slab_of` is given — through a reader
134
+ `slab_of(n0, n1, u0, u1, v0, v1) -> float64 [n1-n0, Cin, u1-u0, v1-v0]` that fetches just the
135
+ slab, with `shape` naming the whole input's `[N, Cin, H, W]`. The reader is what bounds the
136
+ runtime screen: a 128-channel 2048x1024 input is 2.1 GB in float64 whole (the Mac's 27.5 GB
137
+ footprint, 2026-09-25) and a few megabytes as the slab of a few output rows.
138
+
139
+ One BLAS product per tap, the depthwise case as one broadcast product per tap — the
140
+ certifier's arithmetic since 2026-09-07, now the one copy of it.
141
+ """
142
+ w = np.asarray(w, dtype=np.float64)
143
+ if slab_of is None:
144
+ x = np.asarray(x)
145
+ shape = x.shape
146
+ n, c_in, h, wd = (int(v) for v in shape)
147
+ c_out, ci_g, k_h, k_w = w.shape
148
+ if groups < 1 or c_in % groups or c_out % groups or c_in // groups != ci_g:
149
+ raise ValueError(f"{c_in} in / {c_out} out / {ci_g} per group do not divide into {groups} groups")
150
+ s_h, s_w = int(stride[0]), int(stride[1])
151
+ d_h, d_w = int(dilation[0]), int(dilation[1])
152
+ oh = _out_extent(h, int(padding[0]), d_h, k_h, s_h)
153
+ ow = _out_extent(wd, int(padding[1]), d_w, k_w, s_w)
154
+ if oh <= 0 or ow <= 0:
155
+ raise ValueError(f"the geometry produces a {oh}x{ow} output")
156
+ if window is None:
157
+ n0, n1, r0, r1, c0, c1 = 0, n, 0, oh, 0, ow
158
+ else:
159
+ ni, r0, r1, c0, c1 = window
160
+ n0, n1 = int(ni), int(ni) + 1
161
+ (u0, u1, v0, v1), pads = receptive_slab(h, wd, k_h, k_w, stride=stride, padding=padding,
162
+ dilation=dilation, window=(r0, r1, c0, c1))
163
+ if slab_of is None:
164
+ slab = x[n0:n1, :, u0:u1, v0:v1].astype(np.float64)
165
+ else:
166
+ slab = np.asarray(slab_of(n0, n1, u0, u1, v0, v1), dtype=np.float64)
167
+ if slab.shape != (n1 - n0, c_in, u1 - u0, v1 - v0):
168
+ raise ValueError(f"the slab reader returned {slab.shape}, "
169
+ f"the window needs {(n1 - n0, c_in, u1 - u0, v1 - v0)}")
170
+ top, bottom, left, right = pads
171
+ xp = np.pad(slab, ((0, 0), (0, 0), (top, bottom), (left, right)))
172
+ nb, rh, rw = n1 - n0, r1 - r0, c1 - c0
173
+ out = np.zeros((nb, c_out, rh, rw), dtype=np.float64)
174
+ co_g = c_out // groups
175
+ if groups == c_in == c_out and ci_g == 1:
176
+ for i in range(k_h):
177
+ for j in range(k_w):
178
+ patch = xp[:, :, i * d_h:i * d_h + rh * s_h:s_h, j * d_w:j * d_w + rw * s_w:s_w]
179
+ out += patch * w[:, 0, i, j][None, :, None, None]
180
+ return out
181
+ for g in range(groups):
182
+ xg = xp[:, g * ci_g:(g + 1) * ci_g]
183
+ wg = w[g * co_g:(g + 1) * co_g]
184
+ for i in range(k_h):
185
+ for j in range(k_w):
186
+ patch = xg[:, :, i * d_h:i * d_h + rh * s_h:s_h, j * d_w:j * d_w + rw * s_w:s_w]
187
+ prod = patch.transpose(0, 2, 3, 1).reshape(-1, ci_g) @ wg[:, :, i, j].T
188
+ out[:, g * co_g:(g + 1) * co_g] += prod.reshape(nb, rh, rw, co_g).transpose(0, 3, 1, 2)
189
+ return out
190
+
191
+
192
+ def _row_segments(rows, c_out: int, oh: int):
193
+ """Flat output rows `[r0, r1)` of the `[N*Cout*Ho, Wo]` view, cut at every channel boundary:
194
+ yields `(n, c, oh_lo, oh_hi, flat_lo, flat_hi)`, the output rows `oh_lo:oh_hi` of channel `c`
195
+ of element `n`, which are exactly the flat rows `[flat_lo, flat_hi)`.
196
+
197
+ One segment per `(n, c)` run, never a widening: a window that straddles a channel used to
198
+ be widened to every row of the element (`(0, oh)`), whose receptive field is the WHOLE
199
+ input — for a 128 x 2048 x 1024 input the 2.1 GB of float64 this file exists to avoid,
200
+ reachable by window position alone (the guardian, 2026-09-26). The bound must not depend
201
+ on where the windows fall."""
202
+ r0, r1 = int(rows[0]), int(rows[1])
203
+ per_n = c_out * oh
204
+ r = r0
205
+ while r < r1:
206
+ n, rem = divmod(r, per_n)
207
+ c, oh_lo = divmod(rem, oh)
208
+ end = min(r1, r + (oh - oh_lo)) # the last flat row of this channel, or r1
209
+ yield n, c, oh_lo, oh_lo + (end - r), r, end
210
+ r = end
211
+
212
+
213
+ def _conv_geometry(named: dict):
214
+ """The `[N, Cin, H, W]` input, `[Cout, Cin/groups, KH, KW]` weight shape, stride, padding,
215
+ dilation, groups and declared output extents of `conv2d_forward_kernel`'s named arguments —
216
+ refusing, with the reason, a declaration that contradicts the formula."""
217
+ shape = (int(named["batch_dim"]), int(named["in_feat_dim"]),
218
+ int(named["in_height"]), int(named["in_width"]))
219
+ groups = int(named.get("groups", 1))
220
+ k_h, k_w = int(named["kernel_height"]), int(named["kernel_width"])
221
+ w_shape = (int(named["out_feat_dim"]), shape[1] // groups, k_h, k_w)
222
+ stride = (int(named["stride_height"]), int(named["stride_width"]))
223
+ padding = (int(named["padding_height"]), int(named["padding_width"]))
224
+ dilation = (int(named.get("dilation_height", 1)), int(named.get("dilation_width", 1)))
225
+ oh, ow = int(named["out_height"]), int(named["out_width"])
226
+ formula = (_out_extent(shape[2], padding[0], dilation[0], k_h, stride[0]),
227
+ _out_extent(shape[3], padding[1], dilation[1], k_w, stride[1]))
228
+ if (oh, ow) != formula:
229
+ raise ValueError(f"the declared output {oh}x{ow} is not the formula's {formula[0]}x{formula[1]}")
230
+ return shape, w_shape, stride, padding, dilation, groups, oh, ow
231
+
232
+
233
+ def _depthwise_geometry(named: dict):
234
+ c = int(named["C"])
235
+ k_h, k_w = int(named["kh"]), int(named["kw"])
236
+ shape = (int(named["N"]), c, int(named["H_in"]), int(named["W_in"]))
237
+ stride = (int(named["stride_h"]), int(named["stride_w"]))
238
+ padding = (int(named["pad_h"]), int(named["pad_w"]))
239
+ oh, ow = int(named["H_out"]), int(named["W_out"])
240
+ formula = (_out_extent(shape[2], padding[0], 1, k_h, stride[0]),
241
+ _out_extent(shape[3], padding[1], 1, k_w, stride[1]))
242
+ if (oh, ow) != formula:
243
+ raise ValueError(f"the declared output {oh}x{ow} is not the formula's {formula[0]}x{formula[1]}")
244
+ return shape, (c, 1, k_h, k_w), stride, padding, (1, 1), c, oh, ow
245
+
246
+
247
+ def _rows_of(geometry, slab_of, weight_f64, rows) -> np.ndarray:
248
+ shape, w_shape, stride, padding, dilation, groups, oh, ow = geometry
249
+ w = np.asarray(weight_f64, dtype=np.float64)
250
+ if w.size != int(np.prod(w_shape)):
251
+ raise ValueError(f"the weight holds {w.size} elements, the declared {w_shape} needs {int(np.prod(w_shape))}")
252
+ w = w.reshape(w_shape)
253
+ parts = []
254
+ for n, c, oh_lo, oh_hi, lo, hi in _row_segments(rows, w_shape[0], oh):
255
+ block = conv2d_reference_window(None, w, stride=stride, padding=padding, dilation=dilation,
256
+ groups=groups, window=(n, oh_lo, oh_hi, 0, ow),
257
+ shape=shape, slab_of=slab_of)
258
+ parts.append(block[0, c].reshape(hi - lo, ow))
259
+ if not parts:
260
+ raise ValueError(f"the rows {rows} are empty")
261
+ return np.concatenate(parts, axis=0)
262
+
263
+
264
+ def conv2d_rows(named: dict, slab_of, weight_f64, rows) -> np.ndarray:
265
+ """The reference for the flat output rows `rows = (r0, r1)` of `conv2d_forward_kernel`,
266
+ the output read as `[N*Cout*Ho, Wo]` — the form the runtime screen windows every kernel in.
267
+ Reads only the receptive field of those rows through `slab_of`. Raises `ValueError` with
268
+ the reason when it cannot: a declaration that contradicts the arrays it names is a finding
269
+ the screen must say out loud, never a silent consensus."""
270
+ return _rows_of(_conv_geometry(named), slab_of, weight_f64, rows)
271
+
272
+
273
+ def depthwise_rows(named: dict, slab_of, weight_f64, rows) -> np.ndarray:
274
+ """The same for `depthwise_conv2d_kernel` (`groups == C`, weight `[C, KH, KW]`)."""
275
+ return _rows_of(_depthwise_geometry(named), slab_of, weight_f64, rows)
276
+
277
+
278
+ def _row_bytes_of(geometry) -> int:
279
+ """What ONE flat output row costs the reference on the host, from the geometry: the slab of
280
+ input it reads — every input channel, `stride + dilation*(k-1)` input rows (the row and its
281
+ halo), the full input width, 8 bytes an element, counted TWICE because the slab is padded
282
+ into a second array — plus the tap patch and the output row. The screen sizes its windows by
283
+ this, not by the output row's own bytes: a 3-channel output row is 24 KB while its
284
+ 128-channel receptive field is a megabyte, and a window sized to the former reads
285
+ gigabytes."""
286
+ shape, w_shape, stride, _padding, dilation, groups, _oh, ow = geometry
287
+ c_in, w_in = shape[1], shape[3]
288
+ c_out, k_h = w_shape[0], w_shape[2]
289
+ rows_read = max(1, int(stride[0])) + int(dilation[0]) * (k_h - 1)
290
+ return 8 * (2 * c_in * rows_read * w_in + (c_in // groups + c_out) * ow)
291
+
292
+
293
+ class RowOracle(NamedTuple):
294
+ """One kernel's row-windowed reference: the rows function, the names of its INPUT and WEIGHT
295
+ arguments, the `[N, C, H, W]` shape of the input from the named arguments, and what one
296
+ flat output row costs the reference on the host. Everything the screen needs to window the
297
+ kernel is in this row — no branch on the kernel's name lives outside the table."""
298
+ rows: Any
299
+ input_name: str
300
+ weight_name: str
301
+ input_shape: Any
302
+ row_bytes: Any
303
+
304
+
305
+ def oracle_row_bytes(kernel: str, named: dict) -> Optional[int]:
306
+ """What one flat output row costs `kernel`'s reference, or None for a kernel this table does
307
+ not window. A kernel the table DOES window whose cost cannot be formed raises `ValueError`:
308
+ that is a refusal, and a refusal sized to the output row would be the Mac's defect one layer
309
+ down."""
310
+ entry = ROW_ORACLES.get(kernel)
311
+ if entry is None:
312
+ return None
313
+ try:
314
+ return int(entry.row_bytes(named))
315
+ except (KeyError, TypeError, ValueError) as exc:
316
+ raise ValueError(f"{kernel}: the row cost of its reference cannot be formed from the "
317
+ f"named arguments ({type(exc).__name__}: {exc})") from None
318
+
319
+
320
+ def depthwise_reference(x: np.ndarray, w: np.ndarray, *,
321
+ stride: Sequence[int], padding: Sequence[int]) -> np.ndarray:
322
+ """`[N, C, H, W]` ⊛ `[C, KH, KW]` → `[N, C, Ho, Wo]`, fp64.
323
+
324
+ The `groups == C` case, which the engine routes to its own kernel because a
325
+ grouped convolution with one channel per group is a stencil and not a GEMM
326
+ (453x measured on a Sana 4Kpx VAE op). The reference keeps them separate for
327
+ the same reason the kernels are separate: a shared path would let a defect in
328
+ one hide behind the other.
329
+ """
330
+ x = np.asarray(x, dtype=np.float64)
331
+ w = np.asarray(w, dtype=np.float64)
332
+ if x.ndim != 4 or w.ndim != 3:
333
+ raise ValueError(f"expected [N,C,H,W] and [C,KH,KW], got {x.shape} {w.shape}")
334
+ n, c, h, width = x.shape
335
+ c_w, k_h, k_w = w.shape
336
+ if c_w != c:
337
+ raise ValueError(f"weight declares {c_w} channels, the input has {c}")
338
+ s_h, s_w = int(stride[0]), int(stride[1])
339
+ p_h, p_w = int(padding[0]), int(padding[1])
340
+ out_h = _out_extent(h, p_h, 1, k_h, s_h)
341
+ out_w = _out_extent(width, p_w, 1, k_w, s_w)
342
+ if out_h <= 0 or out_w <= 0:
343
+ raise ValueError(f"the geometry produces a {out_h}x{out_w} output")
344
+
345
+ padded = np.pad(x, ((0, 0), (0, 0), (p_h, p_h), (p_w, p_w)))
346
+ out = np.zeros((n, c, out_h, out_w), dtype=np.float64)
347
+ for i in range(k_h):
348
+ rows = slice(i, i + (out_h - 1) * s_h + 1, s_h)
349
+ for j in range(k_w):
350
+ cols = slice(j, j + (out_w - 1) * s_w + 1, s_w)
351
+ out += padded[:, :, rows, cols] * w[None, :, i, j, None, None]
352
+ return out
353
+
354
+
355
+ def _read(named: dict, key: str, to_f64) -> Optional[np.ndarray]:
356
+ tensor = named.get(key)
357
+ if tensor is None:
358
+ return None
359
+ return to_f64(tensor)
360
+
361
+
362
+ def conv2d_from_args(named: dict, to_f64) -> Optional[np.ndarray]:
363
+ """The reference output for `conv2d_forward_kernel`, or None.
364
+
365
+ `to_f64` is the caller's one host-copy path — the provider owns it, because
366
+ reading device memory correctly is a question this module must not answer
367
+ twice (a raw device read was measured returning bytes a kernel had not yet
368
+ landed, and it contradicted every correct candidate as loudly as a wrong
369
+ one).
370
+ """
371
+ try:
372
+ x = _read(named, "input_pointer", to_f64)
373
+ w = _read(named, "weight_pointer", to_f64)
374
+ if x is None or w is None:
375
+ return None
376
+ shape = (int(named["batch_dim"]), int(named["in_feat_dim"]),
377
+ int(named["in_height"]), int(named["in_width"]))
378
+ groups = int(named.get("groups", 1))
379
+ k_h, k_w = int(named["kernel_height"]), int(named["kernel_width"])
380
+ w_shape = (int(named["out_feat_dim"]), shape[1] // groups, k_h, k_w)
381
+ if x.size != int(np.prod(shape)) or w.size != int(np.prod(w_shape)):
382
+ # A declared extent that contradicts the array it names. Refuse:
383
+ # reshaping anyway would produce a confident wrong reference.
384
+ return None
385
+ out = conv2d_reference(
386
+ x.reshape(shape), w.reshape(w_shape),
387
+ stride=(int(named["stride_height"]), int(named["stride_width"])),
388
+ padding=(int(named["padding_height"]), int(named["padding_width"])),
389
+ dilation=(int(named.get("dilation_height", 1)),
390
+ int(named.get("dilation_width", 1))),
391
+ groups=groups)
392
+ declared = (int(named["batch_dim"]), int(named["out_feat_dim"]),
393
+ int(named["out_height"]), int(named["out_width"]))
394
+ if out.shape != declared:
395
+ # The kernel and the formula disagree about the output geometry.
396
+ # That is a finding, not something to paper over with a reshape.
397
+ return None
398
+ return out
399
+ except (KeyError, TypeError, ValueError):
400
+ return None
401
+
402
+
403
+ def depthwise_from_args(named: dict, to_f64) -> Optional[np.ndarray]:
404
+ """The reference output for `depthwise_conv2d_kernel`, or None."""
405
+ try:
406
+ x = _read(named, "x_ptr", to_f64)
407
+ w = _read(named, "w_ptr", to_f64)
408
+ if x is None or w is None:
409
+ return None
410
+ shape = (int(named["N"]), int(named["C"]),
411
+ int(named["H_in"]), int(named["W_in"]))
412
+ w_shape = (int(named["C"]), int(named["kh"]), int(named["kw"]))
413
+ if x.size != int(np.prod(shape)) or w.size != int(np.prod(w_shape)):
414
+ return None
415
+ out = depthwise_reference(
416
+ x.reshape(shape), w.reshape(w_shape),
417
+ stride=(int(named["stride_h"]), int(named["stride_w"])),
418
+ padding=(int(named["pad_h"]), int(named["pad_w"])))
419
+ declared = (int(named["N"]), int(named["C"]),
420
+ int(named["H_out"]), int(named["W_out"]))
421
+ if out.shape != declared:
422
+ return None
423
+ return out
424
+ except (KeyError, TypeError, ValueError):
425
+ return None
426
+
427
+
428
+ #: What a provider's `ORACLES` table absorbs: kernel short name -> (reference
429
+ #: from the live named arguments, the name of its OUTPUT argument).
430
+ #:
431
+ #: The output argument name is not decoration. A provider that matched the
432
+ #: output by byte length once placed the reference on an INPUT of the same size
433
+ #: and refused ten correct candidates of a shape whose certified deviation is
434
+ #: 1.7e-06. It is matched by ADDRESS, and this table is what says which address.
435
+ ORACLES = {
436
+ "conv2d_forward_kernel": (conv2d_from_args, "output_pointer"),
437
+ "depthwise_conv2d_kernel": (depthwise_from_args, "out_ptr"),
438
+ }
439
+
440
+ #: The same kernels on FLAT OUTPUT ROWS, for the runtime screen's windows.
441
+ ROW_ORACLES = {
442
+ "conv2d_forward_kernel": RowOracle(
443
+ conv2d_rows, "input_pointer", "weight_pointer",
444
+ lambda named: _conv_geometry(named)[0],
445
+ lambda named: _row_bytes_of(_conv_geometry(named))),
446
+ "depthwise_conv2d_kernel": RowOracle(
447
+ depthwise_rows, "x_ptr", "w_ptr",
448
+ lambda named: _depthwise_geometry(named)[0],
449
+ lambda named: _row_bytes_of(_depthwise_geometry(named))),
450
+ }
@@ -0,0 +1,159 @@
1
+ """Constant padding — pure @triton.jit kernel.
2
+
3
+ Handles constant_pad_nd for the common 4D case (N,C,H,W) and generic N-D
4
+ via a flat-index approach. For each output element, compute the corresponding
5
+ input coordinate. If in bounds, load from input; otherwise, store pad_value.
6
+
7
+ Logic derived from FlagGems pad.py codegen approach.
8
+ """
9
+
10
+ import triton
11
+ import triton.language as tl
12
+
13
+ @triton.jit
14
+ def constant_pad_2d_kernel(
15
+ x_ptr, output_ptr,
16
+ total,
17
+ in_h, in_w, out_h, out_w,
18
+ channels_times_batch,
19
+ x_stride_n, x_stride_c, x_stride_h, x_stride_w,
20
+ out_stride_n, out_stride_c, out_stride_h, out_stride_w,
21
+ pad_left, pad_top,
22
+ pad_value,
23
+ BLOCK_SIZE: tl.constexpr,
24
+ WIDE: tl.constexpr = True,
25
+ ):
26
+ """Constant pad for 4D tensors (N,C,H,W). Most common case."""
27
+ if WIDE:
28
+ offsets = tl.program_id(0).to(tl.int64) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE) # 64-bit from the program id: the product itself wraps past 2^31 elements (register 58)
29
+ else:
30
+ offsets = tl.program_id(0) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE) # 32-bit below 2^30 (`_index_wide`): Apple emulates 64-bit % and //
31
+ mask = offsets < total
32
+
33
+ # Decompose flat index into (n*c, h, w)
34
+ ow = offsets % out_w
35
+ temp = offsets // out_w
36
+ oh = temp % out_h
37
+ nc = temp // out_h
38
+
39
+ # Map output coords to input coords
40
+ iw = ow - pad_left
41
+ ih = oh - pad_top
42
+
43
+ # Check if within input bounds
44
+ in_bounds = (ih >= 0) & (ih < in_h) & (iw >= 0) & (iw < in_w) & (nc < channels_times_batch)
45
+
46
+ # Flat stride approach: assumes contiguous input (wrapper ensures contiguous)
47
+ inp_offset = nc * in_h * in_w + ih * in_w + iw
48
+
49
+ val = tl.load(x_ptr + inp_offset, mask=mask & in_bounds, other=pad_value)
50
+ out_offset = nc * out_h * out_w + oh * out_w + ow
51
+ tl.store(output_ptr + out_offset, val, mask=mask)
52
+
53
+ @triton.jit
54
+ def constant_pad_1d_kernel(
55
+ x_ptr, output_ptr,
56
+ total,
57
+ in_size, out_size,
58
+ batch_size,
59
+ pad_left,
60
+ pad_value,
61
+ BLOCK_SIZE: tl.constexpr,
62
+ WIDE: tl.constexpr = True,
63
+ ):
64
+ """Constant pad for 2D/3D tensors along last dim."""
65
+ if WIDE:
66
+ offsets = tl.program_id(0).to(tl.int64) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE) # 64-bit from the program id: the product itself wraps past 2^31 elements (register 58)
67
+ else:
68
+ offsets = tl.program_id(0) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE) # 32-bit below 2^30 (`_index_wide`): Apple emulates 64-bit % and //
69
+ mask = offsets < total
70
+
71
+ out_idx = offsets % out_size
72
+ batch_idx = offsets // out_size
73
+
74
+ in_idx = out_idx - pad_left
75
+ in_bounds = (in_idx >= 0) & (in_idx < in_size) & (batch_idx < batch_size)
76
+
77
+ inp_offset = batch_idx * in_size + in_idx
78
+ val = tl.load(x_ptr + inp_offset, mask=mask & in_bounds, other=pad_value)
79
+
80
+ out_offset = batch_idx * out_size + out_idx
81
+ tl.store(output_ptr + out_offset, val, mask=mask)
82
+
83
+
84
+ @triton.jit
85
+ def constant_pad_nd_kernel(
86
+ x_ptr, output_ptr,
87
+ total,
88
+ in0, in1, in2, in3, in4,
89
+ out0, out1, out2, out3, out4,
90
+ xs0, xs1, xs2, xs3, xs4,
91
+ pb0, pb1, pb2, pb3, pb4,
92
+ pad_value,
93
+ BLOCK_SIZE: tl.constexpr,
94
+ WIDE: tl.constexpr = True,
95
+ ):
96
+ """Constant pad of up to 5 dims in ONE pass: each output element maps to its input element (any dim padded,
97
+ a middle one included) or to `pad_value`. Dims a tensor lacks are given extent 1 and pad 0 by the wrapper, so one
98
+ kernel serves 1-D to 5-D. The input is read through its strides (xs*); the output is written contiguous."""
99
+ if WIDE:
100
+ offsets = tl.program_id(0).to(tl.int64) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
101
+ else:
102
+ offsets = tl.program_id(0) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE) # 32-bit below 2^30 (`_index_wide`): Apple emulates 64-bit % and //
103
+ mask = offsets < total
104
+ o4 = offsets % out4
105
+ t = offsets // out4
106
+ o3 = t % out3
107
+ t = t // out3
108
+ o2 = t % out2
109
+ t = t // out2
110
+ o1 = t % out1
111
+ o0 = t // out1
112
+ i0 = o0 - pb0
113
+ i1 = o1 - pb1
114
+ i2 = o2 - pb2
115
+ i3 = o3 - pb3
116
+ i4 = o4 - pb4
117
+ inside = ((i0 >= 0) & (i0 < in0) & (i1 >= 0) & (i1 < in1) & (i2 >= 0) & (i2 < in2)
118
+ & (i3 >= 0) & (i3 < in3) & (i4 >= 0) & (i4 < in4))
119
+ src = i0 * xs0 + i1 * xs1 + i2 * xs2 + i3 * xs3 + i4 * xs4
120
+ val = tl.load(x_ptr + src, mask=mask & inside, other=pad_value)
121
+ tl.store(output_ptr + offsets, val, mask=mask)
122
+
123
+
124
+ @triton.jit
125
+ def replication_pad_nd_kernel(
126
+ x_ptr, output_ptr,
127
+ total,
128
+ in0, in1, in2, in3, in4,
129
+ out0, out1, out2, out3, out4,
130
+ xs0, xs1, xs2, xs3, xs4,
131
+ pb0, pb1, pb2, pb3, pb4,
132
+ BLOCK_SIZE: tl.constexpr,
133
+ WIDE: tl.constexpr = True,
134
+ ):
135
+ """Replication pad of up to 5 dims in ONE pass (PyTorch `replicate`): each output element reads the input element
136
+ at its position clamped into the input, so a padded border repeats the edge. The twin of `constant_pad_nd_kernel`,
137
+ the same index map with a clamp where that one masks; the input is read through its strides, the output written
138
+ contiguous."""
139
+ if WIDE:
140
+ offsets = tl.program_id(0).to(tl.int64) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
141
+ else:
142
+ offsets = tl.program_id(0) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE) # 32-bit below 2^30 (`_index_wide`)
143
+ mask = offsets < total
144
+ o4 = offsets % out4
145
+ t = offsets // out4
146
+ o3 = t % out3
147
+ t = t // out3
148
+ o2 = t % out2
149
+ t = t // out2
150
+ o1 = t % out1
151
+ o0 = t // out1
152
+ i0 = tl.minimum(tl.maximum(o0 - pb0, 0), in0 - 1)
153
+ i1 = tl.minimum(tl.maximum(o1 - pb1, 0), in1 - 1)
154
+ i2 = tl.minimum(tl.maximum(o2 - pb2, 0), in2 - 1)
155
+ i3 = tl.minimum(tl.maximum(o3 - pb3, 0), in3 - 1)
156
+ i4 = tl.minimum(tl.maximum(o4 - pb4, 0), in4 - 1)
157
+ src = i0 * xs0 + i1 * xs1 + i2 * xs2 + i3 * xs3 + i4 * xs4
158
+ val = tl.load(x_ptr + src, mask=mask)
159
+ tl.store(output_ptr + offsets, val, mask=mask)