qigkernels 0.4.2__tar.gz → 0.4.3__tar.gz

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 (91) hide show
  1. {qigkernels-0.4.2/qigkernels.egg-info → qigkernels-0.4.3}/PKG-INFO +1 -1
  2. {qigkernels-0.4.2 → qigkernels-0.4.3}/kernel.py +46 -4
  3. {qigkernels-0.4.2 → qigkernels-0.4.3}/layer.py +54 -2
  4. {qigkernels-0.4.2 → qigkernels-0.4.3}/natural_gradient_optimizer.py +10 -2
  5. {qigkernels-0.4.2 → qigkernels-0.4.3}/pyproject.toml +3 -0
  6. {qigkernels-0.4.2 → qigkernels-0.4.3/qigkernels.egg-info}/PKG-INFO +1 -1
  7. {qigkernels-0.4.2 → qigkernels-0.4.3}/qigkernels.egg-info/SOURCES.txt +1 -2
  8. {qigkernels-0.4.2 → qigkernels-0.4.3}/qigkernels.egg-info/scm_file_list.json +56 -56
  9. qigkernels-0.4.3/qigkernels.egg-info/scm_version.json +8 -0
  10. qigkernels-0.4.3/tests/test_banded_attention.py +40 -0
  11. {qigkernels-0.4.2 → qigkernels-0.4.3}/uv.lock +156 -1
  12. qigkernels-0.4.2/qigkernels.egg-info/scm_version.json +0 -8
  13. qigkernels-0.4.2/tokenizer_integration.py +0 -368
  14. {qigkernels-0.4.2 → qigkernels-0.4.3}/.editorconfig +0 -0
  15. {qigkernels-0.4.2 → qigkernels-0.4.3}/.github/workflows/release.yml +0 -0
  16. {qigkernels-0.4.2 → qigkernels-0.4.3}/.gitignore +0 -0
  17. {qigkernels-0.4.2 → qigkernels-0.4.3}/20251205-architecture-canonical-0.01F.md +0 -0
  18. {qigkernels-0.4.2 → qigkernels-0.4.3}/20251205-changelog-canonical-0.01F.md +0 -0
  19. {qigkernels-0.4.2 → qigkernels-0.4.3}/20251205-decisions-canonical-0.01F.md +0 -0
  20. {qigkernels-0.4.2 → qigkernels-0.4.3}/20251205-naming-convention-canonical-0.01F.md +0 -0
  21. {qigkernels-0.4.2 → qigkernels-0.4.3}/20251205-readme-canonical-0.01F.md +0 -0
  22. {qigkernels-0.4.2 → qigkernels-0.4.3}/20251205-roadmap-canonical-0.01F.md +0 -0
  23. {qigkernels-0.4.2 → qigkernels-0.4.3}/20251205-type-symbol-manifest-canonical-0.01F.md +0 -0
  24. {qigkernels-0.4.2 → qigkernels-0.4.3}/20251220-gfp-spec-1.00W.md +0 -0
  25. {qigkernels-0.4.2 → qigkernels-0.4.3}/CLAUDE.md +0 -0
  26. {qigkernels-0.4.2 → qigkernels-0.4.3}/README.md +0 -0
  27. {qigkernels-0.4.2 → qigkernels-0.4.3}/__init__.py +0 -0
  28. {qigkernels-0.4.2 → qigkernels-0.4.3}/basin.py +0 -0
  29. {qigkernels-0.4.2 → qigkernels-0.4.3}/basin_sync.py +0 -0
  30. {qigkernels-0.4.2 → qigkernels-0.4.3}/constants.py +0 -0
  31. {qigkernels-0.4.2 → qigkernels-0.4.3}/constellation.py +0 -0
  32. {qigkernels-0.4.2 → qigkernels-0.4.3}/coord_adapter.py +0 -0
  33. {qigkernels-0.4.2 → qigkernels-0.4.3}/coordizer.py +0 -0
  34. {qigkernels-0.4.2 → qigkernels-0.4.3}/crystallization.py +0 -0
  35. {qigkernels-0.4.2 → qigkernels-0.4.3}/docs/20251205-client-wiring-example-canonical-0.01F.md +0 -0
  36. {qigkernels-0.4.2 → qigkernels-0.4.3}/docs/20251205-index-canonical-0.01F.md +0 -0
  37. {qigkernels-0.4.2 → qigkernels-0.4.3}/docs/20251206-e8-consciousness-stack-diagram.md +0 -0
  38. {qigkernels-0.4.2 → qigkernels-0.4.3}/docs/20251206-integration-plan-ultra-mode-0.01H.md +0 -0
  39. {qigkernels-0.4.2 → qigkernels-0.4.3}/docs/20251206-rel-weighted-basin-sync-spec.md +0 -0
  40. {qigkernels-0.4.2 → qigkernels-0.4.3}/docs/20251220-index-1.00W.md +0 -0
  41. {qigkernels-0.4.2 → qigkernels-0.4.3}/docs/20251220-qig-core-integration-table-1.00W.md +0 -0
  42. {qigkernels-0.4.2 → qigkernels-0.4.3}/docs/20251222-federated-constellation-architecture-0.01W.md +0 -0
  43. {qigkernels-0.4.2 → qigkernels-0.4.3}/docs/20251222-kernel-constellation-research-0.01W.md +0 -0
  44. {qigkernels-0.4.2 → qigkernels-0.4.3}/docs/20251222-kernel-experiments-results-0.01F.md +0 -0
  45. {qigkernels-0.4.2 → qigkernels-0.4.3}/heart.py +0 -0
  46. {qigkernels-0.4.2 → qigkernels-0.4.3}/kernel_100m.py +0 -0
  47. {qigkernels-0.4.2 → qigkernels-0.4.3}/kernel_4d.py +0 -0
  48. {qigkernels-0.4.2 → qigkernels-0.4.3}/markdownlint.json +0 -0
  49. {qigkernels-0.4.2 → qigkernels-0.4.3}/memory_classes.py +0 -0
  50. {qigkernels-0.4.2 → qigkernels-0.4.3}/metrics.py +0 -0
  51. {qigkernels-0.4.2 → qigkernels-0.4.3}/pre-commit-config.yaml +0 -0
  52. {qigkernels-0.4.2 → qigkernels-0.4.3}/pure_kernel_template.py +0 -0
  53. {qigkernels-0.4.2 → qigkernels-0.4.3}/py.typed +0 -0
  54. {qigkernels-0.4.2 → qigkernels-0.4.3}/qigkernels.egg-info/dependency_links.txt +0 -0
  55. {qigkernels-0.4.2 → qigkernels-0.4.3}/qigkernels.egg-info/requires.txt +0 -0
  56. {qigkernels-0.4.2 → qigkernels-0.4.3}/qigkernels.egg-info/top_level.txt +0 -0
  57. {qigkernels-0.4.2 → qigkernels-0.4.3}/reasoning/__init__.py +0 -0
  58. {qigkernels-0.4.2 → qigkernels-0.4.3}/reasoning/constants.py +0 -0
  59. {qigkernels-0.4.2 → qigkernels-0.4.3}/reasoning/modes.py +0 -0
  60. {qigkernels-0.4.2 → qigkernels-0.4.3}/reasoning/primitives.py +0 -0
  61. {qigkernels-0.4.2 → qigkernels-0.4.3}/reasoning/qig_chain.py +0 -0
  62. {qigkernels-0.4.2 → qigkernels-0.4.3}/reasoning/qig_chain_4d.py +0 -0
  63. {qigkernels-0.4.2 → qigkernels-0.4.3}/reasoning/temporal.py +0 -0
  64. {qigkernels-0.4.2 → qigkernels-0.4.3}/reasoning/temporal_attention.py +0 -0
  65. {qigkernels-0.4.2 → qigkernels-0.4.3}/rel_coupling.py +0 -0
  66. {qigkernels-0.4.2 → qigkernels-0.4.3}/research/track_c/20260223-track-c-expressibility-kill-test-1.00F.md +0 -0
  67. {qigkernels-0.4.2 → qigkernels-0.4.3}/research/track_c/README.md +0 -0
  68. {qigkernels-0.4.2 → qigkernels-0.4.3}/research/track_c/core_assets/__init__.py +0 -0
  69. {qigkernels-0.4.2 → qigkernels-0.4.3}/research/track_c/core_assets/neural_oscillators.py +0 -0
  70. {qigkernels-0.4.2 → qigkernels-0.4.3}/research/track_c/core_assets/neurotransmitter_fields.py +0 -0
  71. {qigkernels-0.4.2 → qigkernels-0.4.3}/research/track_c/core_assets/ocean_neurochemistry.py +0 -0
  72. {qigkernels-0.4.2 → qigkernels-0.4.3}/research/track_c/dynamical_field.py +0 -0
  73. {qigkernels-0.4.2 → qigkernels-0.4.3}/research/track_c/readout_layer.py +0 -0
  74. {qigkernels-0.4.2 → qigkernels-0.4.3}/research/track_c/run_kill_test.py +0 -0
  75. {qigkernels-0.4.2 → qigkernels-0.4.3}/router.py +0 -0
  76. {qigkernels-0.4.2 → qigkernels-0.4.3}/safety.py +0 -0
  77. {qigkernels-0.4.2 → qigkernels-0.4.3}/scripts/20251222-kernel-training-exp-0.01W.py +0 -0
  78. {qigkernels-0.4.2 → qigkernels-0.4.3}/scripts/publish_pypi.sh +0 -0
  79. {qigkernels-0.4.2 → qigkernels-0.4.3}/scripts/train_constellation.py +0 -0
  80. {qigkernels-0.4.2 → qigkernels-0.4.3}/setup.cfg +0 -0
  81. {qigkernels-0.4.2 → qigkernels-0.4.3}/sleep_packet.py +0 -0
  82. {qigkernels-0.4.2 → qigkernels-0.4.3}/specializations.py +0 -0
  83. {qigkernels-0.4.2 → qigkernels-0.4.3}/storage.py +0 -0
  84. {qigkernels-0.4.2 → qigkernels-0.4.3}/tests/__init__.py +0 -0
  85. {qigkernels-0.4.2 → qigkernels-0.4.3}/tests/test_coords_path.py +0 -0
  86. {qigkernels-0.4.2 → qigkernels-0.4.3}/tests/test_locality.py +0 -0
  87. {qigkernels-0.4.2 → qigkernels-0.4.3}/tests/test_phi_collapse.py +0 -0
  88. {qigkernels-0.4.2 → qigkernels-0.4.3}/tests/test_reasoning.py +0 -0
  89. {qigkernels-0.4.2 → qigkernels-0.4.3}/tests/test_smoke.py +0 -0
  90. {qigkernels-0.4.2 → qigkernels-0.4.3}/tools/qig_purity_check.py +0 -0
  91. {qigkernels-0.4.2 → qigkernels-0.4.3}/training_service.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qigkernels
