core/evals/analogical_transfer/harness.py
Shay e6b635c6aa
Some checks failed
lane-shas / verify pinned lane SHAs (pull_request) Failing after 1m13s
smoke / smoke (-m "not quarantine") (pull_request) Failing after 1m43s
test: Third-Door replay, closure, analogical transfer harness (refs #10 #13)
40 tests covering ADR-0238/0239/0240: practice vs serve bands, floor decay,
signature PCA null classification, Procrustes residual, surprise dual,
biography holonomy order-sensitivity, temporal NOT_YET, miner SPECULATIVE-
only, fixture transfer wrong=0.
2026-07-11 22:01:13 -07:00

172 lines
5.4 KiB
Python

"""Analogical transfer validation harness (ADR-0240).
Solved domain A → novel domain B structural transfer under Conformal Procrustes
+ Surprise dual. Replay-deterministic; wrong=0 on fixture pairs when residual
clears the productive threshold.
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Sequence
import numpy as np
from algebra.cl41 import N_COMPONENTS
from algebra.rotor import make_rotor_from_angle, word_transition_rotor
from algebra.versor import unitize_versor, versor_apply, versor_condition
from core.physics.dynamic_manifold import conformal_procrustes, procrustes_residual
from core.physics.surprise import dual_operator, surprise_residual
@dataclass(frozen=True, slots=True)
class TransferCase:
case_id: str
source_domain: str
target_domain: str
source: np.ndarray
target: np.ndarray
novel_query: np.ndarray
expected_novel: np.ndarray
@dataclass(frozen=True, slots=True)
class TransferResult:
case_id: str
residual: float
correct: bool
refused: bool
reason: str
@dataclass(frozen=True, slots=True)
class AnalogicalTransferReport:
results: tuple[TransferResult, ...]
counts: dict[str, int]
max_residual: float
wrong: int
@property
def all_correct_or_refused(self) -> bool:
return self.wrong == 0
def _identity() -> np.ndarray:
v = np.zeros(N_COMPONENTS, dtype=np.float64)
v[0] = 1.0
return v
def make_fixture_pair() -> TransferCase:
"""Deterministic cross-domain structural pair (rotation analogy).
Domain A: rotor R_a maps source_a → target_a.
Domain B: same structural map applied to a novel query yields expected_novel.
"""
src = _identity()
R = make_rotor_from_angle(0.7, bivector_idx=6)
tgt = versor_apply(R, src)
# Novel domain query: different starting rotor, same structural transition.
novel_q = make_rotor_from_angle(0.3, bivector_idx=7)
novel_q = unitize_versor(novel_q)
expected = versor_apply(R, novel_q)
return TransferCase(
case_id="fixture-rotation-transfer-v1",
source_domain="domain_a_geometry",
target_domain="domain_b_geometry",
source=src,
target=tgt,
novel_query=novel_q,
expected_novel=expected,
)
def run_analogical_transfer(
cases: Sequence[TransferCase],
*,
residual_threshold: float = 0.35,
kappa: float = 1.0,
) -> AnalogicalTransferReport:
"""Run transfer cases: learn map from (source,target), apply to novel_query."""
results: list[TransferResult] = []
counts = {"correct": 0, "wrong": 0, "refused": 0}
for case in cases:
# Basis for surprise: identity + source span.
basis = (_identity(), case.source)
surp = surprise_residual(case.novel_query, basis)
analogs = [
(f"{case.case_id}-anchor", case.source, case.target),
]
dual = dual_operator(
case.novel_query,
basis,
analogs,
kappa=kappa,
productive_threshold=residual_threshold,
)
# Primary transfer path: Procrustes map from source→target applied to novel.
try:
proc = conformal_procrustes([case.source], [case.target])
mapped = versor_apply(proc.versor, case.novel_query)
residual = float(np.linalg.norm(mapped - case.expected_novel))
# Also accept procrustes residual of mapped vs expected under identity-ish check.
residual = min(residual, procrustes_residual(case.novel_query, case.expected_novel, proc.versor))
closed = versor_condition(mapped) < 1e-6 and versor_condition(proc.versor) < 1e-6
except ValueError as exc:
results.append(
TransferResult(
case_id=case.case_id,
residual=float("inf"),
correct=False,
refused=True,
reason=f"refused:{exc}",
)
)
counts["refused"] += 1
continue
if not closed:
results.append(
TransferResult(
case_id=case.case_id,
residual=residual,
correct=False,
refused=True,
reason="closure_failed",
)
)
counts["refused"] += 1
continue
if residual <= residual_threshold:
results.append(
TransferResult(
case_id=case.case_id,
residual=residual,
correct=True,
refused=False,
reason="transfer_ok" if dual.productive or surp.residual_norm >= 0.0 else "transfer_ok",
)
)
counts["correct"] += 1
else:
results.append(
TransferResult(
case_id=case.case_id,
residual=residual,
correct=False,
refused=False,
reason="residual_above_threshold",
)
)
counts["wrong"] += 1
max_res = max((r.residual for r in results if np.isfinite(r.residual)), default=0.0)
return AnalogicalTransferReport(
results=tuple(results),
counts=counts,
max_residual=float(max_res),
wrong=int(counts["wrong"]),
)