"""
photon_lab.py  --  testing Article 5's photon claims against the tau-loop
==========================================================================
Same format as spiral_branch.py and branch_sim2.py: every claim is
implemented or asserted as a test that could fail, with a tautology
audit separating documentation from evidence.

WHAT IS UNDER TEST
--------------------
Article 5 makes several claims about the photon that were written before
the tau-loop architecture was settled. Four are checkable arithmetically
or by simulation:

  T1  gamma = DDU = (AL)^2(AV) is dimensionless in BOTH channels
      (theta = 0 AND scalars cancel), and carries Omega^15.
  T2  e- e+ -> gamma gamma is a monopole-block recombination identity.
  T3  the coincidence framework: planar (2-wave) advances the mass
      domain, triple (3-wave) the charge domain, no coincidence leaves
      the branch photon-like. Article 5 predicts the 3-wave rate is
      suppressed by ~1/r_alpha with E[W3] ~ r_alpha^2.
  T4  the Article-4 step is one FULL Compton period, i.e. 2 pi branch
      cycles, with the residual explained by the reduced mass.

NOT TESTED HERE, AND WHY
--------------------------
The Q-bridge conversion (Q^2)_photon <-> (Q^3)_orbital is stated in
Article 5 as an isomorphism of momentum grades, but Q is never given a
numerical definition -- only the grading relation Q^2 x Q^3 = Q^5. There
is nothing to evaluate. The geometric counterpart Omega^2 x Omega^3 =
Omega^5 IS numerical and is checked below as T1c, but that is an
identity about Omega, not a test of the Q-bridge.

Whether gamma under a helical boundary constraint reproduces Article 4's
dr = (alpha/4pi) l_os is also not tested: Article 5 asserts the
constraint exists but does not specify it, so there is no construction
to run. That is the largest untested gap in the interaction sector.
"""

import math
import random

PI = math.pi
ALPHA_INV = 137.035999084
OMEGA = math.sqrt(PI**math.e * math.e**(1.0 - math.e))
R_ALPHA = math.sqrt(2.0*ALPHA_INV)          # 16.5551, Article 5's r_alpha

# atomic-transition constants (Rydberg_atom-v1.py convention)
ALPHA_CALC = 471964
AI_SIM = math.sqrt((ALPHA_CALC + 1.0/3.0)/(8.0*PI))
R0_SIM = 2.0*AI_SIM
T1_SIM = 2.0*PI*R0_SIM*R0_SIM             # 471964.333333
FREQ_ATOM = 1.5518429811660e21            # 2c/(lambda_e + lambda_p)

# measured 1s-ns transition frequencies, Hz
EXP_HZ = {2: 2466061413187.035e3,
          3: 2922743278665.79e3,
          4: 3082581563822.63e3}

# scalar content (a, b) for r^a v^b;  theta = 8a + 17b
S = {'M': (4, -1), 'T': (9, -6), 'P': (2, 0),
     'V': (0, 1), 'L': (9, -5), 'A': (-6, 3)}


def theta(ab):
    return 8*ab[0] + 17*ab[1]


def add(*xs):
    return (sum(x[0] for x in xs), sum(x[1] for x in xs))


def mul(x, n):
    return (x[0]*n, x[1]*n)


D = add(S['A'], S['L'])        # the D block, AL
U = add(S['A'], S['V'])        # the U block, AV


_results = []


def check(name, cond, detail=""):
    _results.append(bool(cond))
    print(f"  [{'PASS' if cond else 'FAIL'}] {name}" + (f"   {detail}" if detail else ""))
    return cond


# ----------------------------------------------------------------------
# T1  gamma = DDU
# ----------------------------------------------------------------------

def test_gamma():
    print("\n-- T1: gamma = DDU = (AL)^2 (AV) --")
    check("theta(AL) = -10", theta(D) == -10, f"got {theta(D)}, scalars r^{D[0]} v^{D[1]}")
    check("theta(AV) = +20", theta(U) == 20, f"got {theta(U)}, scalars r^{U[0]} v^{U[1]}")
    g = add(D, D, U)
    check("theta(gamma) = 0", theta(g) == 0, f"got {theta(g)}")
    check("gamma is SCALAR-FREE (r and v both cancel)", g == (0, 0),
          f"scalars r^{g[0]} v^{g[1]}")
    print("       Both channels cancel, so gamma is dimensionless in the same")
    print("       strong sense as psi -- not merely theta-neutral. Article 5's")
    print("       claim is correct as written.")
    # T1c: the Omega grading
    check("Omega^2 x Omega^3 = Omega^5 (the geometric Q-bridge counterpart)",
          abs(OMEGA**2*OMEGA**3 - OMEGA**5) < 1e-12)
    check("gamma carries Omega^15 = (Omega^5)^3",
          abs((OMEGA**5)**3 - OMEGA**15) < 1e-9,
          f"Omega^15 = {OMEGA**15:.4f}")


# ----------------------------------------------------------------------
# T2  annihilation bookkeeping
# ----------------------------------------------------------------------

def test_annihilation():
    print("\n-- T2: e- e+ -> gamma gamma as block recombination --")
    e_minus = {'D': 3, 'U': 0}          # DDD
    e_plus = {'D': 1, 'U': 2}           # DUU
    two_gamma = {'D': 4, 'U': 2}        # 2 x DDU
    lhs = {k: e_minus[k] + e_plus[k] for k in 'DU'}
    check("block counts balance: DDD + DUU = 2(DDU)", lhs == two_gamma,
          f"{lhs} vs {two_gamma}")

    lhs_s = add(mul(D, lhs['D']), mul(U, lhs['U']))
    rhs_s = add(mul(D, two_gamma['D']), mul(U, two_gamma['U']))
    check("scalars balance", lhs_s == rhs_s, f"r^{lhs_s[0]} v^{lhs_s[1]}")
    check("theta balances", theta(lhs_s) == theta(rhs_s),
          f"theta = {theta(lhs_s)}")
    check("and the total is itself scalar-free", lhs_s == (0, 0))
    print("       The identity holds in block count, scalars and theta")
    print("       simultaneously. Note this is BOOKKEEPING: it shows the")
    print("       reaction is allowed by the algebra, not that it occurs,")
    print("       and it says nothing about rate or kinematics.")


# ----------------------------------------------------------------------
# T3  the coincidence framework
# ----------------------------------------------------------------------

def test_coincidence(n_ticks=4_000_000, seed=3):
    print("\n-- T3: coincidence rates (2-wave vs 3-wave vs none) --")
    print(f"   Article 5: 3-wave progress suppressed ~1/r_alpha relative to")
    print(f"   2-wave, with E[W3] ~ r_alpha^2 = {R_ALPHA**2:.1f} ticks.")
    rng = random.Random(seed)
    # three phases advancing at incommensurate rates; a coincidence is a
    # near-alignment within a tolerance set by the lattice resolution
    tol = 1.0/R_ALPHA                     # per-pair alignment probability
    n2 = n3 = 0
    w3_gaps = []
    last3 = 0
    for k in range(1, n_ticks+1):
        p12 = rng.random() < tol
        p13 = rng.random() < tol
        if p12 and p13:
            n3 += 1
            w3_gaps.append(k - last3)
            last3 = k
        elif p12 or p13:
            n2 += 1
    r2 = n2/n_ticks
    r3 = n3/n_ticks
    print(f"     2-wave rate = {r2:.6e}   (expect ~2/r_alpha = {2/R_ALPHA:.4e})")
    print(f"     3-wave rate = {r3:.6e}   (expect ~1/r_alpha^2 = {1/R_ALPHA**2:.4e})")
    check("3-wave suppressed relative to 2-wave by ~1/r_alpha",
          abs((r2/r3)/R_ALPHA - 2.0) < 0.3,
          f"ratio/r_alpha = {(r2/r3)/R_ALPHA:.3f} (expect 2)")
    if w3_gaps:
        mean_w = sum(w3_gaps)/len(w3_gaps)
        check("E[W3] ~ r_alpha^2", abs(mean_w/R_ALPHA**2 - 1.0) < 0.15,
              f"mean gap {mean_w:.1f} vs r_alpha^2 = {R_ALPHA**2:.1f}")
    print("       The rates follow from the tolerance 1/r_alpha by")
    print("       construction, so this confirms Article 5's arithmetic is")
    print("       self-consistent; it does NOT independently verify that")
    print("       1/r_alpha is the right tolerance.")


# ----------------------------------------------------------------------
# T4  the step relation
# ----------------------------------------------------------------------

def test_step():
    print("\n-- T4: Article-4 step vs branch cycle --")
    h, c = 6.62607015e-34, 2.99792458e8
    me, mp = 9.1093837015e-31, 1.67262192369e-27
    t_P, psi_e = 5.391247e-44, 2.389545e22
    l0 = h/(me*c) + h/(mp*c)
    step = l0/c
    cycle = psi_e*t_P
    ratio = step/cycle
    check("l_0 matches Article 4", abs(l0 - 2.42763e-12)/2.42763e-12 < 1e-5,
          f"{l0:.7e} m")
    check("step/cycle = 2 pi to within the reduced-mass factor",
          abs(ratio/(2*PI) - 1.0) < 1e-3,
          f"ratio = {ratio:.6f}, 2pi = {2*PI:.6f}")
    resid = ratio/(2*PI)
    mu = 1 + me/mp
    check("the residual IS the reduced mass", abs(resid/mu - 1.0) < 2e-4,
          f"residual {resid:.7f} vs 1+m_e/m_p = {mu:.7f}")
    print("       branch cycle = REDUCED Compton time (radius-like)")
    print("       Article-4 step = FULL Compton period (circumference-like)")
    print("       so the 2 pi is the same conversion as psi = sigma^3/2T.")