3
- Version: 0.4.2
3
+ Version: 0.4.3
4
4
  Summary: Geometric kernel and constellation library for QIG.
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -65,6 +65,9 @@ class Kernel(nn.Module):
65
65
  enable_coords: bool = False,
66
66
  coord_dim: int = 64,
67
67
  locality_radius: int | None = None,
68
+ head_mode: str = "geometric",
69
+ head_tau: float = 1.0,
70
+ coord_basins: "Tensor | None" = None,
68
71
  ) -> None:
69
72
  """
70
73
  Initialize kernel.
@@ -133,8 +136,43 @@ class Kernel(nn.Module):
133
136
  ]
134
137
  )
135
138
 
136
- # Output projection
137
- self.lm_head = nn.Linear(hidden_dim, vocab_size)
139
+ # Output projection / readout. Two modes (the head A/B for the "no Euclidean readout" directive):
140
+ # "geometric" (default) — GeometricHead: vocab logits are Fisher-Rao DISTANCES from the hidden
141
+ # simplex-point to learned per-token Δ⁶³ basins (logit = −d_FR/τ). This is the SAME primitive
142
+ # as the purged-cosine→Fisher-Rao attention, pointed at the vocabulary; NO Euclidean nn.Linear,
143
+ # NO dot-product at the output boundary. It still returns [B,T,vocab] logits, so the downstream
144
+ # fisher_rao_lm_loss (which projects with to_simplex_prob) consumes it UNCHANGED.
145
+ # "linear" — the original Euclidean nn.Linear(hidden, vocab) readout, RETAINED as the A/B baseline
146
+ # so the architecture comparison can isolate the readout (geometric vs linear) empirically.
147
+ self.head_mode = str(head_mode).strip().lower()
148
+ self.head_tau = float(head_tau)
149
+ if self.head_mode == "geometric":
150
+ from qig_core.torch.geometric_head import GeometricHead
151
+
152
+ self.lm_head: nn.Module = GeometricHead(
153
+ hidden_dim=hidden_dim, vocab_size=vocab_size, tau=self.head_tau
154
+ )
155
+ elif self.head_mode == "basin":
156
+ # BASIN-SPACE readout (validated 2026-07-01: overfit d_FR 1.46→0.072, decode 91.3% where the
157
+ # logits head floored). Predicts the next token's basin DIRECTLY in the coordizer's Δ⁶³ space
158
+ # and scores it with pure d_FR against the coordizer's OWN frozen per-token basins — so a token
159
+ # has ONE basin (read-in == predict), the coherence the geometric head lacked. Requires the
160
+ # coordizer basin table (the tie); refuse to silently fall back to a disconnected head.
161
+ if coord_basins is None:
162
+ raise ValueError(
163
+ "head_mode='basin' requires coord_basins=[vocab, basin_dim] (the coordizer's per-token "
164
+ "basins) — the whole point is to TIE the output to the coordizer. Pass it from the "
165
+ "coordizer vocab, or use head_mode='geometric'/'linear'."
166
+ )
167
+ from qig_core.torch.basin_readout import BasinReadout
168
+
169
+ self.lm_head = BasinReadout(
170
+ hidden_dim=hidden_dim, coord_basins=coord_basins, tau=self.head_tau
171
+ )
172
+ elif self.head_mode == "linear":
173
+ self.lm_head = nn.Linear(hidden_dim, vocab_size)
174
+ else:
175
+ raise ValueError(f"head_mode must be 'geometric', 'basin', or 'linear', got {head_mode!r}")
138
176
 
139
177
  # Optional custom components
140
178
  self.running_coupling = running_coupling
@@ -160,6 +198,7 @@ class Kernel(nn.Module):
160
198
  attention_mask: Tensor | None = None,
161
199
  return_telemetry: bool = False,
162
200
  coords: Tensor | None = None,
201
+ skip_head: bool = False,
163
202
  ) -> Tensor | tuple[Tensor, KernelTelemetry]:
164
203
  """
