feat(adr-0249): P1 conformal quantity kernel

Numbers as null points on the Cl(4,1) conformal line; add/scale by known
constants as translator/dilator versor sandwiches (affine Tier-1 scope).
Projective scale-invariant decode absorbs the dilator's conformal weight.

Reproducibility (spike §4.6 Tier 2): all construction explicit f64 (guards the
cl41 silent-f32 fallback); golden-bytes canary pins embed_quantity(3.0) SHA-256
for cross-hardware drift detection. Fail-closed QuantityKernelError on
non-finite input and degenerate conformal weight.

Spike doc: §8 rulings recorded RESOLVED (all four approved); §4.6 three-tier
byte-identity analysis added (LAPACK degenerate-eigenspace bound made explicit).

35/35 pins green.

[Verification]: uv run python -m pytest tests/test_adr_0249_quantity_kernel.py -q
This commit is contained in:
Shay 2026-07-18 12:04:28 -07:00
parent 5738252c37
commit 0926a78ccb
3 changed files with 301 additions and 11 deletions

View file

@ -0,0 +1,119 @@
"""core.physics.quantity_kernel — conformal quantity encoding (ADR-0249 P1).
Substrate-native representation of real quantities as null points on the
Cl(4,1) conformal line, with affine transport (add/scale by known constants)
realized as versor sandwiches. This is the standing hand the readerHamiltonian
compiler builds on: numbers live on the field before arithmetic relations can
become field constraints.
Encoding (spike §3, verified against algebra/cl41.py):
n_inf = e4 + e5, n_o = ½(e5 e4) (null basis of the line)
P(q) = n_o + q·e1 + ½·n_inf (null point at coordinate q)
Transport (exact, versor-native):
translate by a: T_a = 1 ½ a·e1·n_inf, T_a P(b) T̃_a = P(a+b)
scale by e^{α}: D_α = exp(+½ α·e4e5), D_α P(b) D̃_α = w·P(e^{α}·b)
Dilation carries a conformal weight w 1, so transported targets are decoded
*projectively* q = e1-coeff / (e5-coeff e4-coeff) which is scale-invariant.
The corridor requires unit-norm states, so relation compilation (P2) normalizes
before building the well; projective decode makes that lossless.
Reproducibility (spike §4.6, Tier 2): every construction is explicit float64.
`algebra.cl41.geometric_product` silently truncates to float32 unless handed
f64 arrays; this module never lets that happen. Serve-quarantined (A-04):
`core/physics/` is never imported by `chat/runtime.py`.
"""
from __future__ import annotations
import math
import numpy as np
from algebra import cl41 as cl
__all__ = [
"QuantityKernelError",
"embed_quantity",
"translate_quantity",
"dilate_quantity",
"decode_quantity",
]
# Grade-1 component indices (e1..e5 occupy indices 1..5 in the blade ordering).
_E1, _E4, _E5 = 1, 4, 5
# Minimum |conformal weight| below which projective decode is undefined.
_MIN_WEIGHT = 1e-9
class QuantityKernelError(ValueError):
"""Typed, fail-closed refusal for the quantity kernel (no guessed values)."""
def _e(i: int) -> np.ndarray:
"""i-th basis vector (0-indexed e1..e5) as an f64 multivector."""
return cl.basis_vector(i).astype(np.float64)
# Null basis of the conformal line, built once in f64.
_N_INF = _e(3) + _e(4) # e4 + e5
_N_O = 0.5 * (_e(4) - _e(3)) # ½(e5 e4)
_E1_NINF = cl.geometric_product(_e(0), _N_INF) # e1·n_inf, for the translator
_E4E5 = cl.geometric_product(_e(3), _e(4)) # e4e5, generator of the dilator
def _f64(value: float, *, what: str) -> float:
v = float(value)
if not math.isfinite(v):
raise QuantityKernelError(f"{what}_not_finite")
return v
def _sandwich(versor: np.ndarray, point: np.ndarray) -> np.ndarray:
"""versor · point · reverse(versor), all in f64."""
v = np.asarray(versor, dtype=np.float64)
p = np.asarray(point, dtype=np.float64)
return cl.geometric_product(cl.geometric_product(v, p), cl.reverse(v))
def embed_quantity(q: float) -> np.ndarray:
"""Null point P(q) = n_o + q·e1 + ½q²·n_inf as an f64 (32,) multivector."""
qf = _f64(q, what="quantity")
return (_N_O + qf * _e(0) + 0.5 * qf * qf * _N_INF).astype(np.float64)
def translate_quantity(point: np.ndarray, shift: float) -> np.ndarray:
"""Add a known constant: T_a P(b) T̃_a = P(a+b), exact and weight-preserving."""
a = _f64(shift, what="shift")
translator = np.zeros(cl.N_COMPONENTS, dtype=np.float64)
translator[0] = 1.0
translator = translator - 0.5 * a * _E1_NINF
return _sandwich(translator, point).astype(np.float64)
def dilate_quantity(point: np.ndarray, alpha: float) -> np.ndarray:
"""Scale by e^{α}: D_α = exp(+½α·e4e5). Carries a conformal weight (decode projectively)."""
a = _f64(alpha, what="alpha")
half = 0.5 * a
dilator = np.zeros(cl.N_COMPONENTS, dtype=np.float64)
dilator[0] = math.cosh(half)
dilator = dilator + math.sinh(half) * _E4E5
return _sandwich(dilator, point).astype(np.float64)
def decode_quantity(point: np.ndarray) -> float:
"""Projective (scale-invariant) recovery of q from a null point.
q = e1-coeff / (e5-coeff e4-coeff). Refuses when the conformal weight is
degenerate an unweighted direction has no finite line coordinate.
"""
arr = np.asarray(point, dtype=np.float64)
if arr.shape != (cl.N_COMPONENTS,):
raise QuantityKernelError("point_bad_shape")
if not np.all(np.isfinite(arr)):
raise QuantityKernelError("point_not_finite")
weight = float(arr[_E5]) - float(arr[_E4])
if abs(weight) < _MIN_WEIGHT:
raise QuantityKernelError("degenerate_conformal_weight")
return float(arr[_E1]) / weight

