core/core/physics/wave_manifold.py
Shay e7d116c924 feat(physics,cognition): Cl(4,1) geometric sovereignty convergence
Excise identity L2 dual-mode and pipeline PASSTHROUGH cold-starts; enforce
wave-only IdentityCheck with MissingWaveStateError; hard-fail GoldTether
transitions via GoldTetherViolationError; dual-competing Shadow Coherence
Gate with populated contract_assessment; auto-compile field packets before
intent ratify; conformal argmax ratification and content-addressed proof
atoms; sandwich multi-modality ingress with GoldTether digests.

Amend ADR-0243/0244 (docs/adr + research) for wave-only / SUPERSEDED sketches.
Pin binary gates in tests/test_geometric_convergence_checklist.py.

[Verification]: Smoke suite passed locally (~136–142s, 176 passed);
cognition suite passed (122 passed, 1 skipped); lifecycle suite 51 passed.
2026-07-20 12:20:05 -07:00

471 lines
18 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
core/physics/wave_manifold.py
Wave-field substrate for Cl(4,1) (ADR-0241).
Continuous multivector wave fields ψ ∈ ℝ³² under:
* sandwich transport ψ' = R ψ ~R (multivector field path; matches versor_apply)
* left spinor transport ψ' = R ψ (odd-capable / chiral path)
* spectral leakage (metric proj onto resonant modes)
* wave polar analogy (sandwich conjugator)
* unitary amplitude residual + chiral spinor charge readout
Algebra-native only (algebra/*). No scipy-as-truth. No teaching/vault imports.
Off-serving until explicit gates; dual-checked unitary residual.
**Backend dispatch (P11a / ADR-0235):** Cl(4,1) hot ops go through
``algebra.backend`` so ``CORE_BACKEND=rust`` can accelerate them when
``core_rs`` is built. Python remains semantic source of truth when Rust
is unset. Helpers without a Rust path (``reverse``, ``scalar_part``,
``versor_unit_residual``) stay on pure algebra modules.
"""
from __future__ import annotations
import hashlib
from typing import Any, Sequence, Tuple
import numpy as np
from algebra.backend import (
cga_inner,
geometric_product,
versor_apply,
versor_condition,
)
from algebra.cl41 import N_COMPONENTS, reverse, scalar_part
from algebra.versor import versor_unit_residual
_CLOSURE_TOL = 1e-6
_NEAR_ZERO = 1e-12
_NONSIMPLE_TOL = 1e-6
def multivector_content_digest(psi: np.ndarray) -> str:
"""Full 64-char SHA-256 of little-endian float64 multivector components.
Canonical content address for Cl(4,1) wave state (Reconstruction-over-Storage).
"""
arr = np.ascontiguousarray(np.asarray(psi, dtype=np.float64))
if arr.shape != (N_COMPONENTS,):
raise ValueError(
f"content digest requires shape ({N_COMPONENTS},); got {arr.shape}"
)
if not np.all(np.isfinite(arr)):
raise ValueError("content digest requires finite multivector components")
le = arr.astype(np.dtype("<f8"), copy=False)
return hashlib.sha256(le.tobytes()).hexdigest()
class WaveSpectralLeakageError(ValueError):
"""Fail-closed spectral leakage (metric-degenerate resonant span).
Mapped to :class:`core.physics.surprise.SurpriseResidualError` at the
surprise boundary so discovery / dual contracts keep a stable error type.
"""
def __init__(self, reason: str, **disclosure: Any) -> None:
self.reason = reason
self.disclosure = dict(disclosure)
super().__init__(f"spectral_leakage refused [{reason}]: {self.disclosure}")
# Unit pseudoscalar I₅ = e1 e2 e3 e4 e5 (central; I² = 1 in Cl(4,1)).
_I5 = np.zeros(N_COMPONENTS, dtype=np.float64)
_I5[31] = 1.0
_I5.setflags(write=False)
def _as_mv(x: np.ndarray, name: str = "ψ") -> np.ndarray:
arr = np.asarray(x, dtype=np.float64)
if arr.shape != (N_COMPONENTS,):
raise ValueError(f"{name} must have shape ({N_COMPONENTS},); got {arr.shape}")
return arr
def _identity() -> np.ndarray:
out = np.zeros(N_COMPONENTS, dtype=np.float64)
out[0] = 1.0
return out
def _strict_close_rotor(V: np.ndarray, *, name: str) -> np.ndarray:
"""Rescale a true versor to unit weight; never seed-fabricate."""
arr = _as_mv(V, name)
product = geometric_product(arr, reverse(arr)).astype(np.float64)
scalar_sq = float(product[0])
residue = product.copy()
residue[0] = 0.0
residue_norm = float(np.linalg.norm(residue))
if residue_norm >= 1e-2 or scalar_sq <= 0.0:
raise ValueError(
f"{name}: input not a versor "
f"(residue_norm={residue_norm:.3e}, scalar_sq={scalar_sq:.3e})"
)
closed = (arr * (1.0 / np.sqrt(scalar_sq))).astype(np.float64)
cond = versor_condition(closed)
if cond >= _CLOSURE_TOL:
raise ValueError(f"{name}: versor_condition={cond:.3e} after close")
return closed
def _require_closed_rotor(R: np.ndarray, *, name: str = "R") -> np.ndarray:
arr = _as_mv(R, name)
cond = versor_condition(arr)
if cond >= _CLOSURE_TOL:
# Attempt strict close only if already a versor (scalar reverse product).
return _strict_close_rotor(arr, name=name)
return arr.astype(np.float64, copy=True)
def _exp_bivector_generator(B: np.ndarray, dt: float) -> np.ndarray:
"""R = exp(B·dt) for a pure (or nearly pure) bivector generator.
Closed form when B² is scalar (simple plane); series fallback otherwise.
Result is construction-closed (versor_condition < 1e-6).
"""
G = _as_mv(B, "B") * float(dt)
G = G.copy()
G[0] = 0.0 # generator is grade ≥ 1; scalar part does not enter exp path
if float(np.linalg.norm(G)) < _NEAR_ZERO:
return _identity()
Gsq = geometric_product(G, G).astype(np.float64)
s = float(Gsq[0])
higher = Gsq.copy()
higher[0] = 0.0
if float(np.linalg.norm(higher)) < _NONSIMPLE_TOL:
out = np.zeros(N_COMPONENTS, dtype=np.float64)
if abs(s) < _NEAR_ZERO:
out[0] = 1.0
out = out + G
elif s < 0.0:
mag = float(np.sqrt(-s))
out[0] = float(np.cos(mag))
out = out + (float(np.sin(mag)) / mag) * G
else:
mag = float(np.sqrt(s))
out[0] = float(np.cosh(mag))
out = out + (float(np.sinh(mag)) / mag) * G
return _strict_close_rotor(out, name="exp_bivector")
# Non-simple: truncated geometric series (construction boundary only).
term = _identity()
out = term.copy()
for k in range(1, 48):
term = geometric_product(term, G) / float(k)
out = out + term
if float(np.linalg.norm(term)) < 1e-18:
break
return _strict_close_rotor(out, name="exp_bivector_series")
def _metric_project(
x: np.ndarray,
modes: Sequence[np.ndarray],
) -> Tuple[np.ndarray, np.ndarray]:
"""Metric-orthogonal projection onto span(modes) under cga_inner.
Solves G c = r with G_ij = ⟨b_i, b_j⟩, r_i = ⟨b_i, x⟩. Returns
(projection, residual) with residual = x projection.
"""
x_arr = _as_mv(x, "ψ_incoming")
cols = [_as_mv(m, f"mode[{i}]") for i, m in enumerate(modes)]
k = len(cols)
if k == 0:
return np.zeros(N_COMPONENTS, dtype=np.float64), x_arr.copy()
gram = np.array(
[[cga_inner(cols[i], cols[j]) for j in range(k)] for i in range(k)],
dtype=np.float64,
)
rhs = np.array([cga_inner(cols[i], x_arr) for i in range(k)], dtype=np.float64)
# Fail-closed on metric-degenerate span (null direction with no reciprocal).
Bmat = np.column_stack(cols)
rank_b = int(np.linalg.matrix_rank(Bmat))
rank_g = int(np.linalg.matrix_rank(gram))
if rank_g < rank_b:
_u, _sv, vh = np.linalg.svd(gram)
degenerate_combo = [round(float(v), 6) for v in vh[-1]]
null_columns = [
i for i in range(k) if abs(float(gram[i, i])) < _NEAR_ZERO
]
raise WaveSpectralLeakageError(
"degenerate_metric_span",
rank_basis=rank_b,
rank_gram=rank_g,
null_columns=null_columns,
degenerate_combo=degenerate_combo,
)
coeffs, *_ = np.linalg.lstsq(gram, rhs, rcond=None)
projection = np.zeros(N_COMPONENTS, dtype=np.float64)
for c, col in zip(coeffs, cols):
projection = projection + float(c) * col
residual = x_arr - projection
return projection, residual
class WaveManifold:
"""Continuous wave propagation + resonant measures over Cl(4,1) fields.
Construction-closed rotors; dual-checked unitary residual; deterministic.
Optional standing-wave mode registry for resonant recall (ADR-0241 §2.2);
not a vault/store — reconstruction-over-storage, off-serving.
Stored modes are content-addressed by SHA-256 over little-endian float64
multivector bytes (:func:`multivector_content_digest`).
"""
def __init__(self, epsilon_drift: float = 1e-6) -> None:
self.epsilon_drift = float(epsilon_drift)
self.n_dims = N_COMPONENTS
# Standing-wave eigenmode registry (session-local; not durable memory).
# Each entry is (digest, psi) so storage is content-addressed.
self._resonant_modes: list[tuple[str, np.ndarray]] = []
@staticmethod
def content_digest(psi: np.ndarray) -> str:
"""SHA-256 hex digest of a Cl(4,1) multivector (little-endian f64)."""
return multivector_content_digest(psi)
# --- Transport -----------------------------------------------------------
def sandwich_step(self, psi: np.ndarray, R: np.ndarray) -> np.ndarray:
"""Multivector field path: ψ' = R ψ ~R (matches :func:`versor_apply`)."""
psi_arr = _as_mv(psi, "ψ")
R_arr = _require_closed_rotor(R, name="R")
return versor_apply(R_arr, psi_arr).astype(np.float64)
def left_spinor_step(self, psi: np.ndarray, R: np.ndarray) -> np.ndarray:
"""Spinor / chiral path: ψ' = R ψ (left geometric product)."""
psi_arr = _as_mv(psi, "ψ")
R_arr = _require_closed_rotor(R, name="R")
return geometric_product(R_arr, psi_arr).astype(np.float64)
def algebraic_schrodinger_step(
self,
psi: np.ndarray,
H_operator: np.ndarray,
dt: float,
) -> np.ndarray:
"""Unitary step via R = exp(B·dt), sandwich on multivector fields.
``H_operator`` is the bivector generator B (32-vector). Default field
law is sandwich so even field-state versors stay closed under the step.
"""
psi_arr = _as_mv(psi, "ψ")
R = _exp_bivector_generator(H_operator, dt)
return self.sandwich_step(psi_arr, R)
# --- Unitary residual (GoldTether wave form) -----------------------------
def measure_unitary_residual(self, psi: np.ndarray) -> float:
"""Dual-checked amplitude drift: max(‖ψ ψ̃ 1‖, ‖~ψ ψ 1‖ proxy).
Uses :func:`versor_unit_residual` on ψ and reverse(ψ).
"""
psi_arr = _as_mv(psi, "ψ")
r = float(versor_unit_residual(psi_arr))
r_rev = float(versor_unit_residual(reverse(psi_arr)))
return max(r, r_rev)
# --- Spectral leakage (surprise) -----------------------------------------
def compute_spectral_leakage(
self,
psi_incoming: np.ndarray,
resonant_modes: Sequence[np.ndarray],
) -> Tuple[np.ndarray, float]:
"""Non-resonant spectral leakage: residual after metric proj onto modes.
Returns ``(surprise_vector, energy)`` with energy = Euclidean ‖residual‖
(definite readout after metric-exact projection; same doctrine as
surprise_residual magnitude).
"""
_proj, residual = _metric_project(psi_incoming, list(resonant_modes))
energy = float(np.linalg.norm(residual))
return residual.astype(np.float64), energy
# --- Wave polar analogy (Procrustes upgrade) -----------------------------
def wave_analogical_polar(
self,
psi_A: np.ndarray,
psi_B: np.ndarray,
) -> np.ndarray:
"""Recover sandwich conjugator R with psi_B ≈ R psi_A ~R.
Canonical single-field analogy rotor via field conjugacy (SVD + Spin GN).
Analytic Clifford polar R = C (~C C)^{-1/2} is **not** used: for
multi-grade Cl(4,1) fields ~C C is non-scalar (ADR-0241 P7 demotion;
``docs/briefs/P7_design_note.md``).
"""
R, _residual = self.wave_field_conjugacy([psi_A], [psi_B])
return R
def wave_field_conjugacy(
self,
sources: Sequence[np.ndarray],
targets: Sequence[np.ndarray],
) -> Tuple[np.ndarray, float]:
"""Multi-pair sandwich conjugacy (thin wrap over stacked field engine).
Canonical multi-field path for Procrustes (ADR-0241 Slice 3). Returns
``(R, residual)`` where residual is the mean raw-sandwich residual from
the conjugacy engine (callers may recompute pair residuals).
"""
# Lazy import: dynamic_manifold may call WaveManifold at runtime.
from core.physics.dynamic_manifold import _field_conjugacy_versor
src = [_as_mv(s, f"source[{i}]") for i, s in enumerate(sources)]
tgt = [_as_mv(t, f"target[{i}]") for i, t in enumerate(targets)]
if len(src) != len(tgt) or not src:
raise ValueError("wave_field_conjugacy: non-empty equal-length pairs required")
R, residual = _field_conjugacy_versor(src, tgt)
return _require_closed_rotor(R, name="R_conjugacy"), float(residual)
# --- Standing-wave registry / resonant recall (ADR-0241 §2.2) ------------
def register_resonant_mode(self, psi_k: np.ndarray) -> int:
"""Register a standing-wave mode. Returns mode index. Session-local only.
Content-addressed by SHA-256 of little-endian float64 components.
"""
mode = _as_mv(psi_k, "ψ_k").copy()
digest = multivector_content_digest(mode)
self._resonant_modes.append((digest, mode))
return len(self._resonant_modes) - 1
def clear_resonant_modes(self) -> None:
"""Drop all registered modes (tests / session reset)."""
self._resonant_modes.clear()
@property
def resonant_modes(self) -> tuple[np.ndarray, ...]:
return tuple(m.copy() for _d, m in self._resonant_modes)
@property
def resonant_mode_digests(self) -> tuple[str, ...]:
"""SHA-256 digests parallel to :attr:`resonant_modes`."""
return tuple(d for d, _m in self._resonant_modes)
def resonant_recall(
self,
psi_query: np.ndarray,
*,
modes: Sequence[np.ndarray] | None = None,
) -> Tuple[np.ndarray, float, int]:
"""Holographic resonant lock-in: max constructive overlap with modes.
Overlap uses the scalar part of ``ψ_q · ~ψ_k`` (algebraic inner structure
via reverse product — not cosine/ANN). Returns
``(best_mode, resonance_energy, index)``.
Empty mode set raises ``ValueError`` (no confabulated recall).
"""
query = _as_mv(psi_query, "ψ_query")
mode_list = self._resolve_modes(modes)
if not mode_list:
raise ValueError("resonant_recall: empty mode set (no confabulated recall)")
best_i = 0
best_E = -1.0
for i, mode in enumerate(mode_list):
# Resonance energy: |⟨ψ_q ~ψ_k⟩_0| — constructive phase lock magnitude.
prod = geometric_product(query, reverse(mode))
energy = abs(float(scalar_part(prod)))
if energy > best_E:
best_E = energy
best_i = i
return mode_list[best_i].copy(), float(best_E), int(best_i)
def resonant_reconstruct(
self,
psi_query: np.ndarray,
*,
modes: Sequence[np.ndarray] | None = None,
) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
"""Superposition reconstruction ψ̂ = Σ_k c_k ψ_k.
Coefficients c_k are reverse-product scalar overlaps
⟨ψ_q ~ψ_k⟩_0, L1-normalized when the total absolute mass is nonzero.
Reconstruction-over-storage via interference weights — not cosine
similarity and not argmax-only lock-in (use :meth:`resonant_recall`
for hard mode selection).
Returns ``(psi_hat, coeffs, energies)``. Empty mode set raises
``ValueError`` (no confabulation).
"""
query = _as_mv(psi_query, "ψ_query")
mode_list = self._resolve_modes(modes)
if not mode_list:
raise ValueError(
"resonant_reconstruct: empty mode set (no confabulated recall)"
)
energies = np.array(
[
float(scalar_part(geometric_product(query, reverse(m))))
for m in mode_list
],
dtype=np.float64,
)
mass = float(np.sum(np.abs(energies)))
if mass < _NEAR_ZERO:
coeffs = np.zeros(len(mode_list), dtype=np.float64)
# Uniform refuse-to-invent: zero reconstruction when no overlap.
psi_hat = np.zeros(N_COMPONENTS, dtype=np.float64)
return psi_hat, coeffs, energies
coeffs = energies / mass
psi_hat = np.zeros(N_COMPONENTS, dtype=np.float64)
for c, mode in zip(coeffs, mode_list):
psi_hat = psi_hat + float(c) * mode
return psi_hat.astype(np.float64), coeffs, energies
def phase_correlation(
self,
psi_A: np.ndarray,
psi_B: np.ndarray,
) -> float:
"""Algebraic multimodal resonance (cohesion I-04).
rho(A,B) = ⟨ψ_A ~ψ_B + ψ_B ~ψ_A⟩_0
Symmetric, deterministic, reverse-product structure. Not cosine/ANN.
"""
a = _as_mv(psi_A, "ψ_A")
b = _as_mv(psi_B, "ψ_B")
ab = geometric_product(a, reverse(b))
ba = geometric_product(b, reverse(a))
return float(scalar_part(ab + ba))
def _resolve_modes(
self,
modes: Sequence[np.ndarray] | None,
) -> list[np.ndarray]:
if modes is None:
return [m.copy() for _d, m in self._resonant_modes]
return [_as_mv(m, f"mode[{i}]") for i, m in enumerate(modes)]
# --- Chiral spinor charge ------------------------------------------------
def chiral_charge(self, psi: np.ndarray) -> float:
"""Topological spinor charge Q = ⟨ψ I₅ ~ψ⟩_0 (ADR-0241 §2.4C).
For strictly even field-states, ⟨I₅ (ψ~ψ)⟩_0 is structurally zero, remaining
honest about the vacuity of the retired #19 gate. However, for odd-capable
spinor packets (mixed parity), ψ~ψ carries a grade-5 component, yielding a
strictly NON-VACUOUS and informative Q that measures the correlation
between the even part and the odd dual part. Q is strictly conserved
under left unitary multiplication by any rotor R.
"""
psi_arr = _as_mv(psi, "ψ")
# ⟨ψ I ~ψ⟩_0 = ⟨I (ψ ~ψ)⟩_0 (I central)
return float(
scalar_part(
geometric_product(
geometric_product(psi_arr, _I5),
reverse(psi_arr),
)
)
)
__all__ = ["WaveManifold", "WaveSpectralLeakageError", "multivector_content_digest"]