Skip to content

add-hea-encoding-emission: §1-§7 — HEA emit branch + animals_hea example - #3

Merged
jascal merged 2 commits into
mainfrom
add-hea-encoding-emission-impl
May 3, 2026
Merged

add-hea-encoding-emission: §1-§7 — HEA emit branch + animals_hea example#3
jascal merged 2 commits into
mainfrom
add-hea-encoding-emission-impl

Conversation

@jascal

@jascal jascal commented May 3, 2026

Copy link
Copy Markdown
Owner

Summary

  • Implements OpenSpec change add-hea-encoding-emission (proposal merged in add-hea-encoding-emission: §0 — proposal + spec deltas #2). Polygram now emits rung-2 HEA .q.orca.md machines alongside the existing rung-1 MPS path.
  • Users opt in via Dictionary(encoding=HEA_Rung2(...)). The renderer dispatches on encoding; the HEA branch emits ## encoding + 3-column ## theta (with cluster column) + optional ## invariants (concept_gram_tier_separation >= bound).
  • Per-feature θ tensors are accepted directly (Feature.theta); when absent, the emitter synthesizes a default tensor by laying (α, β, γ, φ) across the first HEA layer. Dictionary.gram() and the new Dictionary.tier_separation() dispatch on encoding type.

Notable choices

  • q-orca pinned at >=0.9.0 (the first PyPI release with HEA + tier-invariant support — published 2026-05-03).
  • Feature switched to eq=False so the optional np.ndarray θ field doesn't break dataclass equality semantics; existing tests still pass unchanged.
  • HEA rendering matches the q-orca-lang examples/larql-hea-minimal.q.orca.md shape; pairing convention is positional (compute_concept_gram_hea pairs query_concept call sites with theta rows by declaration order).
  • The new examples/animals_hea.py mirrors the Animals dictionary at depth 2; verifies clean with tier_separation ≈ 0.22 (well above the declared 0.025 bound).

Out of scope (deferred)

Multi-knob structural-floor / Cancellation generalization, sweep-to-θ, QFT_Rung3, and Dictionary.from_sae_with_hea heuristics — see openspec/changes/add-hea-encoding-emission/proposal.md "Out of Scope".

Test plan

  • openspec validate add-hea-encoding-emission --strict
  • Full pytest: 130 passed, 1 skipped (was 104 — 26 new tests)
  • ruff check polygram tests examples clean
  • python examples/animals_hea.py runs end-to-end; emitted .q.orca.md parses + verifies clean

🤖 Generated with Claude Code

jascal and others added 2 commits May 3, 2026 11:41
…example

Lifts Polygram to emit rung-2 HEA `.q.orca.md` machines alongside the
existing rung-1 MPS path. Users opt in via `Dictionary(encoding=
HEA_Rung2(...))`; the renderer dispatches on encoding type, the HEA
branch produces `## encoding` + 3-column `## theta` + (optional)
`## invariants` sections, and the q-orca verifier accepts the file with
the declared `concept_gram_tier_separation` invariant satisfied.

- §1 pyproject `q-orca>=0.9.0`; AGENTS.md dependency-contract refresh
- §2 `HEA_Rung2(depth, entangler, rotations, tier_separation_bound,
      n_qubits)` frozen dataclass with full validation + theta_shape
- §3 `Feature.theta` optional field, shape-validated against the
      encoding; `_default_hea_theta` lays (α,β,γ,φ) on the first layer
- §4 `Dictionary.gram()` dispatches MPS↔HEA; new
      `Dictionary.tier_separation()` wraps `compute_tier_separation`
- §5 `_qorca_emit` HEA branch — `## encoding` table, 3-col `## theta`
      with cluster column, conditional `## invariants` (suppressed when
      `tier_separation_bound is None`), one `query_concept` per feature
- §6 26 new tests: `TestHEARung2`, `TestHEADictionary`, `TestHEAEmit`,
      HEA round-trip in `test_emit.py`
- §7 `examples/animals_hea.py` mirrors the Animals dictionary with
      depth-2 HEA, asserts `verify(machine).valid`, prints tier_sep

130 pytest pass (was 104), ruff clean, openspec validate --strict ✓.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…dary

When `rotations == ("Rz",)` and `n_qubits < 2`, both α and φ map to
slot (0, 0, 0); φ is written last and silently overwrites α. That's a
degenerate configuration for the rung-2 spike (which targets 3 qubits),
but the helper doesn't raise — note the boundary in the docstring so
callers know to pass an explicit `Feature.theta` for such layouts.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@jascal
jascal merged commit 1b19adb into main May 3, 2026
jascal added a commit that referenced this pull request May 15, 2026
…#76)

* impl(add-phase-knob-assignment): un-dormant MPSRung1 α/φ + bump 0.6.0

Resolves the root cause of the 2026-05-15 GPT-2 bug report. Adds
`assign_phase_knobs: bool = False` flag to `from_sae_lens`,
populating MPS-substrate α (PC2) and φ (PC3) from decoder PCA when
opted in. Parallel to PR #63's `assign_amp_knobs` for amp branches.

Real-SAE confirmation on the same fixture that surfaced the bug:

  Encoding         | Flag                    | Mean off-diag | λ_min | Cond #
  -----------------|-------------------------|---------------|-------|---------
  MPSRung1 K=8     | (none, baseline)        | 0.7725        | ~0    | inf
  MPSRung1 K=8     | --assign-phase-knobs    | 0.2982        | +0.064| 51
  Rung4 K=32       | --assign-amp-knobs      | 0.4071        | +1e-15| 1.7e+16
  Rung4 K=32       | both flags              | 0.2038        | +4e-14| 2.7e+14

MPSRung1 with phase-on is no longer rank-deficient.

Files (mirrors PR #63 + PR #64 patterns):
- polygram/geometry/phase_assignment.py (new helper, PCA via SVD)
- polygram/geometry/amp_assignment.py (axis shift: PC2-PC5 → PC4-PC7)
- polygram/geometry/protocols.py (KnobAssignmentResult.alphas/phis,
  protocol signature extension)
- polygram/geometry/clustered.py, uniform_sphere.py (strategies)
- polygram/sae_import.py, polygram/config.py (loader + config)
- polygram/compression/epoch.py, compressor.py (compression plumbing)
- examples/rung_gram_condition.py, rung_compression_coverage.py
  (--assign-phase-knobs CLI flag, recorded in output JSON)

Tests:
- tests/test_phase_knob_assignment.py — 12 tests; cornerstone
  falsifying invariant verified (gram with phase-on differs from
  off by Frobenius > 1.0 AND mean off-diag drops below half)
- tests/compression/test_epoch_encoding_configurable.py — 3 new
  plumbing tests (field default; captured-kwargs reach every
  from_sae_lens call; default False propagates)

855 → 870 passing tests; ruff clean; openspec validate strict pass.

Version bump: 0.5.0 → 0.6.0. The amp-axis shift is the load-bearing
reason for the minor: callers with `assign_amp_knobs=True` see
different exact gram-condition numbers (qualitative invariants
preserved). README "SAE import" section updated to document both
flags.

v2.3 supplement added to rung4-viability-spike-v2.md with the
real-SAE measurements above. v2.2 Axis 1 PASS verdict notes the
pre-shift caveat; v2.3 re-run recommended on torch host as
follow-up.

Backward-compat for `assign_amp_knobs=True` callers: PR-#63-era
exact gram-condition numbers in docs/research/data/rung_gram_
condition_*_amp_on.json regenerated with the post-shift allocation;
the cornerstone falsifying tests from PR #63 still pass.

Closes #1 of the 2026-05-15 GPT-2 bug report. Bugs #2, #3, #4
remain separate scopes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* review polish: knob→PCA priority comment + README composition table

Address review feedback on PR #76:
- phase_assignment.py + amp_assignment.py: add a "Knob → PCA-component
  priority order" block at the top of each docstring listing all
  seven slots (PC1→β, PC2→α, PC3→φ, PC4-PC7→amp). Same content,
  one in each file, so a reader stumbling onto either module sees
  the full priority order without cross-referencing.
- README "SAE import" section: add a 4-row truth table showing the
  two-flag composition matrix on Rung4 (matching the design.md/
  CHANGELOG version). Reviewer asked for explicit orthogonality
  call-out; table makes it unmissable.

Non-blocking nits skipped:
- Edge-case guards/notes: the helper already guards <3-feature and
  near-degenerate cases via `n_available_axes` check (falls back to
  encoding default), and test_degenerate_pca_falls_back_to_
  encoding_defaults pins that. Duplicate guards weren't asked for.
- SVD batching: premature optimization, no current consumer pressure.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
jascal pushed a commit that referenced this pull request Jun 13, 2026
…dout basis is wrong for co-firing

Ran the head-to-head behavioural gate (task 4). Extended behavioural_gram_scaleup.py with
--profile {clustered,readout-aligned} --readout-rank R (+ HF-cache SAE fallback, --sae-path), supplying
GPT-2's tied unembed + ln_f gain as u_matrix/gain.

RESULT (blocks.10, Spearman(Polygram, co-firing Jaccard)): clustered 0.640; readout r=64 0.267; r=256 0.067;
r=768(full) 0.640. Readout-alignment STRICTLY HURTS — full rank just recovers the baseline (a full-rank
readout projection is an orthonormal rotation and k-means is rotation-invariant), every truncation degrades.
Mechanism: co-firing is ENCODER-side (which features fire together, full-residual geometry); the readout
subspace is DECODE-side (argmax). Readout-alignment is right for the decode tax (R2 +52/+31/+40pp) but WRONG
for co-firing -> this VINDICATES the raw-decoder geometry here (0.640 is not a basis artifact; Reckoning #3's
basis-limited concern doesn't apply). The profile ships as a correct tool for decode-relevant geometry; a
decode-side behavioural metric is where it would help. Writeup in proposal "Gate RESULT" +
behavioural-scaleup-probe.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant