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,223 @@
1
+ """Shared seeded CPU fp64 draw frontier (R30).
2
+
3
+ ONE code path draws sampled tokens for BOTH engines: logits cross the
4
+ boundary as fp64 numpy arrays (D2H at the caller), the vendor-faithful
5
+ filter chain (repetition penalty -> temperature -> top-k -> top-p) and
6
+ the draw run in CPU fp64, and the uniform stream comes from one seeded
7
+ generator. Compiled and triton therefore produce bit-identical draws
8
+ whenever the incoming logits agree; near-ties remain the only residual
9
+ class, adjudicated by margins (NBX_DECODE_TOPK doctrine).
10
+
11
+ Torch-free by construction: numpy is CPU glue, legal in both modes
12
+ (R33/R34), so this module is importable from core/ AND triton/ without
13
+ duplication. Precedent: the dual_ar flow's byte-identical duplicated
14
+ `_sample_token_np` pair — this module is that prototype promoted to a
15
+ single shared frontier. Scope: activated by a registry-declared speech
16
+ sampling contract; existing zoo samplers are untouched (their byte
17
+ gates hold by construction).
18
+
19
+ Filter semantics mirror the transformers LogitsProcessor chain:
20
+ - repetition penalty: seen ids with logit > 0 divided by the penalty,
21
+ logit <= 0 multiplied by it (RepetitionPenaltyLogitsProcessor).
22
+ - top-k: THRESHOLD keep — every logit >= the k-th highest survives
23
+ (ties at the threshold may keep more than k, exactly like
24
+ TopKLogitsWarper's `< topk(...)[-1]` mask).
25
+ - top-p: smallest set of highest-probability tokens whose cumulative
26
+ probability reaches top_p, at least one token kept
27
+ (TopPLogitsWarper); ties broken by ascending vocab index for
28
+ run-to-run determinism.
29
+ - draw: inverse-CDF walk over the filtered, renormalized fp64 probs in
30
+ vocab-index order against one uniform from the stream. The draw
31
+ count per step is the cross-engine coupling contract: both engines
32
+ MUST consume draws in the same order.
33
+ """
34
+
35
+ import json
36
+ import os
37
+
38
+ import numpy as np
39
+
40
+ __all__ = ["SeededDrawStream", "apply_repetition_penalty",
41
+ "seeded_gaussian"]
42
+
43
+ # NBX_DRAW_DIAG=<jsonl path>: per-draw top-4 candidate ids/logits + the
44
+ # top-2 margin + the chosen id, appended as one JSON line. The speech
45
+ # twin of NBX_DECODE_TOPK — at any cross-engine code divergence the
46
+ # FIRST differing line localizes the flip and its margin adjudicates
47
+ # near-tie vs large-margin (both engines instrumented by construction:
48
+ # this module IS the shared frontier). Default off, zero cost off.
49
+ _DIAG_PATH = os.environ.get("NBX_DRAW_DIAG")
50
+
51
+
52
+ def apply_repetition_penalty(logits: np.ndarray, seen_ids, penalty: float) -> np.ndarray:
53
+ """RepetitionPenaltyLogitsProcessor semantics on fp64 logits (in place)."""
54
+ if not penalty or penalty == 1.0 or seen_ids is None:
55
+ return logits
56
+ ids = np.unique(np.asarray(list(seen_ids), dtype=np.int64))
57
+ if ids.size == 0:
58
+ return logits
59
+ ids = ids[(ids >= 0) & (ids < logits.shape[0])]
60
+ vals = logits[ids]
61
+ logits[ids] = np.where(vals > 0, vals / penalty, vals * penalty)
62
+ return logits
63
+
64
+
65
+ class SeededDrawStream:
66
+ """One seeded uniform stream; the draw ORDER is the R30 contract."""
67
+
68
+ def __init__(self, seed: int):
69
+ self._rng = np.random.default_rng(int(seed) & 0xFFFFFFFFFFFFFFFF)
70
+ self.draws = 0
71
+
72
+ def draw(self, logits_fp64, temperature: float = 1.0, top_k: int = 0,
73
+ top_p: float = 1.0, seen_ids=None,
74
+ repetition_penalty: float = 1.0) -> int:
75
+ """Sample one token id from a single 1-D fp64 logits vector."""
76
+ z = np.array(logits_fp64, dtype=np.float64).reshape(-1)
77
+ apply_repetition_penalty(z, seen_ids, repetition_penalty)
78
+ _diag_rec = None
79
+ if _DIAG_PATH:
80
+ _t4 = np.argsort(z)[::-1][:4]
81
+ _diag_rec = {
82
+ "n": self.draws,
83
+ "top4": [[int(i), round(float(z[i]), 6)] for i in _t4],
84
+ "margin": round(float(z[_t4[0]] - z[_t4[1]]), 6)
85
+ if _t4.size > 1 else None,
86
+ }
87
+ # temp <= 0 is the GREEDY contract (argmax), never a silent
88
+ # unscaled multinomial — the Ming sampling-class trap (2026-07-27).
89
+ if temperature is not None and temperature <= 0:
90
+ _g = int(np.argmax(z))
91
+ if _diag_rec is not None:
92
+ _diag_rec["chosen"] = _g
93
+ with open(_DIAG_PATH, "a") as _f:
94
+ _f.write(json.dumps(_diag_rec) + "\n")
95
+ return _g
96
+ if temperature and temperature != 1.0:
97
+ z = z / float(temperature)
98
+
99
+ keep = np.ones(z.shape[0], dtype=bool)
100
+ if top_k and 0 < top_k < z.shape[0]:
101
+ kth = np.partition(z, -top_k)[-top_k]
102
+ keep &= z >= kth # threshold keep — ties survive (HF semantics)
103
+
104
+ # softmax over the surviving set only, fp64-stable
105
+ zk = np.where(keep, z, -np.inf)
106
+ zk = zk - zk.max()
107
+ p = np.exp(zk)
108
+ p /= p.sum()
109
+
110
+ if top_p and 0.0 < top_p < 1.0:
111
+ # descending prob, ties by ascending vocab index (lexsort keys
112
+ # are last-key-major): smallest high-prob set reaching top_p.
113
+ order = np.lexsort((np.arange(p.shape[0]), -p))
114
+ csum = np.cumsum(p[order])
115
+ cut = int(np.searchsorted(csum, top_p, side="left")) + 1
116
+ nucleus = order[:cut]
117
+ mask = np.zeros(p.shape[0], dtype=bool)
118
+ mask[nucleus] = True
119
+ p = np.where(mask, p, 0.0)
120
+ p /= p.sum()
121
+
122
+ u = self._rng.random()
123
+ self.draws += 1
124
+ chosen = int(np.searchsorted(np.cumsum(p), u,
125
+ side="right").clip(0, p.shape[0] - 1))
126
+ if _diag_rec is not None:
127
+ _diag_rec["chosen"] = chosen
128
+ with open(_DIAG_PATH, "a") as _f:
129
+ _f.write(json.dumps(_diag_rec) + "\n")
130
+ return chosen
131
+
132
+ def draw_chattts(self, logits_fp64, temperature: float, top_p: float,
133
+ top_k: int, min_tokens_to_keep: int = 3,
134
+ seen_ids=None, repetition_penalty: float = 1.0,
135
+ penalty_window: int = 16,
136
+ eos_masked: bool = False, eos_id: int = -1) -> int:
137
+ """Vendor-exact ChatTTS-class chain (MiniCPM-o tts contract,
138
+ modeling generate :4425-4462 + gen_logits :4994-5008):
139
+ temperature -> window-frequency penalty -> TopP (min_keep) ->
140
+ TopK (min_keep) -> optional eos -inf mask (min_new_token) ->
141
+ softmax -> ONE multinomial from the stream. Same seeded stream,
142
+ same draw-order contract as draw() (R30 coupling)."""
143
+ z = np.array(logits_fp64, dtype=np.float64).reshape(-1)
144
+ if temperature is not None and temperature <= 0:
145
+ return int(np.argmax(z)) # greedy contract
146
+ if temperature and temperature != 1.0:
147
+ z = z / float(temperature)
148
+ z = _chattts_window_penalty(z, seen_ids, repetition_penalty,
149
+ penalty_window)
150
+ _mk = max(1, int(min_tokens_to_keep))
151
+ # TopP FIRST (the vendor warper order), HF keep-set semantics +
152
+ # min_tokens_to_keep floor; ties by ascending vocab index.
153
+ if top_p and 0.0 < top_p < 1.0:
154
+ zs = z - z.max()
155
+ pf = np.exp(zs)
156
+ pf /= pf.sum()
157
+ order = np.lexsort((np.arange(pf.shape[0]), -pf))
158
+ csum = np.cumsum(pf[order])
159
+ cut = max(int(np.searchsorted(csum, top_p, side="left")) + 1,
160
+ _mk)
161
+ mask = np.zeros(pf.shape[0], dtype=bool)
162
+ mask[order[:cut]] = True
163
+ z = np.where(mask, z, -np.inf)
164
+ # TopK with the min_tokens_to_keep floor (HF: k = max(k, mk)).
165
+ if top_k and top_k > 0:
166
+ _k = min(max(int(top_k), _mk), z.shape[0])
167
+ kth = np.partition(z, -_k)[-_k]
168
+ z = np.where(z >= kth, z, -np.inf)
169
+ if eos_masked and 0 <= eos_id < z.shape[0]:
170
+ z[eos_id] = -np.inf # min_new_token contract
171
+ _diag_rec = None
172
+ if _DIAG_PATH:
173
+ _t4 = np.argsort(z)[::-1][:4]
174
+ _diag_rec = {
175
+ "n": self.draws, "class": "chattts",
176
+ "top4": [[int(i), round(float(z[i]), 6)] for i in _t4],
177
+ "margin": round(float(z[_t4[0]] - z[_t4[1]]), 6)
178
+ if _t4.size > 1 else None,
179
+ }
180
+ zk = z - z[np.isfinite(z)].max()
181
+ p = np.exp(zk)
182
+ p[~np.isfinite(zk)] = 0.0
183
+ p /= p.sum()
184
+ u = self._rng.random()
185
+ self.draws += 1
186
+ chosen = int(np.searchsorted(np.cumsum(p), u,
187
+ side="right").clip(0, p.shape[0] - 1))
188
+ if _diag_rec is not None:
189
+ _diag_rec["chosen"] = chosen
190
+ with open(_DIAG_PATH, "a") as _f:
191
+ _f.write(json.dumps(_diag_rec) + "\n")
192
+ return chosen
193
+
194
+
195
+ def seeded_gaussian(seed: int, shape) -> np.ndarray:
196
+ """Seeded fp32 standard-normal draw — the latent-init twin of
197
+ SeededDrawStream. ONE stream (PCG64(seed), native-fp32 ziggurat) on
198
+ the CPU; both engines consume the SAME array, so generative
199
+ diffusion legs start from bit-identical noise whenever seed and
200
+ shape agree. This is the cross-engine coupling contract for
201
+ image/video latent init, exactly as the draw stream is for sampled
202
+ tokens: the engines may only diverge through compute numerics,
203
+ never through RNG provenance."""
204
+ return np.random.default_rng(int(seed)).standard_normal(
205
+ size=tuple(int(d) for d in shape), dtype=np.float32)
206
+
207
+
208
+ def _chattts_window_penalty(z: np.ndarray, seen_ids, penalty: float,
209
+ window: int) -> np.ndarray:
210
+ """ChatTTS-class repetition penalty (vendor
211
+ CustomRepetitionPenaltyLogitsProcessorRepeat): alpha = penalty^freq
212
+ over the last `window` draws; negative logits multiply by alpha,
213
+ non-negative divide. Distinct from the HF processor (seen-set,
214
+ freq-blind) — declared per contract as repetition_penalty_class."""
215
+ if not penalty or penalty == 1.0 or not seen_ids:
216
+ return z
217
+ ids = np.asarray(list(seen_ids)[-int(window):], dtype=np.int64)
218
+ ids = ids[(ids >= 0) & (ids < z.shape[0])]
219
+ if ids.size == 0:
220
+ return z
221
+ freq = np.bincount(ids, minlength=z.shape[0]).astype(np.float64)
222
+ alpha = np.power(float(penalty), freq)
223
+ return np.where(z < 0, z * alpha, z / alpha)
@@ -0,0 +1,157 @@
1
+ """Shapes, strides and views as pure functions on integers.
2
+
3
+ Every rule a tensor's layout follows lives here once, and `Tensor` calls it: how many elements a shape holds,
4
+ the row-major strides of a shape, whether a layout is contiguous, the strides of a view (ATen's `computeStride`),
5
+ broadcasting, slice bounds, and the largest offset a strided layout reaches. Integers in, integers out: the
6
+ functions read no device, no dtype and no global state (R-NBXT 11), so a Rust core can take them over unchanged.
7
+
8
+ Strides are in ELEMENTS, never bytes.
9
+ """
10
+ from __future__ import annotations
11
+
12
+ from typing import Optional, Sequence, Tuple
13
+
14
+ __all__ = ["numel", "contiguous_strides", "is_contiguous", "view_strides", "broadcast_shapes",
15
+ "broadcast_strides", "slice_bounds", "max_linear_offset", "MAX_NDIM"]
16
+
17
+ # PyTorch's bound on the rank an op iterates (aten/src/ATen/TensorIterator.h, `MAX_DIMS == 25`); a kernel launch
18
+ # beyond it is refused, never truncated.
19
+ MAX_NDIM = 25
20
+
21
+
22
+ def numel(shape: Sequence[int]) -> int:
23
+ """The number of elements of `shape`: the product of its extents, 1 for the empty shape (a scalar)."""
24
+ n = 1
25
+ for d in shape:
26
+ n *= int(d)
27
+ return n
28
+
29
+
30
+ def contiguous_strides(shape: Sequence[int]) -> Tuple[int, ...]:
31
+ """The row-major strides of `shape`, last dim fastest."""
32
+ if len(shape) == 0:
33
+ return ()
34
+ strides = [1] * len(shape)
35
+ for i in range(len(shape) - 2, -1, -1):
36
+ strides[i] = strides[i + 1] * shape[i + 1]
37
+ return tuple(strides)
38
+
39
+
40
+ def is_contiguous(shape: Sequence[int], strides: Sequence[int]) -> bool:
41
+ """PyTorch's contiguity: the elements lie row-major without gaps; a dim of extent 1 may carry any stride (it is
42
+ never walked) and an empty tensor is contiguous. Comparing the strides to the canonical ones instead called a
43
+ decode-step view such as (1, 32, 64, 1) with strides (2048, 64, 1, 64) — a transposed single-token head block —
44
+ non-contiguous and copied it before every element-wise kernel (NeuroBrix's copy census of 2026-09-07)."""
45
+ expected = 1
46
+ for extent, stride in zip(reversed(shape), reversed(strides)):
47
+ if extent == 0:
48
+ return True
49
+ if extent == 1:
50
+ continue
51
+ if stride != expected:
52
+ return False
53
+ expected *= extent
54
+ return True
55
+
56
+
57
+ def view_strides(old_shape: Sequence[int], old_strides: Sequence[int],
58
+ new_shape: Sequence[int]) -> Optional[list]:
59
+ """The strides `new_shape` takes as a VIEW of a tensor laid out as (`old_shape`, `old_strides`), or None when no
60
+ view exists — ATen's own rule (aten/src/ATen/TensorUtils.cpp `computeStride`): the old dims are walked in chunks
61
+ of contiguous runs, and a new dim must fall inside one chunk."""
62
+ total = numel(old_shape)
63
+ if total == 0 or not old_shape:
64
+ return None
65
+ new_strides = [0] * len(new_shape)
66
+ view_d = len(new_shape) - 1
67
+ chunk_base = old_strides[-1]
68
+ tensor_numel = view_numel = 1
69
+ for tensor_d in range(len(old_shape) - 1, -1, -1):
70
+ tensor_numel *= old_shape[tensor_d]
71
+ if tensor_d == 0 or (old_shape[tensor_d - 1] != 1
72
+ and old_strides[tensor_d - 1] != tensor_numel * chunk_base):
73
+ while view_d >= 0 and (view_numel < tensor_numel or new_shape[view_d] == 1):
74
+ new_strides[view_d] = view_numel * chunk_base
75
+ view_numel *= new_shape[view_d]
76
+ view_d -= 1
77
+ if view_numel != tensor_numel:
78
+ return None
79
+ if tensor_d > 0:
80
+ chunk_base = old_strides[tensor_d - 1]
81
+ tensor_numel = view_numel = 1
82
+ return new_strides if view_d == -1 else None
83
+
84
+
85
+ def broadcast_shapes(*shapes: Sequence[int]) -> Tuple[int, ...]:
86
+ """The shape two or more shapes broadcast to (numpy's rule: right-aligned, an extent of 1 stretches); shapes
87
+ that do not broadcast are refused by name."""
88
+ if len(shapes) == 1:
89
+ return tuple(shapes[0])
90
+ result = tuple(shapes[0])
91
+ for s in shapes[1:]:
92
+ s = tuple(s)
93
+ ndim = max(len(result), len(s))
94
+ a = (1,) * (ndim - len(result)) + result
95
+ b = (1,) * (ndim - len(s)) + s
96
+ new = []
97
+ for sa, sb in zip(a, b):
98
+ if sa == sb:
99
+ new.append(sa)
100
+ elif sa == 1:
101
+ new.append(sb)
102
+ elif sb == 1:
103
+ new.append(sa)
104
+ else:
105
+ raise ValueError(f"Cannot broadcast {result} and {s}")
106
+ result = tuple(new)
107
+ return result
108
+
109
+
110
+ def broadcast_strides(shape: Sequence[int], strides: Sequence[int],
111
+ target: Sequence[int]) -> Tuple[Tuple[int, ...], Tuple[int, ...]]:
112
+ """(shape, strides) of the layout (`shape`, `strides`) EXPANDED to `target` without a copy: leading dims are
113
+ prepended with extent 1, a dim of extent 1 stretches with stride 0, an entry of -1 keeps the dim as it is
114
+ (ATen `expand`)."""
115
+ pad = len(target) - len(shape)
116
+ old_s = (1,) * pad + tuple(shape)
117
+ old_st = (0,) * pad + tuple(strides)
118
+ new_s, new_st = [], []
119
+ for i, s in enumerate(target):
120
+ if s == -1:
121
+ new_s.append(old_s[i])
122
+ new_st.append(old_st[i])
123
+ elif old_s[i] == 1:
124
+ new_s.append(s)
125
+ new_st.append(0)
126
+ else:
127
+ new_s.append(s)
128
+ new_st.append(old_st[i])
129
+ return tuple(new_s), tuple(new_st)
130
+
131
+
132
+ def slice_bounds(start: Optional[int], stop: Optional[int], size: int, step: Optional[int] = None) -> Tuple[int, int]:
133
+ """(start, stop) of a slice over an axis of `size`, as torch and numpy read it: negative bounds count from the
134
+ end, and both bounds are CLAMPED to [0, size] — [50:80] over 60 rows is rows 50..59. Unclamped, a stop past the
135
+ extent read past the tensor's storage (CogVideoX's last VAE tiles in NeuroBrix, 2026-10-17). A step other than 1
136
+ is refused by name."""
137
+ if step not in (None, 1):
138
+ raise RuntimeError(f"ZERO FALLBACK: slicing with step {step} is not supported (narrow only)")
139
+ start = 0 if start is None else int(start)
140
+ stop = size if stop is None else int(stop)
141
+ if start < 0:
142
+ start += size
143
+ if stop < 0:
144
+ stop += size
145
+ start = min(max(start, 0), size)
146
+ stop = min(max(stop, start), size)
147
+ return start, stop
148
+
149
+
150
+ def max_linear_offset(shape: Sequence[int], strides: Sequence[int]) -> int:
151
+ """The largest element offset a strided layout reaches — what a kernel's index arithmetic must be wide enough
152
+ for."""
153
+ total = 0
154
+ for extent, stride in zip(shape, strides):
155
+ if extent > 0:
156
+ total += (int(extent) - 1) * abs(int(stride))
157
+ return total