# ----------------------------------------------------------------------

def test_rydberg_scaling():
    """T5. The model scales exactly as (1-1/n^2). Any n-dependence in the
    residual therefore belongs to the EXPERIMENT, not the model."""
    print("\n-- T5: Rydberg scaling and the residual decomposition --")
    f = lambda n: (n*n - 1.0)*FREQ_ATOM/(n*n*T1_SIM)
    for a, b in ((2, 3), (2, 4), (3, 4)):
        mr = f(a)/f(b)
        pr = (1 - 1/a**2)/(1 - 1/b**2)
        check(f"model ratio {a}/{b} is exactly (1-1/n^2)",
              abs(mr - pr) < 1e-12, f"{mr:.12f}")

    print(f"  {'n':>3}{'model ppm':>13}{'exp departure':>16}{'sum':>12}")
    base = (f(2) - EXP_HZ[2])/EXP_HZ[2]*1e6
    A = EXP_HZ[2]/(1 - 1/4)
    tot = []
    for n in (2, 3, 4):
        ppm = (f(n) - EXP_HZ[n])/EXP_HZ[n]*1e6
        dep = (EXP_HZ[n]/(1 - 1/n**2) - A)/A*1e6
        tot.append(abs(ppm - base + dep))
        print(f"  {n:>3}{ppm:>13.3f}{dep:>16.3f}{ppm-base+dep:>12.5f}")
    check("residual n-dependence is exactly the experimental departure",
          max(tot) < 1e-3, f"max |sum| = {max(tot):.2e} ppm")
    print(f"       So the offset is a CONSTANT {base:.3f} ppm, and the")
    print( "       apparent drift to -10.8 is the Lamb shift and related")
    print( "       QED terms, which the model does not contain. Quoting")
    print( "       '-11 ppm common across n' conflates the two.")


def test_pitch_and_increment():
    """T6. The helical constraint, now that it is specified."""
    print("\n-- T6: pitch and radial increment --")
    dr_sim = 1.0/(2.0*PI*R0_SIM)          # rincr, in l_0 per step
    dr_art4 = 1.0/(AI_SIM*4.0*PI)         # alpha/4pi
    check("rincr = alpha/4pi identically",
          abs(dr_sim - dr_art4)/dr_sim < 1e-14,
          f"{dr_sim:.9e} vs {dr_art4:.9e}")
    print("       since r_0 = 2/alpha, 2 pi r_0 = 4 pi/alpha. Article 4's")
    print("       increment and the simulation's are the same number.")

    # pitch from the IMPOSED phase: tan = n/2pi
    print(f"  {'n':>4}{'tan = n/2pi':>15}{'numerical':>15}{'theta':>11}")
    ok = True
    for n in (1, 2, 3, 4):
        k = (n*n - 1.0)*T1_SIM
        dphi = 2.0*PI/(T1_SIM*n**3)
        r_in_l0 = n*n*R0_SIM          # radius in l_0, NOT in r_0 units
        num = (1.0/(2.0*PI*R0_SIM))/(r_in_l0*dphi)
        ok &= abs(num - n/(2*PI))/(n/(2*PI)) < 1e-9
        print(f"  {n:>4}{n/(2*PI):>15.9f}{num:>15.9f}"
              f"{math.degrees(math.atan(n/(2*PI))):>10.4f}d")
    check("pitch = n/2pi from the imposed phase", ok)
    print("       Rising with n, NOT the (1-1/n^2)/4pi that a constant-dr")
    print("       reading gives. The two constructions are incompatible and")
    print("       this is the one reproducing the frequencies.")


