#!/usr/bin/env python3
"""
verify_P029.py -- Paper 29: training/exposure distinction.

This verifier checks the direct loss-landscape and TOE-identity arithmetic,
then records theorem-scope issues where the text needs stronger assumptions
than it states.
"""

from __future__ import annotations

import math
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent))
from verify_common import CheckResult, Verifier


class _ModernVerifier(Verifier):
    """Local adapter: identical tolerance logic, modern output format."""

    def __init__(self, name: str):
        self.name = name
        self.results = []
        print(name)

    def record(self, label, ok, computed="", claimed="", detail=""):
        self.results.append(CheckResult(label, ok, computed, claimed, detail))
        n = len(self.results)
        desc, info = label, detail
        i = detail.find("Expected")
        if i >= 0:
            desc = f"{label} -- {detail[i:]}"
            info = detail[:i].rstrip().rstrip(";")
        print(f"  [{'PASS' if ok else 'FAIL'}] {n:>2}. {desc}")
        if computed != "" or claimed != "":
            print(f"        computed: {computed}")
            print(f"        claimed : {claimed}")
        if info:
            print(f"        {info}")
        return bool(ok)

    def summary(self) -> int:
        passed = sum(bool(r.ok) for r in self.results)
        failed = len(self.results) - passed
        print(f"\n{'='*60}\nRESULT: {passed} PASS / {failed} FAIL")
        return 1 if failed else 0


v = _ModernVerifier("P029 -- Training Exposure")

ROOT = Path(__file__).resolve().parents[2]
TEX = (ROOT / "toe" / "29_Paper_TrainingExposure.tex").read_text()

PI = math.pi


def rel_percent(value: float, target: float) -> float:
    return 100.0 * (value - target) / abs(target)


def linear_loss(theta: float) -> float:
    """Population loss for f_theta(x)=theta*x, f*(x)=x, x uniform on [-1,1]."""
    return (theta - 1.0) ** 2 / 3.0


def resonance_amplitude(omega: float, omega0: float, gamma: float, force: float = 1.0) -> float:
    return force / math.sqrt((omega0**2 - omega**2) ** 2 + gamma**2 * omega**2)


v.record("TeX source is present", "Geometric Exactness" in TEX and "Training" in TEX)

# Zero-loss and Hessian checks on a concrete exact graph.
theta_star = 1.0
v.check("zero loss at exact parameter", linear_loss(theta_star), 0.0, abs_tol=1e-15)
v.check("gradient at exact parameter", 2.0 * (theta_star - 1.0) / 3.0, 0.0, abs_tol=1e-15)
v.check("positive Hessian in scalar full-support model", 2.0 / 3.0, 2.0 / 3.0, rel=1e-15)
v.record(
    "nearby nonzero perturbation gives positive loss under full support",
    linear_loss(1.1) > 0.0,
    computed=linear_loss(1.1),
    claimed="positive",
)
eta = 0.37
theta_next = theta_star - eta * (2.0 * (theta_star - 1.0) / 3.0)
v.check("exact gradient descent from theta* stays fixed", theta_next, theta_star, abs_tol=1e-15)

# TOE identity arithmetic.
beta = 0.37
phi_plus = 0.23
phi_minus = 1.10
a = math.cos(beta) * math.cos(phi_plus)
b = math.cos(beta) * math.sin(phi_plus)
c = math.sin(beta) * math.cos(phi_minus)
d = math.sin(beta) * math.sin(phi_minus)
hopf_v = (a * a + b * b) - (c * c + d * d)
v.check("Hopf polynomial equals cos(2 beta)", hopf_v, math.cos(2.0 * beta), rel=1e-14)
v.check("Lorentz lapse example", math.sqrt(1.0 - 0.6**2), 0.8, rel=1e-14)
n_parallel = 0.3
eta_axis = 1.2
axis_v = n_parallel**2 + (1.0 - n_parallel**2) * math.cos(eta_axis)
v.record(
    "axis-resolved formula stays in velocity range for sample input",
    -1.0 <= axis_v <= 1.0,
    computed=axis_v,
    claimed="in [-1, 1]",
)
v.check("Omega0 from V6/V3 normalization", 2.0 * PI * (PI**2 / 8.0), PI**3 / 4.0, rel=1e-15)
v.check("monad closure alpha inverse arithmetic", 4.0 * PI**3 + PI**2 + PI, 137.036304, rel=3e-9)

