flashrt-structures 0.2.0__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 (122) hide show
  1. flashrt_structures/__init__.py +174 -0
  2. flashrt_structures/adapters/__init__.py +55 -0
  3. flashrt_structures/adapters/diffusers_attention.py +237 -0
  4. flashrt_structures/adapters/diffusers_rotary_attention.py +239 -0
  5. flashrt_structures/adapters/factored_qk_norm_rope.py +252 -0
  6. flashrt_structures/adapters/factored_two_way_attention.py +99 -0
  7. flashrt_structures/adapters/gemma_attention.py +226 -0
  8. flashrt_structures/adapters/packed_qkv_rope.py +342 -0
  9. flashrt_structures/adapters/packed_stream_qk_norm_rope.py +376 -0
  10. flashrt_structures/adapters/qwen_per_head_qk_norm_rope.py +231 -0
  11. flashrt_structures/adapters/sglang_engine.py +207 -0
  12. flashrt_structures/adapters/transformers_attention_interface.py +73 -0
  13. flashrt_structures/adapters/transformers_gated_delta.py +152 -0
  14. flashrt_structures/adapters/transformers_gated_delta_fused.py +96 -0
  15. flashrt_structures/adapters/vllm_engine.py +424 -0
  16. flashrt_structures/adjudicate.py +85 -0
  17. flashrt_structures/aot.py +191 -0
  18. flashrt_structures/autobuild.py +2052 -0
  19. flashrt_structures/beta/__init__.py +43 -0
  20. flashrt_structures/beta/conform.py +94 -0
  21. flashrt_structures/beta/joins.py +113 -0
  22. flashrt_structures/beta/negotiate.py +84 -0
  23. flashrt_structures/beta/ports.py +140 -0
  24. flashrt_structures/decisions.py +80 -0
  25. flashrt_structures/discover.py +623 -0
  26. flashrt_structures/explain.py +70 -0
  27. flashrt_structures/frontdoor.py +572 -0
  28. flashrt_structures/gates.py +465 -0
  29. flashrt_structures/guard.py +421 -0
  30. flashrt_structures/handle.py +189 -0
  31. flashrt_structures/impls/__init__.py +219 -0
  32. flashrt_structures/impls/adaln_producer/__init__.py +8 -0
  33. flashrt_structures/impls/adaln_producer/broker.py +116 -0
  34. flashrt_structures/impls/adaln_producer/fused.py +388 -0
  35. flashrt_structures/impls/adarms_stack/__init__.py +8 -0
  36. flashrt_structures/impls/adarms_stack/fp8_chain.py +832 -0
  37. flashrt_structures/impls/adarms_stack/region.py +102 -0
  38. flashrt_structures/impls/attention_core/__init__.py +132 -0
  39. flashrt_structures/impls/attention_core/fa2_seqused.py +458 -0
  40. flashrt_structures/impls/attention_core/fa4_cute.py +154 -0
  41. flashrt_structures/impls/attention_core/fa4_fp8.py +178 -0
  42. flashrt_structures/impls/attention_core/masked_mha.py +158 -0
  43. flashrt_structures/impls/attention_core/two_way_fa2.py +220 -0
  44. flashrt_structures/impls/cadence_static/__init__.py +18 -0
  45. flashrt_structures/impls/cadence_static/buffers.py +122 -0
  46. flashrt_structures/impls/cadence_static/cross_attention.py +187 -0
  47. flashrt_structures/impls/chain_elements.py +89 -0
  48. flashrt_structures/impls/decode_loop/__init__.py +0 -0
  49. flashrt_structures/impls/decode_loop/fp8_kv.py +206 -0
  50. flashrt_structures/impls/decode_loop/mtp_speculative.py +245 -0
  51. flashrt_structures/impls/decode_loop/whole_step.py +852 -0
  52. flashrt_structures/impls/decoder_block/__init__.py +6 -0
  53. flashrt_structures/impls/decoder_block/attn_sublayer.py +110 -0
  54. flashrt_structures/impls/decoder_block/fused.py +167 -0
  55. flashrt_structures/impls/decoder_ffn/__init__.py +0 -0
  56. flashrt_structures/impls/decoder_ffn/fp8_static.py +310 -0
  57. flashrt_structures/impls/decoder_ffn/fp8_static.yaml +22 -0
  58. flashrt_structures/impls/decoder_ffn/w4a16_static.py +221 -0
  59. flashrt_structures/impls/decoder_ffn/w8a16_static.py +183 -0
  60. flashrt_structures/impls/dit_stack/__init__.py +11 -0
  61. flashrt_structures/impls/dit_stack/fp4_chain.py +417 -0
  62. flashrt_structures/impls/dit_stack/region.py +86 -0
  63. flashrt_structures/impls/fixed_iter/__init__.py +29 -0
  64. flashrt_structures/impls/fixed_iter/openpi.py +264 -0
  65. flashrt_structures/impls/fixed_iter/protocol.py +94 -0
  66. flashrt_structures/impls/gated_delta_core/__init__.py +3 -0
  67. flashrt_structures/impls/gated_delta_core/fused_layer.py +545 -0
  68. flashrt_structures/impls/gated_delta_core/hub_v3.py +152 -0
  69. flashrt_structures/impls/graph_lowering/__init__.py +27 -0
  70. flashrt_structures/impls/graph_lowering/pi052_denoise.py +179 -0
  71. flashrt_structures/impls/graph_lowering/protocol.py +76 -0
  72. flashrt_structures/impls/graph_lowering/qwen3_vl.py +364 -0
  73. flashrt_structures/impls/linear_proj/__init__.py +0 -0
  74. flashrt_structures/impls/linear_proj/fp8_static.py +270 -0
  75. flashrt_structures/impls/linear_proj/nvfp4_balance.py +131 -0
  76. flashrt_structures/impls/linear_proj/nvfp4_dynamic.py +182 -0
  77. flashrt_structures/impls/linear_proj/w8a16_static.py +230 -0
  78. flashrt_structures/impls/modnorm_qkv_chain/__init__.py +0 -0
  79. flashrt_structures/impls/modnorm_qkv_chain/fp8_ptok_table.py +291 -0
  80. flashrt_structures/impls/moe_experts/__init__.py +9 -0
  81. flashrt_structures/impls/moe_experts/nvfp4_dynamic.py +208 -0
  82. flashrt_structures/impls/moe_experts/nvfp4_w4a16.py +129 -0
  83. flashrt_structures/impls/norm_fused/__init__.py +3 -0
  84. flashrt_structures/impls/norm_fused/bf16.py +94 -0
  85. flashrt_structures/impls/norm_fused/fp8_producer.py +84 -0
  86. flashrt_structures/impls/patch_projection/__init__.py +3 -0
  87. flashrt_structures/impls/patch_projection/bf16_flat.py +139 -0
  88. flashrt_structures/impls/prefill_tower/__init__.py +10 -0
  89. flashrt_structures/impls/prefill_tower/fp8_chain.py +955 -0
  90. flashrt_structures/impls/prefill_tower/region.py +99 -0
  91. flashrt_structures/impls/qk_norm_rope/__init__.py +12 -0
  92. flashrt_structures/impls/qk_norm_rope/per_head_gqa.py +199 -0
  93. flashrt_structures/impls/qk_norm_rope/projection_bf16.py +165 -0
  94. flashrt_structures/impls/qkv_pack/__init__.py +5 -0
  95. flashrt_structures/impls/qkv_pack/bf16.py +110 -0
  96. flashrt_structures/impls/qkv_pack/fp8_static.py +435 -0
  97. flashrt_structures/impls/qkv_pack/nvfp4_balance.py +218 -0
  98. flashrt_structures/impls/qkv_rope/__init__.py +3 -0
  99. flashrt_structures/impls/qkv_rope/packed_bias_bf16.py +143 -0
  100. flashrt_structures/impls/step_table.py +113 -0
  101. flashrt_structures/impls/vision_ffn/__init__.py +0 -0
  102. flashrt_structures/impls/vision_ffn/fp8_static.py +261 -0
  103. flashrt_structures/impls/vision_ffn/nvfp4_balance.py +211 -0
  104. flashrt_structures/impls/vision_tower/__init__.py +7 -0
  105. flashrt_structures/impls/vision_tower/fp8_chain.py +533 -0
  106. flashrt_structures/impls/vision_tower/region.py +91 -0
  107. flashrt_structures/matrix.py +126 -0
  108. flashrt_structures/points.py +368 -0
  109. flashrt_structures/prequantized.py +131 -0
  110. flashrt_structures/quantize_on_adopt.py +94 -0
  111. flashrt_structures/recipe.py +438 -0
  112. flashrt_structures/regions.py +208 -0
  113. flashrt_structures/schemes.py +490 -0
  114. flashrt_structures/stages.py +298 -0
  115. flashrt_structures/storage.py +255 -0
  116. flashrt_structures/swap.py +398 -0
  117. flashrt_structures/workspace.py +110 -0
  118. flashrt_structures-0.2.0.dist-info/METADATA +140 -0
  119. flashrt_structures-0.2.0.dist-info/RECORD +122 -0
  120. flashrt_structures-0.2.0.dist-info/WHEEL +5 -0
  121. flashrt_structures-0.2.0.dist-info/licenses/LICENSE +202 -0
  122. flashrt_structures-0.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,388 @@