View file

@ -112,6 +112,37 @@ consumes nothing from this arc. Sealed practice vs serving split per ADR-0175; w
held on the deductive flagship; honest-NULL protocol on the instrument; proposal-only learning
(I-03) untouched.
### 4.6 Byte-identity & cross-hardware reproducibility (three tiers, honestly bounded)
The determinism claim splits into three tiers; only the first two are unconditionally
achievable, and the design says so rather than promising universal bit-identity.
- **Tier 1 — content address: SOLVED, unconditional.** `hamiltonian_id` = SHA-256 over
canonical JSON + explicit `<f8` LE matrix bytes (ADR-0244 §2.7). Endianness — the one real
architecture variable in hashing — is already coerced. Same matrix ⇒ same id on any machine.
- **Tier 2 — matrix construction: ACHIEVABLE, enforced in P1.** `algebra.cl41.geometric_product`
(`:108-125`) is a fixed-order scatter-add (`result[idx] += sign·aᵢ·bⱼ`, canonical i,j order),
no BLAS / `dot` / reduction ⇒ IEEE-754 correctly-rounded and hardware-deterministic. The
translator/dilator identities have integer/half-integer coefficients, so well *centers* are
bit-clean (verified §3). **Trap:** `geometric_product` and `reverse` silently fall back to
**float32** unless handed f64 arrays (`:110-112`, `:134-135`). P1 constructs every versor and
sandwich in explicit f64, and pins the result with **golden-bytes tests** — the frozen
SHA-256 of a canonical compiled-Hamiltonian set as literal constants, so any numpy / toolchain
/ hardware drift in the last bit fails the test loudly (same discipline as the biography
`<f8` hash pin and the `_cached_eigh` memoization tests).
- **Tier 3 — eigensolve → answer: GENUINELY hardware-bounded; do not overclaim.** The affine
well `H = c(Id ψψᵀ)` is dense, so `relax_to_ground` takes the LAPACK branch
(`cognitive_lifecycle.py:590-593`). Its excited eigenspace is **31-fold degenerate** (all at
energy c), and LAPACK fills that basis arbitrarily per build ⇒ `evecs`/`propagator` **bytes
are not cross-hardware identical**. Mitigation, in order:
1. **Analytic ground recovery.** The compiler *constructs* the target ψ (versor transport),
so the corridor's job is to *confirm* relaxation reaches span(ψ), not to discover it. The
converged steady state projects onto the unique 1-D ground space, so the degenerate-basis
arbitrariness cancels in the limit; pin the **basis-invariant** `phase_correlation/2`
agreement to ψ, never the propagator bytes.
2. Where a future non-affine tier yields a genuinely dense non-degenerate H, record
cross-hardware eigen-reproducibility as an explicit limitation (no-silent-caps) and pin
the **decision** (`_certified` already uses tolerances, not bit-equality), not the bytes.
## 5. In-tree inventory (survey bindings)
### 5.1 Hamiltonian construction contract (verified)
@ -228,15 +259,16 @@ Each phase: own PR, smoke-gated, TDD-first. New machinery ⇒ **ADR-0249** (Prop
re-verify number at landing), acceptance evidence assembled as in the intelligence-loop arc;
no self-Accept.
## 8. Open decisions (Shay)
## 8. Rulings (RESOLVED 2026-07-18)
1. Tier-1 scope ruling: affine-only, or include unknown×unknown via a declared non-versor
mechanism (leaning: affine-only; keep the versor story exact).
2. Confirm >5-atom deduction (ROBDD-partitioned turn programs) is the *next* arc, not this
one (leaning: yes — one coherent capability per arc; plan P6 reflects this).
3. ADR granularity: one ADR (0249) for quantity kernel + relation compiler + turn programs +
CNF converter, or split (leaning: one — they are one capability with four organs).
4. Field-reasoner wedge relationship: wedge continues independently on its 0D+W trajectory
while this arc generalizes the same versor mechanism into the corridor (leaning: yes;
any merge is a later explicit ADR, and the compiler must not import either wedge arm —
INV-27 stays intact).
All four APPROVED by Shay:
1. **Tier-1 = affine-only.** Unknown×unknown deferred; keep the versor story exact.
2. **>5-atom deduction = next arc**, via ROBDD-partitioned turn programs. NOTE the honest
reason: this is a *sequencing* choice (one capability per arc), **not** a claim that
>5-atom deduction is impossible or needs probabilistic approximation — composition handles
it deterministically and exactly. The 32-blade ceiling only forbids doing it *natively in
one Hamiltonian*; the certified turn chain crosses it losslessly.
3. **One ADR (0249)** for quantity kernel + relation compiler + CNF converter + turn programs.
4. **Field wedge continues independently** (0D+W); this arc generalizes the same versor
mechanism into the corridor; compiler imports neither wedge arm (INV-27 intact); any merge
is a later explicit ADR.