# Resonance formula: the stated amplitude is standard, but its peak is not
# exactly at omega0 for the written damped displacement response.
omega0 = 2.0
gamma = 1.0
omega_peak = math.sqrt(omega0**2 - gamma**2 / 2.0)
v.check(
    "resonance amplitude at omega0",
    resonance_amplitude(omega0, omega0, gamma),
    1.0 / (gamma * omega0),
    rel=1e-15,
)
v.record(
    "damped displacement response peaks exactly at omega0",
    False,
    computed=f"omega_peak={omega_peak:.12f}, A(omega_peak)={resonance_amplitude(omega_peak, omega0, gamma):.12f}, A(omega0)={resonance_amplitude(omega0, omega0, gamma):.12f}",
    claimed="peak at omega=omega0",
    detail="Expected fail: differentiating the displayed denominator gives omega_peak=sqrt(omega0^2-gamma^2/2) for gamma>0.",
)

# Theorem-scope checks.
v.record(
    "local injectivity alone implies positive population loss for arbitrary mu",
    False,
    computed="Counterexample: f_theta(x)=theta*x on X=[0,1] is locally injective as a function map, but if mu is a point mass at x=0 then L(theta)=0 for every theta.",
    claimed="existence of one mismatching x gives L(theta*+delta)>0",
    detail="Expected fail: the theorem needs full-support/positive-measure or continuity assumptions.",
)
v.record(
    "local isolation implies unique isolated global minimum",
    False,
    computed="Counterexample: f_theta(x)=(theta-2)^2*x, f*(x)=x has zero loss at theta=1 and theta=3, while the map is locally injective near theta=1.",
    claimed="the architecture sits at an isolated global minimum",
    detail="Expected fail: the stated hypotheses support a strict local minimum, not global uniqueness.",
)
v.record(
    "necessary and sufficient conditions are established",
    False,
    computed="the paper gives useful sufficient conditions: exact implementation, local injectivity, and support/rank assumptions; it does not prove necessity for all exact computational graphs",
    claimed="necessary and sufficient conditions",
    detail="Expected theorem-scope fail.",
)
v.record(
    "all catalogued TOE identities are independently established in P29",
    False,
    computed="P29 imports the identity catalogue and empirical RMSE claims from earlier papers; P28/P27 proof-status issues are not re-derived here",
    claimed="identities established as exact theorems and verified empirically in Paper 27",
    detail="Expected dependency/proof-status fail.",
)
v.record(
    "zero free parameters in operational pipeline",
    False,
    computed="the constants are fixed, but q0^(±) and generator schedules Omega^(±)(t) are still external input functions/degrees of freedom",
    claimed="complete computational pipeline contains zero free parameters",
    detail="Expected wording fail: zero trainable constants is narrower than zero operational degrees of freedom.",
)
v.record(
    "regularization or noise generically prevents convergence",
    False,
    computed="some regularizers preserve the exact value, e.g. adding lambda*(theta-1)^2 to the scalar exact model; stochastic noise can also converge in expectation under decreasing step sizes",
    claimed="training with regularization or noise generically prevents convergence to theta*",
    detail="Expected overbreadth fail.",
)
v.record(
    "single instance is sufficient for exposure in general",
    False,
    computed="a single input suffices to evaluate a known identity at that input, but not to identify, validate, or calibrate the input interface/generator schedules",
    claimed="data requirement: single instance suffices",
    detail="Expected scope fail.",
)

sys.exit(v.summary())
