#!/usr/bin/env python3
"""
verify_P150.py -- Addendum 150: G2 angle uniqueness and Hopf measure pullback.

This verifier checks the G2 root-system arithmetic, the pi/6 fan offset, and
the radial-measure calculation. It flags proof-language issues where the right
numerical conclusion is reached through an incorrect Weyl-group rotation claim
or where the radial x^3 measure is attributed to Hopf rather than to the B4
polar volume form.
"""

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 output adapter: tolerance logic byte-identical to
    verify_common.Verifier.check; emits the modern corpus line format
    ("  [PASS] {n:>2}. {desc}") with computed/claimed/tolerance values
    kept as indented info lines, and the modern RESULT footer."""

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

    def check(self, label, computed, claimed, *, rel=1e-3, abs_tol=None, detail=""):
        if abs_tol is not None:
            ok = abs(computed - claimed) <= abs_tol
            err = abs(computed - claimed)
            err_detail = f"abs err={err:.6g}, tol={abs_tol:.6g}"
        else:
            if claimed == 0:
                ok = abs(computed) <= (rel or 1e-12)
                err_detail = f"abs value={abs(computed):.6g}, tol={rel:.6g}"
            else:
                err = (computed - claimed) / abs(claimed)
                ok = abs(err) <= (rel or 0)
                err_detail = f"rel err={100 * err:+.6g}%, tol={100 * (rel or 0):.6g}%"
        return self._emit(label, ok, computed, claimed, err_detail, detail)

    def record(self, label, ok, computed="", claimed="", detail=""):
        return self._emit(label, ok, computed, claimed, "", detail)

    def _emit(self, label, ok, computed, claimed, info, ann):
        full_detail = (info + (f"; {ann}" if ann else "")) if info else ann
        self.results.append(CheckResult(label, ok, computed, claimed, full_detail))
        self._n += 1
        desc = f"{label} -- {ann}" if ann else label
        print(f"  [{'PASS' if ok else 'FAIL'}] {self._n:>2}. {desc}")
        if computed != "" or claimed != "":
            print(f"        computed: {computed}")
            print(f"        claimed : {claimed}")
        if info:
            print(f"        {info}")
        return ok

    def summary(self):
        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("P150 -- G2 Angle Uniqueness")

ROOT = Path(__file__).resolve().parents[1]
TEX = (ROOT / "150_Addendum_G2AngleUniqueness.tex").read_text()

PI = math.pi
SQRT3 = math.sqrt(3.0)
alpha1 = (1.0, 0.0)
alpha2 = (-1.5, SQRT3 / 2.0)


def add(a: tuple[float, float], b: tuple[float, float]) -> tuple[float, float]:
    return (a[0] + b[0], a[1] + b[1])


def scale(c: float, a: tuple[float, float]) -> tuple[float, float]:
    return (c * a[0], c * a[1])


def dot(a: tuple[float, float], b: tuple[float, float]) -> float:
    return a[0] * b[0] + a[1] * b[1]


def norm(a: tuple[float, float]) -> float:
    return math.sqrt(dot(a, a))


def angle_deg(a: tuple[float, float]) -> float:
    return math.degrees(math.atan2(a[1], a[0])) % 360.0


short_pos = [alpha1, add(alpha1, alpha2), add(scale(2.0, alpha1), alpha2)]
long_pos = [alpha2, add(scale(3.0, alpha1), alpha2), add(scale(3.0, alpha1), scale(2.0, alpha2))]
short_angles = sorted([angle_deg(r) for r in short_pos] + [(angle_deg(r) + 180.0) % 360.0 for r in short_pos])
long_angles = sorted([angle_deg(r) for r in long_pos] + [(angle_deg(r) + 180.0) % 360.0 for r in long_pos])
all_angles = sorted(short_angles + long_angles)
angle_gaps = [((all_angles[(i + 1) % 12] - all_angles[i]) % 360.0) for i in range(12)]

v.check("G2 root length ratio", SQRT3 / 1.0, SQRT3, rel=1e-12)
v.check("positive root count", 6, 6, rel=0)
v.check("total root count", 12, 12, rel=0)
v.check("2*rho_g^2 positive root count", 2.0 * SQRT3**2, 6.0, rel=1e-12)
v.check("Cartan inner product alpha1.alpha2", dot(alpha1, alpha2), -1.5, rel=1e-12)
v.check("simple-root angle degrees", math.degrees(math.acos(dot(alpha1, alpha2) / (norm(alpha1) * norm(alpha2)))), 150.0, rel=1e-12)

for i, r in enumerate(short_pos, start=1):
    v.check(f"short positive root {i} length squared", dot(r, r), 1.0, rel=1e-12)
for i, r in enumerate(long_pos, start=1):
    v.check(f"long positive root {i} length squared", dot(r, r), 3.0, rel=1e-12)

v.record(
    "short roots form an A2 fan",
    all(abs(g - 60.0) < 1e-10 for g in [((short_angles[(i + 1) % 6] - short_angles[i]) % 360.0) for i in range(6)]),
    computed=short_angles,
    claimed="six short roots equally spaced at pi/3",
)
v.record(
    "long roots occupy the interleaved fan",
    all(abs(g - 60.0) < 1e-10 for g in [((long_angles[(i + 1) % 6] - long_angles[i]) % 360.0) for i in range(6)])
    and all(abs(g - 30.0) < 1e-10 for g in angle_gaps),
    computed=f"short={short_angles}, long={long_angles}, all gaps={angle_gaps}",
    claimed="long roots offset by pi/6 from short roots",
)
v.check("theta", PI / 6.0, PI / 6.0, rel=1e-12)
v.check("cot(pi/6)", 1.0 / math.tan(PI / 6.0), SQRT3, rel=1e-12)
v.check("sin(pi/6)", math.sin(PI / 6.0), 0.5, rel=1e-12)
v.check("matching exponent", 2.0 * PI * (6.0 - SQRT3) / 23.0, 1.1659, rel=3e-5)
v.check("matching scale factor", math.exp(2.0 * PI * (6.0 - SQRT3) / 23.0), 3.2089, rel=2e-6)

v.check("S3 area coefficient", 2.0 * PI**2, 19.7392, rel=5e-7)
v.check("integral of x^3 on [0,1]", 1.0 / 4.0, 0.25, rel=0)
v.check("B4 volume from radial form", 2.0 * PI**2 / 4.0, PI**2 / 2.0, rel=1e-12)
v.check("density bulk integral", 16.0 * PI**3 / 4.0, 4.0 * PI**3, rel=1e-12)
v.check("Hopf half-lapse u=cos(2*pi/6)", math.cos(2.0 * PI / 6.0), 0.5, rel=1e-12)
v.record(
    "CP-3 remains open after the G2 calculation",
    "CP-3 therefore remains open" in TEX and "No such computation is available" in TEX,
    computed="open-status caveat found",
    claimed="F4/J3(O) flat-measure argument still needed",
)

v.record(
    "W(G2) of order 12 contains a rotation by pi/6",
    False,
    computed="the G2 Weyl group has Coxeter number 6; its rotations are multiples of 2*pi/6=pi/3 and preserve root length. A pi/6 rotation would swap short and long roots and is not a Weyl symmetry",
    claimed="W(G2) order 12 includes rotation by 2*pi/12=pi/6",
    detail="Expected group-theory fail.",
)
v.record(
    "theta uniqueness proof depends correctly on Weyl group rotation",
    False,
    computed="the interleaved 30-degree root fan is real, but Step 1 proves it using a non-Weyl pi/6 rotation",
    claimed="theta=pi/6 is forced by the Weyl rotation argument",
    detail="Expected proof-step fail; the conclusion can be true while this step is false.",
)
v.record(
    "Hopf fibration alone pulls S3 measure back to the B4 radial interval",
    False,
    computed="Hopf maps S3 to S2 and has no radial coordinate; the x^3 factor is the B4 polar-volume Jacobian",
    claimed="x^3 dx is induced via Hopf pullback to [0,1]",
    detail="Expected attribution fail.",
)
v.record(
    "using volumetric x^3 dx makes the displayed rho flat integral self-consistent",
    False,
    computed=f"if 16*pi^3*x^3 is integrated against an additional x^3 dx weight, the bulk integral is 16*pi^3/7, not 4*pi^3",
    claimed="G2 volumetric measure leaves no inconsistency at the G2 level for the rho integral",
    detail="Expected measure-bookkeeping fail.",
)
v.record(
    "unique G2-compatible measure on S3 is established",
    False,
    computed="the paper does not construct a G2 action on the specific S3 boundary; it uses the ambient SO(4) round measure instead",
    claimed="round measure is the unique G2-compatible measure on S3",
    detail="Expected representation/geometric-action gap.",
)

sys.exit(v.summary())
