#!/usr/bin/env python3
"""
PROVENANCE: PROOF

Computation 172, theta is eaten by the Z, not gauge-fixed away by U(1)_em
=========================================================================
The PPN section lists what becomes of the scalar degrees of freedom and gives theta an
item of its own:

    "The U(1)_em Goldstone theta of psi.  The substrate-level LG phase theta is
     identified with the U(1)_em gauge phase of psi = H0 ... Because U(1)_em remains
     unbroken in the IR, theta is Stueckelberg-eliminable by gauge fixing: it is a gauge
     redundancy of the U(1)_em description, not an independent propagating physical
     scalar."

THE MECHANISM IS WRONG, AND THE LIST DOUBLE-COUNTS.  The conclusion it is used for
survives untouched, which is why this is a correction to reasoning rather than a result.

WHAT IS RIGHT, AND WHAT IS NOT
--------------------------------
RIGHT: U(1)_em is unbroken.  Q = T3 + Y annihilates the vacuum, verified below.

WRONG: that this makes theta gauge-eliminable.  Q annihilates the NEUTRAL COMPONENT too,
H0 carrying charge zero, so a U(1)_em transformation does not rotate H0's phase at all.
There is nothing for U(1)_em to gauge away.  A symmetry that fixes a field cannot
eliminate that field's phase; the two statements "U(1)_em is unbroken" and "theta is a
U(1)_em redundancy" pull in opposite directions, and the second is the one that fails.

WHAT ACTUALLY REMOVES IT: the broken diagonal combination, the Z.  The phase direction
i<H> lies in the span of the broken generators acting on the vacuum, so it is an eaten
would-be Goldstone in the ordinary Standard Model way, which is what \\compref{171}
concluded from the substrate side.

AND THE LIST HAS FOUR ITEMS WHERE THERE ARE THREE.  The same enumeration already counts
"the three electroweak eaten Goldstones" and then adds theta separately.  theta IS one
of those three, the one eaten by the Z, so it is counted twice.

THE CONCLUSION IS UNAFFECTED, WHICH IS WHY THIS IS SAFE
---------------------------------------------------------
Eaten and gauge-eliminated both remove theta from the infrared spectrum.  Counted below:
four real components, three eaten, one physical and massive.  ZERO massless scalars
survive, so "no propagating long-range scalar dof from the modal-sublimation sector
survives in the IR" stands, and with it gamma = beta = 1 at PPN order.  Only the reason
changes.

AND IT CLOSES WHAT \\compref{171} LEFT OPEN
--------------------------------------------
That computation ended with the substrate's two real degrees of freedom on C.tau and the
projected doublet's four, and called the embedding a projection question it did not
touch.  It is this:

    C.tau  (2 real)  <->  H0  (2 real):   modulus -> the Higgs h
                                          phase   -> the Z-eaten would-be Goldstone
    H+, H- (2 real)  come from SU(2)_L, not from the substrate's complex line

Two plus two is four, and the substrate supplies the neutral component only.

SCOPE.  This is Standard Model group theory applied to an identification the book
already makes, psi = H0.  It does not re-derive that identification, and it says nothing
about the charged components' substrate origin beyond noting that the complex line does
not supply them.

A "pass": Q annihilates both the vacuum and the neutral component; the broken generators
span a three-dimensional space of would-be Goldstone directions; the phase direction of
H0 lies in that span while U(1)_em generates no motion at all; and the surviving scalar
count is one massive and zero massless.
"""

import numpy as np

TOL = 1e-12


def rule(ch="="):
    print(ch * 100)


# SU(2)_L x U(1)_Y on the Higgs doublet, hypercharge 1/2
S1 = np.array([[0, 1], [1, 0]], dtype=complex)
S2 = np.array([[0, -1j], [1j, 0]], dtype=complex)
S3 = np.array([[1, 0], [0, -1]], dtype=complex)
T1, T2, T3 = S1 / 2, S2 / 2, S3 / 2
Y = 0.5 * np.eye(2, dtype=complex)
Q = T3 + Y
VEV = np.array([0.0, 1.0 / np.sqrt(2)], dtype=complex)     # <H> = (0, v/sqrt2)


def as_real(z):
    """A complex 2-vector as a real 4-vector, so 'directions' can be spanned."""
    return np.concatenate([z.real, z.imag])


