"""
compute_het_sg0.8.py
Computation of every quantity in the Summary of results of
"Spectral Geometry of Vacuum Entanglement on the Cube and Prism" (het_sg0.8).
Self-contained: numpy only, no files read.  Paste into one Google Colab cell and run.

PHYSICS CARRIED IN THIS FILE
----------------------------
Bond: S_chi = S_BH l_P^2/A = 1/4 (Bekenstein-Hawking), vacuum entanglement S* = 2/9,
residual entanglement capacity xi* = S_chi - S* = 1/36.
Prism Q4 = Q3 x I: 16 vertices (x,y,z,tau) in {0,1}^4, index v = 8x+4y+2z+tau; 32 edges,
each oriented from its 0-vertex to its 1-vertex in the flipped coordinate.
Disentangler deformation: c_D = (5/sqrt2) xi*, x and y edges weight omega = 1 + 4 c_D,
z and tau edges weight 1.  Weighted vertex Laplacian L_{V,omega}; M_{V,omega} = L_{V,omega} + 1.
Sigma_V = Tr M_{V,omega}^-1.

Gravity (sec. 8):     1/(16 pi G_N) = Sigma_V / (12 x 16) l_P^-2,  so G_N = 12/(pi Sigma_V) l_P^2.
Descent (sec. 9):     E_phi = m_P Theta_phi Pi_phi^p exp(-1/xi*),  m_P = 1.2209e19 GeV.
  suppression:       exp(-1/xi*) = exp(-36);  m_IR = m_P exp(-1/xi*);  l_c = l_P exp(1/xi*) = hbar c/m_IR.
  vev:               Higgs mode psi = (-1)^tau, lambda = 2, G_psi = 1/3, Pi_psi = G_psi/Sigma_V,
                     Theta_psi = 1, p = 1.
  string tension:    sourced colour flux b_s on the z-tau face at (x,y) = (0,0), bare edge operator
                     M_E = d0 d0^T + 1, G_bs = b^T M_E^-1 b / |b|^2, Pi_bs = G_bs/Sigma_E,
                     Theta_bs = 3/8, p = 2.
  glueball:          closed colour flux b_g on the same face, Pi_bg = 1/Sigma_E, Theta_bg = 1/4, p = 2.
Neutrinos (sec. 10):  cell (a,b) of L_{V,omega}: a excited x,y directions, b excited z,tau directions,
                     lambda(a,b) = 2 omega a + 2 b, multiplicity C(2,a) C(2,b).
                     D_omega = det M_{V,omega}^-1, Theta_nu = 1/2,
                     y_nu_i = Theta_nu D_omega prod over C_i of 1/(1+lambda),
                     C_3 = {(1,2)}, C_2 = {(1,2),(1,1)}, C_1 = {(1,2),(1,1),(2,2)};  m_nu_i = y v/sqrt2.
Charged leptons (sec. 11): R_ab = 1/(m^2 + lambda(a,b)), m^2 = 1; couplings m^2 and omega;
                     y_tau = (h0 G_psi)^-1 d_m2 R22 / d_m2 ln D_omega, h0 = 1/sqrt2;
                     y_mu = |d y_tau / d ln y_nu3| in m^2;  y_e = |d y_mu / d ln y_nu2| in omega.
References: v 246.22 GeV (PDG); y_tau 9.93780e-3, y_mu 5.85042e-4, y_e 2.77713e-6 at M_Z (Antusch-Hinze-Saad); sqrt(sigma) 424.264 MeV (hadron spectrum); m_0++ 1730(50)(80) MeV
(anisotropic lattice); NuFIT 6.0 dm21^2 = 7.49e-5, dm31^2 = 2.513e-3 eV^2 (dm32^2 = dm31^2 - dm21^2); DESI DR2 sum < 0.0642 eV.
"""
import itertools, math
import numpy as np