1
+ """adaln_producer — conditioning-driven norm, resolved per step.
2
+
3
+ Diffusion hosts modulate every layer with a projection of the current
4
+ timestep embedding. Two facts make this a structure rather than a plain
5
+ GEMM: the conditioning vector takes one of a small fixed set of values
6
+ over a tick (it is a function of the step), and the norm that consumes
7
+ it can fuse modulation and output quantization into one kernel.
8
+
9
+ This implementation splits those two concerns:
10
+
11
+ - :class:`StepLocator` resolves "which step is this" from the
12
+ conditioning tensor using a few high-separation coordinates — a
13
+ fingerprint — instead of a full-width matmul against every stored
14
+ vector. It is pure tensor work (index_select, squared distance,
15
+ argmax), so it traces under dynamo and captures into a graph without
16
+ host-side state. Sibling producers fed by the same conditioning
17
+ stream share one locator, letting the compiler fold the repeated
18
+ lookups.
19
+ - :class:`AdaLNProducer` replaces the host's adaptive norm: it looks up
20
+ the precomputed style row for the current step and runs the fused
21
+ norm+modulate(+static FP8 quantize) kernel, emitting either BF16 or
22
+ FP8 plus the host's gate. The FP8 form is the upstream half of a
23
+ producer→consumer seam: the shared ``act_scale`` lets a packed
24
+ projection skip its own input quantization.
25
+
26
+ Qualification: the conditioning must actually be step-quantized (more
27
+ distinct vectors than ``max_steps`` means it depends on more than the
28
+ step, and a table would alias different inputs onto one row), and the
29
+ chosen fingerprint coordinates must separate the stored vectors by a
30
+ real margin. Either failure raises ``ValueError`` — the host keeps its
31
+ own producer.
32
+ """
33
+
34
+ from __future__ import annotations
35
+
36
+ import torch
37
+
38
+ from .. import hub_kernel
39
+ from ...workspace import lease
40
+ from ...guard import CAST_OK, PROCEED, GuardedSeam
41
+
42
+
43
+ def _dedup(pairs, max_steps, rtol):
44
+ conds, outs = [], []
45
+ for cond, out in pairs:
46
+ c = cond.detach().reshape(-1, cond.shape[-1])
47
+ o = out.detach().reshape(-1, out.shape[-1])
48
+ for row in range(c.shape[0]):
49
+ cr = c[row]
50
+ if any(torch.allclose(cr, seen, rtol=rtol,
51
+ atol=1e-6 * cr.abs().max().item() + 1e-12)
52
+ for seen in conds):
53
+ continue
54
+ conds.append(cr.clone())
55
+ outs.append(o[row].clone())
56
+ if len(conds) > max_steps:
57
+ raise ValueError(
58
+ f"adaln_producer: >{max_steps} distinct conditioning "
59
+ "vectors — not step-quantized, keeping the host path")
60
+ if not conds:
61
+ raise ValueError("adaln_producer: no calibration pairs")
62
+ return torch.stack(conds), torch.stack(outs)
63
+
64
+
65
+ class StepLocator(torch.nn.Module):
66
+ """Resolve the current step index from the conditioning tensor."""
67
+
68
+ def __init__(self, conds: torch.Tensor, n_dims: int = 8,
69
+ rel_margin: float = 1e-3):
70
+ super().__init__()
71
+ c = conds.float()
72
+ steps = c.shape[0]
73
+ if steps == 1:
74
+ dims = torch.zeros(1, dtype=torch.long, device=c.device)
75
+ else:
76
+ diffs = (c.unsqueeze(0) - c.unsqueeze(1)).abs()
77
+ eye = torch.eye(steps, device=c.device, dtype=torch.bool)
78
+ diffs = diffs.masked_fill(eye.unsqueeze(-1), float("inf"))
79
+ minsep = diffs.amin(dim=(0, 1))
80
+ k = min(n_dims, c.shape[1])
81
+ dims = minsep.topk(k).indices.sort().values
82
+ margin = minsep[dims].min().item()
83
+ if margin < rel_margin * c.abs().mean().item():
84
+ raise ValueError(
85
+ "adaln_producer: conditioning vectors are not "
86
+ "separable on any coordinate subset")
87
+ self.register_buffer("fp_dims", dims)
88
+ self.register_buffer("fp_conds", c.index_select(
89
+ 1, dims).contiguous())
90
+
91
+ def forward(self, cond: torch.Tensor) -> torch.Tensor:
92
+ flat = cond.reshape(-1, cond.shape[-1]).float()
93
+ c = flat.index_select(1, self.fp_dims)
94
+ scores = -((c.unsqueeze(1) - self.fp_conds) ** 2).sum(-1)
95
+ return scores.argmax(-1)
96
+
97
+
98
+ class StyleTable(GuardedSeam, torch.nn.Module):
99
+ """Replace only the conditioning projection with its step table.
100
+
101
+ The narrower of the two bind forms: the host keeps its own norm
102
+ (often already fused by the compiler) and only the per-step style
103
+ projection is memoized. Prefer this wherever the norm itself is not
104
+ being upgraded — measurement decides, and the fused form is worth
105
+ its kernel only when it also serves a downstream seam.
106
+ """
107
+
108
+ _frt_host_attr = "host_linear"
109
+ _frt_can_fallback = True
110
+
111
+ def __init__(self, host_proj: torch.nn.Module, styles: torch.Tensor,
112
+ locator: StepLocator):
113
+ super().__init__()
114
+ self.host_linear = host_proj
115
+ self.locator = locator
116
+ self.register_buffer("table", styles.contiguous())
117
+ weight = getattr(host_proj, "weight", None)
118
+ self._frt_arm(dtypes=CAST_OK, device=self.table.device,
119
+ k=None if weight is None else int(weight.shape[1]))
120
+
121
+ def forward(self, cond: torch.Tensor) -> torch.Tensor:
122
+ admitted = self._frt_admit(cond)
123
+ if admitted is not PROCEED:
124
+ return admitted
125
+ out = self.table.index_select(0, self.locator(cond))
126
+ return out.reshape(*cond.shape[:-1], out.shape[-1])
127
+
128
+ def __getattr__(self, name):
129
+ try:
130
+ return super().__getattr__(name)
131
+ except AttributeError:
132
+ return getattr(super().__getattr__("host_linear"), name)
133
+
134
+
135
+ class AdaLNProducer(GuardedSeam, torch.nn.Module):
136
+ """Adaptive norm replacement: step lookup + fused norm/quantize.
137
+
138
+ This is the one structure in the library that refuses instead of
139
+ falling back, and the reason is that its output dtype is half of an
140
+ agreement with a downstream seam. On the fp8 entry it hands a packed
141
+ projection FP8 activations under a shared static scale; quietly
142
+ reverting to the host norm would hand that consumer BF16 under an FP8
143
+ scale. Two seams negotiated the form together, so neither can leave it
144
+ alone — a call outside the calibrated form raises here and the caller
145
+ detaches the attachment rather than running half of it.
146
+ """
147
+
148
+ _frt_host_attr = "host_norm"
149
+ _frt_can_fallback = False
150
+
151
+ def __init__(self, host_norm: torch.nn.Module,
152
+ styles: torch.Tensor, locator: StepLocator,
153
+ act_scale: torch.Tensor | None, rows: int, dim: int,
154
+ norm: str = "rms", out_format: str | None = None):
155
+ super().__init__()
156
+ self.host_norm = host_norm
157
+ self.locator = locator
158
+ self.norm = norm
159
+ # set by attach_broker when this producer joins a stream-scoped
160
+ # materialisation; alone, it materialises its own style
161
+ self.broker = None
162
+ self.slot = 0
163
+ self.writer = True
164
+ self.register_buffer("styles",
165
+ styles.to(torch.bfloat16).contiguous())
166
+ self.out_fp8 = act_scale is not None
167
+ self.out_nvfp4 = out_format == "nvfp4"
168
+ dev = styles.device
169
+ if self.out_nvfp4:
170
+ # NVFP4 wire emission: the fused kernel norms, modulates and
171
+ # quantizes into preallocated packed/SFA buffers, so a
172
+ # downstream pack takes the scale factors once at bind time
173
+ # (accept_wire) and every call — eager, compiled, captured —
174
+ # reads the same storage. Layer flavour serves the DiT form;
175
+ # the rms flavour rides the fp4-fused-ops twins when a host
176
+ # needs it.
177
+ if norm != "layer":
178
+ raise ValueError(
179
+ "adaln_producer: nvfp4 emission currently serves "
180
+ "the layer form")
181
+ kq = hub_kernel("flashrt/adaptive-layernorm-producers",
182
+ ">=1")
183
+ self._fn4 = kq.ada_layer_norm_quant_nvfp4_swizzled_bf16
184
+ probe = torch.zeros(rows, dim, device=dev,
185
+ dtype=torch.bfloat16)
186
+ zero = torch.zeros(dim, device=dev, dtype=torch.bfloat16)
187
+ packed, sfa = self._fn4(probe, zero, zero)
188
+ self.wire_packed = lease(tuple(packed.shape), packed.dtype,
189
+ dev, tag="producer_wire")
190
+ self.wire_sfa = lease(tuple(sfa.shape), sfa.dtype, dev,
191
+ tag="producer_wire_sfa")
192
+ elif norm == "layer":
193
+ # LayerNorm hosts (DiT AdaLayerNorm): style is (scale,
194
+ # shift), no gate, and the fused kernel takes the raw
195
+ # scale — it applies the (1 + scale) itself.
196
+ if not self.out_fp8:
197
+ raise ValueError("adaln_producer: layer norm form "
198
+ "currently requires fp8 output")
199
+ kq = hub_kernel("flashrt/adaptive-layernorm-producers", ">=1")
200
+ self._fn = kq.ada_layer_norm_quant_fp8_bf16
201
+ self.register_buffer("act_scale", act_scale)
202
+ else:
203
+ ka = hub_kernel("flashrt/flashrt-adaptive-norms", ">=1")
204
+ if self.out_fp8:
205
+ self._fn = ka.gate_residual_ada_norm_fp8_static_bf16
206
+ self.register_buffer("act_scale", act_scale)
207
+ else:
208
+ self._fn = ka.ada_rms_norm_style_bf16
209
+ # residual=0 / gate=1 turn the gated-residual kernel into a
210
+ # plain modulated norm; both are preallocated for graph replay.
211
+ # The kernel writes the residual buffer in place, so the zero
212
+ # has to be re-established on every call — a buffer that is
213
+ # merely allocated zeroed drifts silently from the second tick
214
+ # onward, and the drift compounds.
215
+ self.w_ones = lease((dim,), torch.bfloat16, dev,
216
+ tag="producer_ones", fill="ones")
217
+ self.resid = lease((rows, dim), torch.bfloat16, dev,
218
+ tag="producer_resid")
219
+ self.gate_ones = lease((rows, dim), torch.bfloat16, dev,
220
+ tag="producer_ones", fill="ones")
221
+ # the rms form works through the preallocated residual and gate
222
+ # buffers, so its row count is fixed; the layer form's kernel
223
+ # takes scale and shift directly and leaves rows free
224
+ self._frt_arm(dtypes=CAST_OK, device=dev, k=int(dim),
225
+ rows=(None if norm == "layer"
226
+ and not self.out_nvfp4 else int(rows)))
227
+
228
+ # ---- block-facing entries -------------------------------------
229
+ # A caller that owns the whole block (see ``impls.decoder_block``)
230
+ # can do two things a norm-boundary caller cannot: resolve the step
231
+ # once and share it across the producers on the same conditioning
232
+ # stream, and hand this producer the residual that is still pending
233
+ # from the previous sublayer. The kernel already computes
234
+ # ``residual + x * gate`` before it norms — at the norm boundary
235
+ # there is nothing to hand it, so the residual is zeroed and the
236
+ # host pays a separate elementwise add. These entries expose the
237
+ # wider contract without changing the standalone one below.
238
+
239
+ @property
240
+ def can_absorb(self) -> bool:
241
+ """Whether this producer can fold a pending gated residual."""
242
+ return self.out_fp8 and self.norm == "rms"
243
+
244
+ @property
245
+ def takes_style_rows(self) -> bool:
246
+ """Whether this form consumes a materialised ``(rows, W)`` style.
247
+
248
+ Only the rms form does. The layer form's kernel takes scale and
249
+ shift as separate one-row arguments, so there is nothing to
250
+ repeat to the row count and nothing for a broker to share — it
251
+ would attach, never be read, and still be reported as active.
252
+ """
253
+ return self.norm == "rms"
254
+
255
+ def attach_broker(self, broker, slot: int, *, writer: bool) -> None:
256
+ """Take styles from a stream-scoped broker (see :mod:`.broker`)."""
257
+ self.broker = broker
258
+ self.slot = slot
259
+ self.writer = writer
260
+
261
+ def resolve(self, cond: torch.Tensor):
262
+ """Step index for this conditioning — shareable across siblings.
263
+
264
+ With a broker only the stream's writer resolves anything: the
265
+ step is a property of the stream, not of this producer, and the
266
+ readers take their styles from the buffer the writer filled.
267
+ """
268
+ if self.broker is None:
269
+ return self.locator(cond)
270
+ return self.broker.refresh(cond) if self.writer else None
271
+
272
+ def _style2d(self, idx: torch.Tensor) -> torch.Tensor:
273
+ if self.broker is not None:
274
+ return self.broker.slice(self.slot)
275
+ style = self.styles.index_select(0, idx)
276
+ return style.expand(self.resid.shape[0], -1).contiguous()
277
+
278
+ def produce(self, x: torch.Tensor, idx: torch.Tensor):
279
+ """Normed output plus the full-width gate, both 2D.
280
+
281
+ The standalone ``forward`` slices the gate down to one row for
282
+ the host's broadcast add; a block caller keeps the full rows so
283
+ it can feed the gate straight back into :meth:`absorb`.
284
+ """
285
+ # a block reaches this entry instead of ``forward``, and the
286
+ # block's own contract already covered the form; count the call so
287
+ # the ledger does not report a producer that ran every tick as one
288
+ # that never ran
289
+ self._frt_touch()
290
+ style2d = self._style2d(idx)
291
+ x2d = x.reshape(-1, x.shape[-1])
292
+ if self.out_fp8:
293
+ self.resid.zero_() # in-place residual: reset per call
294
+ _, y, gate = self._fn(self.resid, x2d, self.gate_ones,
295
+ self.w_ones, style2d, self.act_scale)
296
+ else:
297
+ y, gate = self._fn(x2d, self.w_ones, style2d)
298
+ return y, gate
299
+
300
+ def absorb(self, residual: torch.Tensor, x: torch.Tensor,
301
+ gate: torch.Tensor, idx: torch.Tensor):
302
+ """Fold a pending ``residual + x * gate`` into this norm.
303
+
304
+ Returns the updated residual stream, the normed (fp8) output and
305
+ this producer's own gate. The residual is copied into the
306
+ kernel's in-place buffer rather than written through: the caller
307
+ owns its tensor and a hidden mutation of it is exactly the kind
308
+ of silent aliasing that only shows up as drift.
309
+ """
310
+ if not self.can_absorb:
311
+ raise ValueError(
312
+ "adaln_producer: absorb needs the rms form with fp8 "
313
+ "output — the plain entry has no residual argument")
314
+ self._frt_touch()
315
+ style2d = self._style2d(idx)
316
+ shape = self.resid.shape
317
+ self.resid.copy_(residual.reshape(shape))
318
+ return self._fn(self.resid, x.reshape(shape), gate,
319
+ self.w_ones, style2d, self.act_scale)
320
+
321
+ def forward(self, x: torch.Tensor, cond: torch.Tensor | None = None):
322
+ admitted = self._frt_admit(x, cond)
323
+ if admitted is not PROCEED: # unreachable: this form
324
+ return admitted # refuses rather than reverts
325
+ idx = self.locator(cond)
326
+ if self.out_nvfp4:
327
+ style = self.styles.index_select(0, idx)
328
+ scale, shift = style[0].chunk(2, dim=-1)
329
+ self._fn4(
330
+ x.reshape(-1, x.shape[-1]).to(torch.bfloat16)
331
+ .contiguous(),
332
+ scale.contiguous(), shift.contiguous(),
333
+ packed=self.wire_packed, sf_swizzled=self.wire_sfa)
334
+ return self.wire_packed.reshape(
335
+ *x.shape[:-1], x.shape[-1] // 2)
336
+ if self.norm == "layer":
337
+ style = self.styles.index_select(0, idx)
338
+ scale, shift = style[0].chunk(2, dim=-1)
339
+ y = self._fn(
340
+ x.reshape(-1, x.shape[-1]).to(torch.bfloat16)
341
+ .contiguous(),
342
+ scale.contiguous(), shift.contiguous(),
343
+ self.act_scale)
344
+ return y.reshape(x.shape)
345
+ y, gate = self.produce(x, idx)
346
+ return (y.reshape(x.shape),
347
+ gate[:1].reshape(1, 1, gate.shape[-1]).to(x.dtype))
348
+
349
+ def __getattr__(self, name):
350
+ try:
351
+ return super().__getattr__(name)
352
+ except AttributeError:
353
+ return getattr(super().__getattr__("host_norm"), name)
354
+
355
+
356
+ def bind_step_locator(pairs, *, max_steps: int = 64,
357
+ dedup_rtol: float = 1e-5, n_dims: int = 8):
358
+ """Build a locator and the step table from ``(cond, out)`` pairs."""
359
+ conds, outs = _dedup(pairs, max_steps, dedup_rtol)
360
+ return StepLocator(conds, n_dims=n_dims), outs
361
+
362
+
363
+ def bind_style_table(host_proj: torch.nn.Module, pairs, *,
364
+ locator: StepLocator | None = None,
365
+ max_steps: int = 64) -> StyleTable:
366
+ """Bind the table-only form onto the conditioning projection."""
367
+ built, styles = bind_step_locator(pairs, max_steps=max_steps)
368
+ return StyleTable(host_proj, styles, locator or built)
369
+
370
+
371
+ def bind_adaln_producer(host_norm: torch.nn.Module, pairs, *,
372
+ act_scale: torch.Tensor | None = None,
373
+ rows: int, dim: int,
374
+ locator: StepLocator | None = None,
375
+ max_steps: int = 64, norm: str = "rms",
376
+ out_format: str | None = None):
377
+ """Bind an adaptive-norm producer from real ``(cond, style)`` pairs.
378
+
379
+ ``pairs`` come from hooking the host's own conditioning projection
380
+ over at least one full tick, so the stored style rows are exactly
381
+ what the host computed. Pass ``act_scale`` to emit FP8 for a
382
+ downstream packed projection; pass ``locator`` to share the step
383
+ lookup with sibling producers on the same conditioning stream.
384
+ """
385
+ built, styles = bind_step_locator(pairs, max_steps=max_steps)
386
+ return AdaLNProducer(host_norm, styles, locator or built,
387
+ act_scale, rows, dim, norm=norm,
388
+ out_format=out_format)
@@ -0,0 +1,8 @@
1
+ """The adaptive-RMS decoder stack region: a cached-prefix expert tower.
2
+
3
+ An action-expert decoder whose every norm is conditioned (scale, shift,
4
+ gate from one dense projection), attending over a prefix another tower
5
+ left in the cache. One region family identifies the stack shape; its
6
+ fused-chain candidate re-expresses the whole per-layer loop in hub
7
+ primitives with static-FP8 GEMMs.
8
+ """