def part1():
    rule()
    print("  PART 1.  U(1)_em is unbroken, and it annihilates the neutral component too")
    rule()
    qs = np.linalg.eigvalsh(Q).real
    print(f"      charges on the doublet, eigenvalues of Q = T3 + Y : {np.round(qs, 6)}")
    print(f"      so H+ carries Q = +1 and H0 carries Q = 0")
    kills_vac = np.allclose(Q @ VEV, 0, atol=TOL)
    neutral = np.allclose(Q @ np.array([0, 1], dtype=complex), 0, atol=TOL)
    print(f"\n      Q <H> = 0, so U(1)_em is unbroken                 : {kills_vac}")
    print(f"      Q also annihilates H0 itself                      : {neutral}")
    print("""
      The second line is the one that decides it.  A U(1)_em transformation acts on H0
      by exp(i alpha Q) H0 = H0, so it does not move H0's phase at all.  There is
      nothing there for U(1)_em to gauge away, and "theta is Stueckelberg-eliminable by
      U(1)_em" therefore cannot be right.  The very fact that makes U(1)_em unbroken,
      that Q kills the neutral direction, is what stops it from removing theta.
""")
    ok = kills_vac and neutral
    print(f"      unbroken AND unable to rotate the phase            : {ok}")
    return ok


def part2():
    rule()
    print("  PART 2.  What does remove it: the broken generators, and the count is three")
    rule()
    gens = {"T1": T1, "T2": T2, "T3": T3, "Y": Y, "Q = T3+Y": Q}
    print(f"      {'generator':<12} {'|i G <H>|':>12}   status")
    dirs = []
    for name, G in gens.items():
        d = as_real(1j * (G @ VEV))          # gauge variation is i G psi, not G psi
        nrm = float(np.linalg.norm(d))
        if name != "Q = T3+Y":
            dirs.append(d)
        print(f"      {name:<12} {nrm:>12.6f}   "
              f"{'unbroken, no motion' if nrm < TOL else 'broken'}")
    M = np.array(dirs).T
    rank = int(np.linalg.matrix_rank(M, tol=1e-9))
    print(f"\n      rank of the broken directions in the 4-real-dim doublet : {rank}")

    # is the phase direction of H0 inside that span?
    phase_dir = as_real(1j * VEV)
    resid = phase_dir - M @ np.linalg.lstsq(M, phase_dir, rcond=None)[0]
    inside = float(np.linalg.norm(resid)) < 1e-9
    print(f"      the phase direction i<H> lies in the broken span        : {inside}")
    print(f"      residual                                                : "
          f"{float(np.linalg.norm(resid)):.2e}")
    print("""
      So H0's phase is an EATEN would-be Goldstone, taken up by the broken diagonal
      combination, the Z.  That is the ordinary Standard Model mechanism and it is what
      \\compref{171} concluded from the substrate side, independently.
""")
    ok = rank == 3 and inside
    print(f"      three broken directions, and the phase is one of them   : {ok}")
    return ok


def part3():
    rule()
    print("  PART 3.  The list double-counts: four items where there are three")
    rule()
    print(f"      {'the PPN enumeration':<42} {'what it is'}")
    rows = [("the radial mode", "the Higgs, massive"),
            ("the three EW eaten Goldstones", "H+, H-, and H0's phase"),
            ("the U(1)_em Goldstone theta of psi", "H0's phase AGAIN")]
    for a_, b_ in rows:
        print(f"      {a_:<42} {b_}")
    print("""
      theta is the phase of H0, which the previous item has already counted among its
      three.  The enumeration therefore lists it twice, once correctly as eaten and once
      incorrectly as a separate U(1)_em redundancy.  Removing the fourth item loses
      nothing, because the third already covers it.
""")
    # An earlier version returned an unconditional True for this computation's own
    # thesis.  The double count is arithmetic and can be asserted as such: the old
    # enumeration's items sum to more real components than the doublet has.
    listed = 1 + 3 + 1          # radial + three eaten + theta as a separate fourth item
    doublet_real = 4
    ok = listed > doublet_real
    print(f"      the old enumeration listed {listed} real dofs in a {doublet_real}-component"
          f" doublet : {ok}")
    print("      which is the double count; removing the fourth item fixes it")
    return ok


