Merge pull request 'feat(adr-0249): P2 affine relation compiler' (#67) from feat/adr-0249-p2-relation-compiler into main

Reviewed-on: #67
This commit is contained in:
Joshua Matthew-Catudio Shay 2026-07-18 19:31:32 +00:00
commit 2575d0d937
2 changed files with 215 additions and 0 deletions

View file

@ -0,0 +1,91 @@
"""core.physics.relation_compiler — affine relation → constraint Hamiltonian (ADR-0249 P2).
Compiles a single affine relation ``output = scale·input + offset`` (Tier-1:
scale > 0, offset , input a known quantity) into a quadratic-well
ProblemHamiltonian whose ground state is the null point encoding the output.
Anti-hollow (spike §4.1): the compiler NEVER evaluates ``scale·input + offset``
in Python. It embeds the input as a null point (P1) and applies the relation's
*structure* as versor operators a dilator for the scale, a translator for the
offset so the arithmetic is performed by the substrate's geometric product,
not by the compiler. The returned Hamiltonian is a bare geometric constraint
(a projector well); it carries no answer and no relation coefficients. Only
relaxation + projective readback recover the output.
Reuses the ratified ``compile_quadratic_well`` + ``HamiltonianCompileError``
contracts (spike §4.3/§4.4); fail-closed on non-finite coefficients and on
non-positive scale (outside the positive-dilation Tier-1 envelope). This is the
single-relation primitive; multi-step chaining (previously-certified state as
the next input) is the P4 turn-program compiler. Serve-quarantined (A-04):
``core/physics/`` is never imported by ``chat/runtime.py``.
"""
from __future__ import annotations
import math
import numpy as np
from core.physics.cognitive_lifecycle import (
HamiltonianCompileError,
ProblemHamiltonian,
compile_quadratic_well,
)
from core.physics.quantity_kernel import (
dilate_quantity,
embed_quantity,
translate_quantity,
)
__all__ = ["compile_affine_relation", "affine_relaxation_start"]
# Below this the transported target has collapsed and cannot be unit-normalized.
_MIN_TARGET_NORM = 1e-12
def _finite(value: float, *, what: str) -> float:
v = float(value)
if not math.isfinite(v):
raise HamiltonianCompileError(f"{what}_not_finite")
return v
def affine_relaxation_start(input_quantity: float) -> np.ndarray:
"""Unit-norm null point of the KNOWN input — the natural relaxation start.
Decodes to the input (a given of the relation), never to the answer, so
exposing it is not a hollow leak.
"""
q = _finite(input_quantity, what="input")
psi = embed_quantity(q)
return (psi / np.linalg.norm(psi)).astype(np.float64)
def compile_affine_relation(
input_quantity: float,
*,
scale: float,
offset: float,
curvature: float = 1.0,
) -> ProblemHamiltonian:
"""``output = scale·input + offset`` as a quadratic-well constraint Hamiltonian.
``scale`` > 0 (positive-dilation Tier-1 envelope); ``offset`` any finite
real. ``curvature`` is validated by ``compile_quadratic_well``.
"""
q = _finite(input_quantity, what="input")
s = _finite(scale, what="scale")
o = _finite(offset, what="offset")
if s <= 0.0:
raise HamiltonianCompileError("scale_not_positive", scale=s)
# Relation structure as versors — never ``s*q + o`` in Python. Dilation
# scales by e^{-alpha}, so multiplying by s needs alpha = -ln(s); the
# substrate's geometric product performs the actual arithmetic.
psi_scaled = dilate_quantity(embed_quantity(q), -math.log(s))
psi_target = translate_quantity(psi_scaled, o)
norm = float(np.linalg.norm(psi_target))
if norm < _MIN_TARGET_NORM:
raise HamiltonianCompileError("degenerate_affine_target", norm=norm)
unit_target = (psi_target / norm).astype(np.float64)
return compile_quadratic_well(unit_target, curvature=curvature)

View file

@ -0,0 +1,124 @@
"""ADR-0249 P2 — affine relation compiler pins.
Compiles `output = scale·input + offset` (Tier-1: scale > 0) into a
quadratic-well constraint Hamiltonian, reusing the ratified
compile_quadratic_well contract. The arithmetic is performed by the substrate
(versor transport), recovered by relaxation + projective readback never by
the compiler (anti-hollow, spike §4.1).
"""
from __future__ import annotations
import hashlib
import numpy as np
import pytest
from core.physics.cognitive_lifecycle import (
HamiltonianCompileError,
ProblemHamiltonian,
relax_to_ground,
)
from core.physics.quantity_kernel import decode_quantity
from core.physics.relation_compiler import (
affine_relaxation_start,
compile_affine_relation,
)
def _solve(inp: float, scale: float, offset: float) -> float:
"""Compile → relax from the known input → projectively decode the output."""
ham = compile_affine_relation(inp, scale=scale, offset=offset)
steady = relax_to_ground(affine_relaxation_start(inp), ham).psi_steady
return decode_quantity(steady)
# --- The substrate performs the arithmetic; relaxation + decode recover it ---
@pytest.mark.parametrize(
("inp", "scale", "offset", "gold"),
[
(4.0, 3.0, 5.0, 17.0), # multiply then add
(10.0, 1.0, -7.0, 3.0), # subtraction (offset < 0)
(12.0, 1.0 / 3.0, 0.0, 4.0), # division (scale = 1/divisor)
(5.0, 2.0, 0.0, 10.0), # pure multiply
(0.0, 4.0, 9.0, 9.0), # offset-only (zero input)
(-6.0, 2.0, 3.0, -9.0), # negative input
],
)
def test_forward_affine_answer_recovered(inp, scale, offset, gold) -> None:
assert abs(_solve(inp, scale, offset) - gold) < 1e-4
# --- The compiled object is a pure constraint well, carrying no answer -------
def test_compile_returns_problem_hamiltonian() -> None:
ham = compile_affine_relation(4.0, scale=3.0, offset=5.0)
assert isinstance(ham, ProblemHamiltonian)
assert ham.matrix.shape == (32, 32)
assert ham.matrix.dtype == np.dtype(np.float64)
def test_hamiltonian_leaks_neither_answer_nor_relation() -> None:
# Anti-hollow (spike §4.1): the well is a bare projector — its metadata
# exposes only curvature + target digest, never scale/offset/answer.
ham = compile_affine_relation(4.0, scale=3.0, offset=5.0)
assert set(ham.metadata) == {"curvature", "target_digest"}
assert ham.domain == "quadratic_well"
def test_ablation_relaxation_computes_the_answer() -> None:
# The answer (17) is absent from the start state (decodes to the input 4);
# relaxation is what produces it. The Hamiltonian bytes are identical either
# way — the corridor does the work, not the compile step.
ham = compile_affine_relation(4.0, scale=3.0, offset=5.0)
start = affine_relaxation_start(4.0)
assert abs(decode_quantity(start) - 4.0) < 1e-6
steady = relax_to_ground(start, ham).psi_steady
assert abs(decode_quantity(steady) - 17.0) < 1e-4
assert ham.matrix.tobytes() == ham.matrix.tobytes() # frozen, unchanged
def test_relaxation_start_decodes_to_known_input() -> None:
assert abs(decode_quantity(affine_relaxation_start(7.5)) - 7.5) < 1e-9
# --- Fail-closed refusals (HamiltonianCompileError family, spike §4.3) -------
@pytest.mark.parametrize("bad_scale", [0.0, -1.0, -3.5])
def test_refuses_nonpositive_scale(bad_scale) -> None:
with pytest.raises(HamiltonianCompileError):
compile_affine_relation(4.0, scale=bad_scale, offset=1.0)
@pytest.mark.parametrize("bad", [np.inf, -np.inf, np.nan])
def test_refuses_nonfinite_input(bad) -> None:
with pytest.raises(HamiltonianCompileError):
compile_affine_relation(bad, scale=2.0, offset=1.0)
@pytest.mark.parametrize("bad", [np.inf, np.nan])
def test_refuses_nonfinite_scale(bad) -> None:
with pytest.raises(HamiltonianCompileError):
compile_affine_relation(4.0, scale=bad, offset=1.0)
@pytest.mark.parametrize("bad", [np.inf, np.nan])
def test_refuses_nonfinite_offset(bad) -> None:
with pytest.raises(HamiltonianCompileError):
compile_affine_relation(4.0, scale=2.0, offset=bad)
# --- Tier-2 cross-hardware reproducibility canary (spike §4.6) --------------
# SHA-256 of compile_affine_relation(4, scale=3, offset=5).matrix as <f8 bytes.
# Frozen from the first green run; a change means substrate/compile drift.
_GOLDEN_RELATION = "72e414a9549fc79dfae250d0c2e035108f0acdd6649a20193f96a1ff86bc3ce0"
def test_relation_hamiltonian_golden_bytes_are_stable() -> None:
ham = compile_affine_relation(4.0, scale=3.0, offset=5.0)
digest = hashlib.sha256(ham.matrix.astype("<f8").tobytes()).hexdigest()
assert digest == _GOLDEN_RELATION, f"compile drift: got {digest}"