# ---------------------------------------------------------------- prism
S_CHI, S_STAR = 1/4, 2/9
XI = S_CHI - S_STAR
V = [tuple(int(c) for c in f"{n:04b}") for n in range(16)]          # (x,y,z,tau)
E = [(i, j) for i, a in enumerate(V) for j, b in enumerate(V)
     if sum(p != q for p, q in zip(a, b)) == 1 and sum(b) > sum(a)]  # 0-vertex -> 1-vertex
AXIS = [[k for k in range(4) if V[i][k] != V[j][k]][0] for i, j in E]
d0 = np.zeros((len(E), 16))
for k, (i, j) in enumerate(E):
    d0[k, i], d0[k, j] = -1, 1
C_D = 5*XI/math.sqrt(2)
OM = 1 + 4*C_D
W = np.array([OM if ax in (0, 1) else 1.0 for ax in AXIS])
L_V = d0.T @ np.diag(W) @ d0
M_V = L_V + np.eye(16)
SIGMA_V = np.trace(np.linalg.inv(M_V))

# ---------------------------------------------------------------- gravity
G_N = 12/(math.pi*SIGMA_V)

# ---------------------------------------------------------------- descent
M_P = 1.2209e19
DESC = math.exp(-1/XI)                                              # descent suppression exp(-1/xi*)
M_IR = M_P*DESC                                                     # m_IR = m_P exp(-1/xi*), GeV
HBARC = 1.973269804e-16                                             # hbar c, GeV m
L_C = HBARC/M_IR                                                    # l_c = l_P exp(1/xi*) = hbar c/m_IR, m
PSI = np.array([(-1)**v[3] for v in V], float)
G_PSI = PSI @ np.linalg.inv(M_V) @ PSI / (PSI @ PSI)
VEV = M_P*1*(G_PSI/SIGMA_V)*DESC

M_E = d0 @ d0.T + np.eye(len(E))
SIGMA_E = np.trace(np.linalg.inv(M_E))
EIDX = {e: k for k, e in enumerate(E)}
idx = lambda s: int(s, 2)
face = [(idx("0000"), idx("0010")), (idx("0010"), idx("0011")),
        (idx("0001"), idx("0011")), (idx("0000"), idx("0001"))]
b_s = np.zeros(len(E)); b_g = np.zeros(len(E))
for e, s, g in zip(face, (+1, -1, -1, +1), (+1, +1, -1, -1)):
    b_s[EIDX[e]], b_g[EIDX[e]] = s, g
G_BS = b_s @ np.linalg.inv(M_E) @ b_s/(b_s @ b_s)
G_BG = b_g @ np.linalg.inv(M_E) @ b_g/(b_g @ b_g)
SQRT_SIGMA = M_P*(3/8)*(G_BS/SIGMA_E)**2*DESC
M_GLUE = M_P*(1/4)*(G_BG/SIGMA_E)**2*DESC

# ---------------------------------------------------------------- neutrinos
LAM = lambda a, b: 2*OM*a + 2*b
MULT = lambda a, b: math.comb(2, a)*math.comb(2, b)
CELLS = [(a, b) for a in range(3) for b in range(3)]
D_OM = 1/np.linalg.det(M_V)
THETA_NU = 0.5
READ = {"nu1": [(1, 2), (1, 1), (2, 2)], "nu2": [(1, 2), (1, 1)], "nu3": [(1, 2)]}
y_nu = {n: THETA_NU*D_OM/np.prod([1 + LAM(*c) for c in cs]) for n, cs in READ.items()}
m_nu = {n: y*VEV/math.sqrt(2)*1e9 for n, y in y_nu.items()}                # eV
D21 = m_nu["nu2"]**2 - m_nu["nu1"]**2
D31 = m_nu["nu3"]**2 - m_nu["nu1"]**2
SUM = sum(m_nu.values())