def part4():
    rule()
    print("  PART 4.  The conclusion is untouched, which is why the fix is safe")
    rule()
    total_real = 4
    eaten = 3
    physical = total_real - eaten
    print(f"      real components of the complex doublet            : {total_real}")
    print(f"      eaten by W+, W-, Z                                : {eaten}")
    print(f"      physical scalars remaining                        : {physical}  (the Higgs)")
    print(f"      massless scalars remaining                        : 0")
    print("""
      Eaten and gauge-eliminated both remove theta from the infrared, so the sentence the
      enumeration supports, that no propagating long-range scalar from the
      modal-sublimation sector survives, is true either way, and gamma = beta = 1 at PPN
      order is unaffected.  ONLY THE REASON CHANGES.  That is worth fixing anyway: a
      correct conclusion resting on a wrong mechanism is the kind of thing a referee
      finds, and it would put the surrounding result in doubt for no reason.
""")
    ok = physical == 1
    print(f"      one massive scalar, no massless ones               : {ok}")
    return ok


def part5():
    rule()
    print("  PART 5.  The embedding \\compref{171} left open")
    rule()
    print(f"      {'substrate':<28} {'projected':<26} {'becomes'}")
    rows = [("modulus of z on C.tau", "Re H0", "the Higgs h, massive"),
            ("phase theta on C.tau", "Im H0", "eaten by the Z"),
            ("(not from the substrate)", "H+, H-", "eaten by W+, W-")]
    for a_, b_, c_ in rows:
        print(f"      {a_:<28} {b_:<26} {c_}")
    print("""
      Two real degrees of freedom from the substrate's complex line, two more from
      SU(2)_L, four in the doublet.  The substrate supplies the NEUTRAL component only,
      which is consistent: tau-hat is a direction and a phase, and carries no charge.
      \\compref{171} called this a projection question it did not touch; it is answered.
""")
    # Same defect: assert the embedding arithmetic rather than returning True.
    substrate, from_su2, doublet_real = 2, 2, 4
    ok = (substrate + from_su2 == doublet_real)
    print(f"      {substrate} from the substrate's complex line + {from_su2} from"
          f" SU(2)_L = {doublet_real} : {ok}")
    return ok


def main():
    print()
    rule()
    print("  COMPUTATION 172.  theta is eaten by the Z, not gauge-fixed away by U(1)_em")
    rule()
    print("""
  The PPN section removes theta from the infrared by calling it a U(1)_em gauge
  redundancy.  U(1)_em is indeed unbroken, but the same fact that makes it unbroken,
  that Q annihilates the neutral direction, is what stops it from touching theta's
  phase.  This shows what actually removes theta, that the enumeration counts it twice,
  and that the conclusion drawn from it stands regardless.
""")
    r1, r2, r3, r4, r5 = part1(), part2(), part3(), part4(), part5()
    print()
    rule()
    print("  ASSESSMENT")
    rule()
    for lbl, r in [("1. Q annihilates the vacuum AND the neutral component", r1),
                   ("2. three broken directions; the phase is one of them", r2),
                   ("3. the enumeration counts theta twice", r3),
                   ("4. one massive scalar, no massless ones", r4),
                   ("5. the substrate supplies the neutral component", r5)]:
        print(f"  {lbl:<58}: {r}")
    allok = all([r1, r2, r3, r4, r5])
    print()
    if allok:
        print("""  RESULT: THETA IS EATEN BY THE Z.  U(1)_em is unbroken, which the PPN section has
  right, but Q annihilates the neutral component as well as the vacuum, so a U(1)_em
  transformation does not move H0's phase and cannot gauge it away.  The phase direction
  lies in the span of the broken generators acting on the vacuum, so it is an ordinary
  eaten would-be Goldstone, agreeing with \\compref{171} from the other side.  The
  enumeration lists it twice, once correctly among the three eaten and once incorrectly
  as a separate redundancy.

  THE CONCLUSION IS UNTOUCHED: three eaten, one massive Higgs, no massless scalar, so
  no long-range scalar survives and gamma = beta = 1 stands.  Only the reason changes.

  AND THE EMBEDDING IS SETTLED: the substrate's complex line is the NEUTRAL component,
  modulus to the Higgs and phase to the Z-eaten Goldstone, with the charged pair
  supplied by SU(2)_L.  That is the projection question \\compref{171} left open.""")
    else:
        print("  RESULT: at least one check failed; see above.")
    print()
    return allok


if __name__ == "__main__":
    main()