def test_q_bridge():
    """T7. The Q-grading, which HAS a realisation after all."""
    print("\n-- T7: Q^2 x Q^3 = Q^5 --")
    Om = OMEGA
    check("Omega^2 x Omega^3 = Omega^5", abs(Om**2*Om**3 - Om**5) < 1e-12)
    print(f"       V ~ Omega^2 (mass), A ~ Omega^3 (charge), K ~ Omega^5")
    print(f"       and K = AV/2pi BY DEFINITION, so the grading is that")
    print(f"       identity: temperature is current times velocity.")
    # A's grade is forced, not assigned
    print(f"       A ~ V^3/P^3 ~ Omega^(6-3) = Omega^3   -- forced")
    check("Omega^15 = (Omega^5)^3", abs(Om**15 - (Om**5)**3) < 1e-6,
          f"{Om**15:.4f}")
    print(f"       An earlier version of this file recorded the Q-bridge as")
    print(f"       'not testable, Q has no numerical definition'. It does")
    print(f"       have one: Q is the Omega grading with the value removed.")


def test_commensurability():
    """T8. W-axis vs orbital winding, and the integer-transition rule."""
    print("\n-- T8: commensurability and integer transitions --")
    def ratio(n):
        W = (n*n - 1.0)*T1_SIM*PI
        return W/(2.0*(1.0 - 1.0/n))
    base = ratio(2)
    ok = all(abs(ratio(n)/base - n*(n+1)/6.0) < 1e-9
             for n in (2, 3, 4, 5, 6, 8, 10))
    check("W/orbital winding ratio = n(n+1)/6 x ratio(2)", ok)
    print("       pi cancels: both windings carry it. Neither winding is")
    print("       rational; their ratio is.")

    from fractions import Fraction
    T1f = Fraction(ALPHA_CALC) + Fraction(1, 3)
    ok2 = all((((n*n - 1)*T1f).denominator == 1) == (n % 3 != 0)
              for n in range(2, 40))
    check("transition integral exactly when 3 does not divide n", ok2)
    print("       This is what the +1/3 in alpha_calc achieves, and it is")
    print("       the branch model's synchronisation condition applied to")
    print("       the closure EVENT rather than to the orbital period.")
    a = math.sqrt(float(T1f)/(8.0*PI))
    print(f"       implied alpha^-1 = {a:.9f}")
    for nm, v in (("Art.6 pathway A", 137.03599512277),
                  ("Art.6 cube c/D", 137.03599591488)):
        print(f"         vs {nm:<18}{(v-a)/a*1e9:>8.2f} ppb")


def audit():
    print("\n-- TAUTOLOGY AUDIT --")
    print("   BY CONSTRUCTION (documentation, not evidence):")
    for s in ["Omega^2 x Omega^3 = Omega^5      (exponent arithmetic)",
              "coincidence rates from tolerance (tol is set to 1/r_alpha)",
              "l_0 matches Article 4           (same formula)"]:
        print(f"     - {s}")
    print("   GENUINE (could have failed):")
    for s in ["theta(AL) and theta(AV) match Article 5's stated values",
              "gamma scalar-free in BOTH channels, not just theta",
              "DDD + DUU = 2(DDU) in blocks, scalars and theta together",
              "step/cycle = 2 pi from two unrelated definitions",
              "the 2 pi residual equals the reduced-mass factor"]:
        print(f"     + {s}")
    print("\n   RESOLVED SINCE THE FIRST VERSION:")
    for t in ["Q-bridge: Q IS defined -- it is the Omega grading, realised",
              "   as K = AV/2pi (T7). Previously marked not testable.",
              "helical constraint: SPECIFIED, pitch = n/2pi from the",
              "   imposed phase (T6). Previously marked not testable."]:
        print(f"     * {t}")
    print("\n   STILL NOT TESTABLE HERE:")
    for t in ["Phi = 4 pi(1-1/n) is Article 4's construction, not derived",
              "   from the tau-loop axioms. T6 and T8 therefore show",
              "   consistency, not correctness.",
              "how a loop with no closure condition acquires one (the",
              "   photon terminating on absorption). No axiom covers it."]:
        print(f"     ? {t}")


if __name__ == "__main__":
    print("="*70)
    print("PHOTON LAB -- Article 5 claims against the tau-loop")
    print("="*70)
    print(f"  Omega   = {OMEGA:.12f}")
    print(f"  r_alpha = sqrt(2/alpha) = {R_ALPHA:.8f}")
    print(f"  D = AL: r^{D[0]} v^{D[1]}, theta = {theta(D)}")
    print(f"  U = AV: r^{U[0]} v^{U[1]}, theta = {theta(U)}")
    test_gamma()
    test_annihilation()
    test_coincidence()
    test_step()
    test_rydberg_scaling()
    test_pitch_and_increment()
    test_q_bridge()
    test_commensurability()
    audit()
    print("\n" + "="*70)
    print(f"OVERALL: {sum(_results)}/{len(_results)} passed"
          + ("" if all(_results) else "   <-- FAILURES PRESENT"))
    print("="*70)