res = lambda x, r: 100*(x/r - 1)
print("Table 1. Prism quantities")
print("  omega = %.12f   Sigma_V = %.9f   Sigma_E = %.9f (6368/315 = %.9f)" % (OM, SIGMA_V, SIGMA_E, 6368/315))
print("  check: spectrum of L_V,omega = 2 omega a + 2 b:",
      np.allclose(np.sort(np.linalg.eigvalsh(L_V)), sorted(LAM(a, b) for a, b in CELLS for _ in range(MULT(a, b)))))
print("  G_psi = %.9f (1/3)   G_bs = %.9f (127/315 = %.9f)   G_bg = %.9f" % (G_PSI, G_BS, 127/315, G_BG))
print("  D_omega = %.9e" % D_OM)
print("  1/xi* = %.9f   exp(-1/xi*) = %.6e   m_IR = %.1f GeV   l_c/l_P = %.6e   l_c = %.4e m" % (1/XI, DESC, M_IR, math.exp(1/XI), L_C))
print("\nTable 2. Summary of results")
print("  %-22s %-24s %-20s %s" % ("quantity", "prism value", "reference value", "residual"))
print("  %-22s %-24s %-20s %+.3f%%" % ("G_N", "%.6f l_P^2" % G_N, "l_P^2", res(G_N, 1.0)))
print("  %-22s %-24s %-20s %+.2f%%" % ("v", "%.6f GeV" % VEV, "246.22 GeV", res(VEV, 246.22)))
print("  %-22s %-24s %-20s %+.2f%%" % ("sqrt(sigma)", "%.4f MeV" % (1e3*SQRT_SIGMA), "424.264 MeV", res(1e3*SQRT_SIGMA, 424.264)))
print("  %-22s %-24s %-20s %s" % ("m_0++", "%.2f MeV" % (1e3*M_GLUE), "1730(50)(80) MeV", "---"))
for n in ("nu1", "nu2", "nu3"):
    print("  %-22s %-24s %-20s %s" % ("m_" + n, "%.6f eV" % m_nu[n], "---", "---"))
print("  %-22s %-24s %-20s %+.2f%%" % ("dm21^2", "%.6e eV^2" % D21, "7.49e-5 eV^2", res(D21, 7.49e-5)))
print("  %-22s %-24s %-20s %+.3f%%" % ("dm31^2", "%.6e eV^2" % D31, "2.513e-3 eV^2", res(D31, 2.513e-3)))
print("  %-22s %-24s %-20s %+.3f%%" % ("dm32^2", "%.6e eV^2" % (m_nu["nu3"]**2 - m_nu["nu2"]**2), "2.4381e-3 eV^2", res(m_nu["nu3"]**2 - m_nu["nu2"]**2, 2.513e-3 - 7.49e-5)))
print("  %-22s %-24s %-20s %s" % ("sum m_nu", "%.6f eV" % SUM, "< 0.0642 eV", "---"))
print("\nTable 3. Neutrino Yukawa couplings: y = Theta_nu D_omega / prod(1+lambda)")
for n in ("nu1", "nu2", "nu3"):
    print("  %s  cells %-24s  product of 1+lambda %.6f  y %.9e" % (n, READ[n], np.prod([1 + LAM(*c) for c in READ[n]]), y_nu[n]))
# selection on the prism: every form with up to four cell factors
NT = [c for c in CELLS if c != (0, 0)]
FORMS = [f for k in range(5) for f in itertools.combinations_with_replacement(NT, k)]
mass = lambda f: THETA_NU*D_OM/np.prod([1 + LAM(*c) for c in f])*VEV/math.sqrt(2)*1e9
lo3, hi3 = math.sqrt(2.513e-3), 0.050310
sol3 = [f for f in FORMS if lo3 <= mass(f) <= hi3]
m1max = math.sqrt(m_nu["nu3"]**2 - 2.513e-3)
lo2, hi2 = math.sqrt(7.49e-5), math.sqrt(m1max**2 + 7.49e-5)
sol2 = [f for f in FORMS if len(f) <= 2 and lo2 <= mass(f) <= hi2]
print("\nTable 4. Selection on the prism")
print("  forms with up to four cell factors: %d; solutions for m_nu3 in [%.6f, %.6f] eV: %s" % (len(FORMS), lo3, hi3, sol3))
print("  forms with up to two cell factors: %d; solutions for m_nu2 in [%.6f, %.6f] eV: %s" %
      (sum(len(f) <= 2 for f in FORMS), lo2, hi2, sol2))