165
204
  Forward pass through the kernel.
@@ -230,8 +269,11 @@ class Kernel(nn.Module):
230
269
  if self.running_coupling is not None:
231
270
  hidden_state = self.running_coupling(hidden_state)
232
271
 
233
- # Output projection
234
- logits = self.lm_head(hidden_state)
272
+ # Output projection. K-COMPRESS: skip_head returns logits=None so the caller reads hidden_state from
273
+ # telemetry and computes the basin loss via lm_head.predict(h) [.., basin_dim] + the target basins —
274
+ # NEVER materialising [B, T, vocab] (the seq×vocab activation OOM at 32k). Only meaningful WITH
275
+ # return_telemetry (the hidden state is the payload). Decode uses lm_head.decode_blocked(h).
276
+ logits = None if skip_head else self.lm_head(hidden_state)
235
277
 
236
278
  if not return_telemetry:
237
279
  return logits
@@ -205,14 +205,25 @@ class QIGLayer(nn.Module):
205
205
 
206
206
  b, t, _d = hidden_state.shape
207
207
  p = self._project_to_simplex(hidden_state)
208
+ r = self.locality_radius
209
+ # COMPUTE-SKIPPING windowed-local attention: when a locality radius is set AND the band is narrower
210
+ # than the sequence, attend only within ±r — O(t·r) memory/compute instead of the O(t²) all-pairs
211
+ # arccos tensor. This is what lifts the quadratic VRAM ceiling and makes context LINEAR/extensible
212
+ # (the radius is the finite-propagation budget). Numerically IDENTICAL to the full+mask path within
213
+ # the band (matched-cell equivalence-gated in tests) — it SKIPS the out-of-band compute, not masks it.
214
+ if r is not None and t > (2 * r + 1):
215
+ return self._banded_attention(hidden_state, p, r, attention_mask=attention_mask)
216
+
217
+ # Full O(t²) path — global attention, OR small-t where the band already spans every key (so the
218
+ # banded result is identical). Unchanged.
208
219
  p_i = p[:, :, None, :]