View file

@ -0,0 +1,139 @@
"""ADR-0249 P1 — conformal quantity kernel pins.
Verifies the substrate-native encoding of quantities as null points on the
Cl(4,1) conformal line, and affine transport by translator/dilator versors.
Every claim here was first checked numerically against algebra/cl41.py's own
multiplication table in the design spike
(docs/research/reader-hamiltonian-compiler-spike-2026-07-18.md §3); these are
the pinned, permanent form.
Reproducibility discipline (spike §4.6):
- Tier 2 (matrix/versor construction) MUST be f64 and hardware-deterministic;
the golden-bytes test is the cross-hardware canary.
"""
from __future__ import annotations
import hashlib
import numpy as np
import pytest
from algebra import cl41 as cl
from core.physics.quantity_kernel import (
QuantityKernelError,
decode_quantity,
dilate_quantity,
embed_quantity,
translate_quantity,
)
def _null_defect(psi: np.ndarray) -> float:
return abs(cl.scalar_part(cl.geometric_product(psi, psi)))
# --- Embedding: P(q) is a null point, in f64 ------------------------------
@pytest.mark.parametrize("q", [-50.0, -3.0, 0.0, 1.0, 7.5, 42.0])
def test_embedding_is_null(q: float) -> None:
assert _null_defect(embed_quantity(q)) < 1e-9
def test_embedding_is_float64() -> None:
# Guards the cl41 silent-f32 fallback (spike §4.6 Tier 2 trap).
assert embed_quantity(3.0).dtype == np.dtype(np.float64)
def test_embedding_shape() -> None:
assert embed_quantity(3.0).shape == (cl.N_COMPONENTS,)
# --- Translator: exact, weight-preserving (algebraic identity) ------------
@pytest.mark.parametrize(("a", "b"), [(3.0, 4.0), (-2.0, 9.0), (0.5, 0.5), (10.0, -10.0)])
def test_translate_is_exact_addition(a: float, b: float) -> None:
got = translate_quantity(embed_quantity(b), a)
want = embed_quantity(a + b)
# Integer/half-integer coefficients ⇒ f64 rounding only.
assert np.max(np.abs(got - want)) < 1e-9
def test_translate_stays_null() -> None:
assert _null_defect(translate_quantity(embed_quantity(4.0), 3.0)) < 1e-9
def test_translate_output_is_float64() -> None:
assert translate_quantity(embed_quantity(4.0), 3.0).dtype == np.dtype(np.float64)
# --- Dilator: scales by e^{-alpha} (SIGN PINNED, spike §3), weight != 1 ----
@pytest.mark.parametrize(("alpha", "b"), [(0.7, 3.0), (-1.1, 5.0), (2.0, -4.0)])
def test_dilate_scales_by_exp_minus_alpha(alpha: float, b: float) -> None:
q_dec = decode_quantity(dilate_quantity(embed_quantity(b), alpha))
assert abs(q_dec - np.exp(-alpha) * b) < 1e-6
def test_dilate_carries_conformal_weight() -> None:
# Weight must genuinely differ from 1 → normalize-then-projective-decode is required.
x = dilate_quantity(embed_quantity(3.0), 0.7)
weight = float(x[5]) - float(x[4])
assert abs(weight - 1.0) > 1e-3
# --- Decode: projective, scale-invariant, round-trips ---------------------
@pytest.mark.parametrize("q", [-50.0, -3.0, 0.0, 1.0, 7.5, 42.0])
def test_decode_round_trips_embedding(q: float) -> None:
assert abs(decode_quantity(embed_quantity(q)) - q) < 1e-9
@pytest.mark.parametrize("scale", [0.1, 1.0, 3.3, 10.0])
def test_decode_is_scale_invariant(scale: float) -> None:
psi = embed_quantity(7.5)
assert abs(decode_quantity(scale * psi) - decode_quantity(psi)) < 1e-9
def test_affine_chain_composes(a_mul: float = 3.0, add: float = 5.0, y: float = 4.0) -> None:
# "x = a*y + b" as versor transport. Dilation scales by e^{-alpha} (spike §3),
# so multiplying by a_mul needs alpha = -ln(a_mul), then translate by b.
psi = translate_quantity(dilate_quantity(embed_quantity(y), -np.log(a_mul)), add)
assert abs(decode_quantity(psi) - (a_mul * y + add)) < 1e-6
# --- Fail-closed on non-finite input --------------------------------------
@pytest.mark.parametrize("bad", [np.inf, -np.inf, np.nan])
def test_embedding_refuses_non_finite(bad: float) -> None:
with pytest.raises(QuantityKernelError):
embed_quantity(bad)
def test_translate_refuses_non_finite_shift() -> None:
with pytest.raises(QuantityKernelError):
translate_quantity(embed_quantity(1.0), np.nan)
def test_decode_refuses_degenerate_weight() -> None:
# A point with zero conformal weight cannot be projectively decoded.
psi = np.zeros(cl.N_COMPONENTS, dtype=np.float64)
psi[1] = 1.0 # e1 only: weight (e5c - e4c) = 0
with pytest.raises(QuantityKernelError):
decode_quantity(psi)
# --- Tier-2 cross-hardware reproducibility canary (golden bytes) ----------
# SHA-256 of embed_quantity(3.0).astype("<f8").tobytes(). Frozen from the first
# green run; a change means the substrate math or dtype drifted (spike §4.6).
_GOLDEN_EMBED_3 = "be50e6f65ebe0e528055912aaaa3ddc2af3eb363e00cdccc711aa26c32548719"
def test_embedding_golden_bytes_are_stable() -> None:
digest = hashlib.sha256(embed_quantity(3.0).astype("<f8").tobytes()).hexdigest()
assert digest == _GOLDEN_EMBED_3, f"substrate drift: got {digest}"