for c in NT:
    m1 = m_nu["nu2"]/(1 + LAM(*c))
    print("  nu1 = nu2/(1+lambda%s): m_nu1 %.6f eV, dm21^2 residual %+.3f%%" % (c, m1, res(m_nu["nu2"]**2 - m1**2, 7.49e-5)))

# ---------------------------------------------------------------- charged leptons
H0 = 1/math.sqrt(2)
def Rp(cell, p): return 1/(p[0] + 2*p[1]*cell[0] + 2*cell[1])         # p = (m^2, omega)
def lnD(p): return sum(MULT(*cl)*math.log(Rp(cl, p)) for cl in CELLS)
def dd(f, i, p, h=1e-3):
    q = lambda s: f(tuple(p[k] + (s if k == i else 0) for k in range(2)))
    return (-q(2*h) + 8*q(h) - 8*q(-h) + q(-2*h))/(12*h)
P0 = (1.0, OM)
lny = {k: (lambda cs: (lambda p: lnD(p) + sum(math.log(Rp(cl, p)) for cl in cs)))(v) for k, v in READ.items()}
y_tau = lambda p: dd(lambda q: Rp((2, 2), q), 0, p)/(H0*G_PSI*dd(lnD, 0, p))
y_mu = lambda p: abs(dd(y_tau, 0, p)/dd(lny["nu3"], 0, p))
y_e = lambda p: abs(dd(y_mu, 1, p, 2e-2)/dd(lny["nu2"], 1, p, 2e-2))
R22 = Rp((2, 2), P0); R12 = Rp((1, 2), P0); R11 = Rp((1, 1), P0)
S1 = lambda w, k: sum(MULT(*cl)*(1.0 if w == 0 else 2.0*cl[0])*Rp(cl, P0)**k for cl in CELLS)
dD = [-S1(0, 1), -S1(1, 1)]; dDm = [S1(0, 2), S1(1, 2)]; dDmm = [-2*S1(0, 3), -2*S1(1, 3)]
wgt = lambda w, cl: 1.0 if w == 0 else 2.0*cl[0]
YT = R22**2/(H0*G_PSI*SIGMA_V)
s_tau = [-2*wgt(w, (2, 2))*R22 - dDm[w]/dD[0] for w in (0, 1)]
YM = YT*abs(s_tau[0]/(dD[0] - R12))
dN = [2*wgt(w, (2, 2))*R22**2 - (dDmm[w]*dD[0] - dDm[0]*dDm[w])/dD[0]**2 for w in (0, 1)]
dP = [dDm[w] + wgt(w, (1, 2))*R12**2 for w in (0, 1)]
s_mu = [s_tau[w] + dN[w]/s_tau[0] - dP[w]/(dD[0] - R12) for w in (0, 1)]
YE = YM*abs(s_mu[1]/(dD[1] - 2*R12 - 2*R11))
AHS = {"tau": 9.93780e-3, "mu": 5.85042e-4, "e": 2.77713e-6}
print("\nTable 5. Charged-lepton Yukawa couplings (closed form; direct numerical derivative in brackets)")
print("  sensitivities d ln y_tau/d(m2, omega) = %+.9f, %+.9f;  d ln y_mu/d(m2, omega) = %+.9f, %+.9f" % (s_tau[0], s_tau[1], s_mu[0], s_mu[1]))
for n, v, f in (("e", YE, y_e), ("mu", YM, y_mu), ("tau", YT, y_tau)):
    print("  y_%-4s %.9e  [%.6e]   reference %.5e at M_Z   residual %+.3f%%" % (n, v, f(P0), AHS[n], res(v, AHS[n])))