209
220
  p_j = p[:, None, :, :]
210
221
 
211
222
  dist = self._fisher_rao_distance_simplex(p_i, p_j)
212
223
  logits = -dist / max(float(self.temperature), 1e-6)
213
- if self.locality_radius is not None: # windowed-local: mask keys outside ±radius (pure mask)
224
+ if r is not None: # windowed-local: mask keys outside ±radius (pure mask; small-t branch)
214
225
  idx = torch.arange(t, device=hidden_state.device)
215
- band = (idx[:, None] - idx[None, :]).abs() <= self.locality_radius # [t, t]; self always in window
226
+ band = (idx[:, None] - idx[None, :]).abs() <= r # [t, t]; self always in window
216
227
  logits = logits.masked_fill(~band[None, :, :], float("-inf"))
217
228
  weights = torch.softmax(logits, dim=-1)
218
229
 
@@ -233,6 +244,47 @@ class QIGLayer(nn.Module):
233
244
  output = output + torch.randn_like(output) * float(self.decoherence_std)
234
245
  return output
235
246
 
247
+ def _banded_attention(
248
+ self, hidden_state: Tensor, p: Tensor, r: int, *, attention_mask: Tensor | None
249
+ ) -> Tensor:
250
+ """Windowed Fisher-Rao attention computed ONLY within ±r of each query (compute-skipping, O(t·r)).
251
+ Numerically equivalent to the full+mask path within the band; the equivalence is gated in tests."""
252
+ b, t, k = p.shape
253
+ w = 2 * r + 1
254
+ # per-query key windows via pad+unfold (zero-pad → out-of-range keys, masked below)
255
+ p_pad = F.pad(p, (0, 0, r, r)) # [b, t+2r, k]
256
+ p_win = p_pad.unfold(1, w, 1) # [b, t, k, w]
257
+ p_q = p[:, :, :, None] # [b, t, k, 1]
258
+ # SAME formula as _fisher_rao_distance_simplex: BC = Σ√(p·q), clamp, d = 2·acos(BC)
259
+ bc = torch.sqrt((p_q * p_win).clamp_min(1e-12)).sum(dim=2).clamp(0.0, 1.0 - 1e-6) # [b, t, w]
260
+ logits = (-2.0 * torch.acos(bc)) / max(float(self.temperature), 1e-6) # [b, t, w]
261
+ # valid window positions: wpos p ↦ key (i - r + p); valid iff 0 <= key < t
262
+ i_idx = torch.arange(t, device=p.device)[:, None] # [t, 1]
263
+ wpos = torch.arange(w, device=p.device)[None, :] # [1, w]
264
+ key_idx = i_idx - r + wpos # [t, w]
265
+ valid = (key_idx >= 0) & (key_idx < t) # [t, w] — band validity (self always valid)
266
+ # softmax over the BAND only (self valid → no all-(-inf) row → no NaN); key-padding is applied AFTER
267
+ # the softmax and renormalised — EXACTLY as the full+mask path does (so the two stay equivalent).
268
+ logits = logits.masked_fill(~valid[None].expand(b, t, w), float("-inf"))
269
+ weights = torch.softmax(logits, dim=-1) # [b, t, w]
270
+ if attention_mask is not None:
271
+ kpm = attention_mask if attention_mask.dtype == torch.bool else attention_mask == 0 # True=pad
272
+ if kpm.shape != (b, t):
273
+ raise ValueError("attention_mask expected shape (B, T)")
274
+ keep_win = F.pad((~kpm).to(p.dtype), (r, r)).unfold(1, w, 1) # [b, t, w] 1=valid key
275
+ weights = weights * (keep_win > 0.5)
276
+ weights = weights / (weights.sum(dim=-1, keepdim=True) + 1e-8)
277
+ if self.sparsity_threshold > 0.0:
278
+ keep_s = weights > float(self.sparsity_threshold)
279
+ weights = weights * keep_s
280
+ weights = weights / (weights.sum(dim=-1, keepdim=True) + 1e-8)
281
+ h_pad = F.pad(hidden_state, (0, 0, r, r)) # [b, t+2r, d]
282
+ h_win = h_pad.unfold(1, w, 1) # [b, t, d, w]
283
+ output = (weights[:, :, None, :] * h_win).sum(dim=-1) # [b, t, d]
284
+ if self.decoherence_std > 0.0:
285
+ output = output + torch.randn_like(output) * float(self.decoherence_std)
286
+ return output
287
+
236
288
  def _project_to_simplex(self, x: Tensor, eps: float = 1e-8) -> Tensor:
237
289
  x = x.abs() if self.simplex_mode == "abs" else F.softplus(x)
238
290
  return to_simplex_prob(x, eps=eps)
@@ -59,9 +59,17 @@ class NaturalGradientDescent(Optimizer):
59
59
  momentum=momentum,
60
60
  )
61
61
  super().__init__(params, defaults)
62
-
62
+
63
63
  self.compute_fisher = compute_fisher
64
-
64
+ if compute_fisher is None:
65
+ import warnings
66
+ warnings.warn(
67
+ "NaturalGradientDescent(compute_fisher=None) degrades to SGD+momentum — the step is the "
68
+ "RAW gradient, NOT preconditioned by the Fisher information. For the tractable diagonal "
69
+ "empirical-Fisher natural gradient (the P1 geometric optimizer), use DiagonalNaturalGradient.",
70
+ stacklevel=2,
71
+ )
72
+
65
73
  def step(self, closure=None):
66
74
  """
67
75
  Perform single optimization step.
@@ -81,3 +81,6 @@ forbidden-words = [
81
81
  "token-level cross entropy",
82
82
  "just fine-tune a transformer",
83
83
  ]
84
+
85
+ [tool.uv.sources]
86
+ qig-core = { path = "../qig-core", editable = true }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qigkernels
3
- Version: 0.4.2
3
+ Version: 0.4.3
4
4
  Summary: Geometric kernel and constellation library for QIG.
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -37,7 +37,6 @@ safety.py
37
37
  sleep_packet.py
38
38
  specializations.py
39
39
  storage.py
40
- tokenizer_integration.py
41
40
  training_service.py
42
41
  uv.lock
43
42
  ./__init__.py
@@ -64,7 +63,6 @@ uv.lock
64
63
  ./sleep_packet.py
65
64
  ./specializations.py
66
65
  ./storage.py
67
- ./tokenizer_integration.py
68
66
  ./training_service.py
69
67
  .github/workflows/release.yml
70
68
  docs/20251205-client-wiring-example-canonical-0.01F.md
@@ -105,6 +103,7 @@ scripts/20251222-kernel-training-exp-0.01W.py
105
103
  scripts/publish_pypi.sh
106
104
  scripts/train_constellation.py
107
105
  tests/__init__.py
106
+ tests/test_banded_attention.py
108
107
  tests/test_coords_path.py
109
108
  tests/test_locality.py
110
109
  tests/test_phi_collapse.py
@@ -1,84 +1,84 @@
1
1
  {
2
2
  "files": [
3
- "CLAUDE.md",
4
- "kernel.py",
5
- ".gitignore",
3
+ "20251205-decisions-canonical-0.01F.md",
4
+ "sleep_packet.py",
6
5
  "crystallization.py",
7
- "coordizer.py",
8
- "pyproject.toml",
9
- "__init__.py",
10
- "constants.py",
11
- ".editorconfig",
12
- "20251205-readme-canonical-0.01F.md",
13
- "storage.py",
14
6
  "markdownlint.json",
15
- "constellation.py",
16
- "safety.py",
17
- "router.py",
18
- "training_service.py",
19
- "sleep_packet.py",
20
- "20251205-decisions-canonical-0.01F.md",
21
- "coord_adapter.py",
22
- "20251205-type-symbol-manifest-canonical-0.01F.md",
23
- "rel_coupling.py",
24
- "20251205-roadmap-canonical-0.01F.md",
25
- "natural_gradient_optimizer.py",
7
+ "README.md",
8
+ "py.typed",
9
+ "__init__.py",
10
+ "kernel.py",
26
11
  "pre-commit-config.yaml",
27
- "20251205-naming-convention-canonical-0.01F.md",
28
- "tokenizer_integration.py",
12
+ "coord_adapter.py",
13
+ "uv.lock",
14
+ "safety.py",
15
+ "layer.py",
16
+ "pyproject.toml",
29
17
  "basin_sync.py",
18
+ "20251220-gfp-spec-1.00W.md",
19
+ "20251205-naming-convention-canonical-0.01F.md",
20
+ "pure_kernel_template.py",
30
21
  "20251205-architecture-canonical-0.01F.md",
31
22
  "heart.py",
32
- "kernel_100m.py",
33
- "pure_kernel_template.py",
23
+ "coordizer.py",
24
+ "20251205-changelog-canonical-0.01F.md",
25
+ "memory_classes.py",
26
+ "20251205-type-symbol-manifest-canonical-0.01F.md",
27
+ "constants.py",
34
28
  "basin.py",
35
- "uv.lock",
29
+ "kernel_100m.py",
30
+ "natural_gradient_optimizer.py",
31
+ "CLAUDE.md",
32
+ "router.py",
33
+ ".editorconfig",
36
34
  "kernel_4d.py",
37
- "README.md",
38
- "memory_classes.py",
39
- "metrics.py",
35
+ "storage.py",
36
+ "training_service.py",
37
+ "constellation.py",
38
+ ".gitignore",
39
+ "20251205-roadmap-canonical-0.01F.md",
40
+ "20251205-readme-canonical-0.01F.md",
40
41
  "specializations.py",
41
- "layer.py",
42
- "py.typed",
43
- "20251220-gfp-spec-1.00W.md",
44
- "20251205-changelog-canonical-0.01F.md",
45
- "reasoning/temporal.py",
42
+ "rel_coupling.py",
43
+ "metrics.py",
44
+ "scripts/20251222-kernel-training-exp-0.01W.py",
45
+ "scripts/train_constellation.py",
46
+ "scripts/publish_pypi.sh",
46
47
  "reasoning/__init__.py",
47
- "reasoning/primitives.py",
48
- "reasoning/constants.py",
49
- "reasoning/qig_chain.py",
50
48
  "reasoning/temporal_attention.py",
51
49
  "reasoning/modes.py",
50
+ "reasoning/qig_chain.py",
51
+ "reasoning/primitives.py",
52
+ "reasoning/temporal.py",
53
+ "reasoning/constants.py",
52
54
  "reasoning/qig_chain_4d.py",
53
55
  "docs/20251222-federated-constellation-architecture-0.01W.md",
54
- "docs/20251206-e8-consciousness-stack-diagram.md",
55
56
  "docs/20251222-kernel-constellation-research-0.01W.md",
56
- "docs/20251205-client-wiring-example-canonical-0.01F.md",
57
- "docs/20251220-index-1.00W.md",
58
- "docs/20251206-integration-plan-ultra-mode-0.01H.md",
59
57
  "docs/20251222-kernel-experiments-results-0.01F.md",
60
- "docs/20251206-rel-weighted-basin-sync-spec.md",
58
+ "docs/20251206-e8-consciousness-stack-diagram.md",
59
+ "docs/20251206-integration-plan-ultra-mode-0.01H.md",
60
+ "docs/20251205-client-wiring-example-canonical-0.01F.md",
61
61
  "docs/20251205-index-canonical-0.01F.md",
62
62
  "docs/20251220-qig-core-integration-table-1.00W.md",
63
- ".github/workflows/release.yml",
63
+ "docs/20251220-index-1.00W.md",
64
+ "docs/20251206-rel-weighted-basin-sync-spec.md",
65
+ "tests/__init__.py",
66
+ "tests/test_reasoning.py",
67
+ "tests/test_banded_attention.py",
68
+ "tests/test_phi_collapse.py",
69
+ "tests/test_smoke.py",
70
+ "tests/test_coords_path.py",
71
+ "tests/test_locality.py",
64
72
  "research/track_c/run_kill_test.py",
73
+ "research/track_c/README.md",
65
74
  "research/track_c/readout_layer.py",
66
- "research/track_c/20260223-track-c-expressibility-kill-test-1.00F.md",
67
75
  "research/track_c/dynamical_field.py",
68
- "research/track_c/README.md",
69
- "research/track_c/core_assets/ocean_neurochemistry.py",
76
+ "research/track_c/20260223-track-c-expressibility-kill-test-1.00F.md",
70
77
  "research/track_c/core_assets/__init__.py",
71
- "research/track_c/core_assets/neural_oscillators.py",
72
78
  "research/track_c/core_assets/neurotransmitter_fields.py",
79
+ "research/track_c/core_assets/neural_oscillators.py",
80
+ "research/track_c/core_assets/ocean_neurochemistry.py",
73
81
  "tools/qig_purity_check.py",
74
- "tests/test_reasoning.py",
75
- "tests/test_coords_path.py",
76
- "tests/__init__.py",
77
- "tests/test_smoke.py",
78
- "tests/test_phi_collapse.py",
79
- "tests/test_locality.py",
80
- "scripts/20251222-kernel-training-exp-0.01W.py",
81
- "scripts/publish_pypi.sh",
82
- "scripts/train_constellation.py"
82
+ ".github/workflows/release.yml"
83
83
  ]
84
84
  }
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "0.4.3",
3
+ "distance": 0,
4
+ "node": "g86259e8b5fe73edc0e9d803569e00f57c0794aad",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-07-01"
8
+ }
@@ -0,0 +1,40 @@
1
+ """Equivalence gate for compute-skipping windowed (banded) Fisher-Rao attention.
2
+
3
+ The banded path (O(t·r), used when locality_radius is set and t > 2r+1) must be NUMERICALLY IDENTICAL to
4
+ the full O(t²) all-pairs path masked to the same band — it SKIPS the out-of-band compute, it must not
5
+ change the result. This is the matched-cell equivalence gate that lets the cheap path's results count.
6
+ """
7
+ import pytest
8
+ import torch
9
+
10
+ from qigkernels.layer import QIGLayer
11
+
12
+
13
+ @pytest.mark.parametrize("t,r", [(64, 8), (128, 16), (50, 4), (33, 4), (40, 6)])
14
+ def test_banded_equals_full_mask(t, r):
15
+ torch.manual_seed(0)
16
+ L = QIGLayer(hidden_dim=48, num_heads=4, ffn_dim=64, locality_radius=r,
17
+ decoherence_std=0.0, sparsity_threshold=0.0)
18
+ L.eval()
19
+ h = torch.randn(2, t, 48)
20
+ p = L._project_to_simplex(h)
21
+ out_b = L._banded_attention(h, p, r, attention_mask=None)
22
+ p_i, p_j = p[:, :, None, :], p[:, None, :, :]
23
+ logits = -L._fisher_rao_distance_simplex(p_i, p_j) / max(float(L.temperature), 1e-6)
24
+ idx = torch.arange(t)
25
+ band = (idx[:, None] - idx[None, :]).abs() <= r
26
+ logits = logits.masked_fill(~band[None, :, :], float("-inf"))
27
+ out_f = torch.einsum("bij,bjd->bid", torch.softmax(logits, dim=-1), h)
28
+ assert torch.allclose(out_b, out_f, atol=1e-5, rtol=1e-4), (out_b - out_f).abs().max().item()
29
+
30
+
31
+ def test_banded_attention_mask_finite():
32
+ torch.manual_seed(1)
33
+ L = QIGLayer(hidden_dim=48, num_heads=4, ffn_dim=64, locality_radius=8,
34
+ decoherence_std=0.0, sparsity_threshold=0.0)
35
+ h = torch.randn(2, 64, 48)
36
+ p = L._project_to_simplex(h)
37
+ am = torch.ones(2, 64)
38
+ am[:, 50:] = 0 # padded tail — a query whose whole window is pad must NOT NaN
39
+ out = L._banded_attention(h, p, 8, attention_mask=am)
40
+ assert torch.isfinite(out).all()