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

SCOPE NOTE, 2026-10-10 (comp 201).  The dependency graph below has one free node, d_0,
because it does not include eq:xi_psi, the book's own definition of d_0 as the
Landau-Ginzburg coherence length sqrt(c_LG / (2 |a_LG|)) with |a_LG| = m_h^2 / 4.  With
that edge the gradient normalisation and d_0 are one unknown, and under the canonical
reading of sec:ch-normalisation d_0 = sqrt(2) hbar c / m_h = 2.2 am: "closes only if d_0 is
predicted" was already met.  At that d_0 the derived-unit coefficient is
kappa = m_h^2 / (2 v^2) = 0.13, order one.  Every number below is at the Casimir bound
and stands as such.

Computation 197 -- the normalisation item with r_0 = v: one unknown length, and the
derived-unit route is not an O(1) route
=================================================================================
WHAT THIS DOES.  The third structural item (sec:open-structural) is a value for the
composite K = c-tilde d_0^2 / 16 that the Mosco limit maps P3's gradient coefficient
onto (comp 177), and comp 194 added that the unit of orbital angular momentum is this
normalisation's: r_0^2 d_0^2 / c is the unique action monomial the Goldstone sector
supplies, so a derived unit hbar = kappa r_0^2 d_0^2 / c would fix r_0^2 absolutely.
comp 194 then illustrated with "m_0 c^2 = 3.5 keV / kappa at the Casimir bound",
which treats r_0 as free and kappa as a number of order one.

THE BOOK DOES NOT LEAVE r_0 FREE.  Three places identify r_0 = v = 246 GeV, the
electroweak vacuum: the sentence after eq:G-closed, the dimensional note that follows
it, and sec:c-dimensional-chain.  With that identification the unit relation is not a
relation between two unknowns but a value for kappa, and this file computes it.

RESULT 1 -- THE DERIVED-UNIT COEFFICIENT IS 1.2e-19 AT THE CASIMIR BOUND.  With
r_0 = v, hbar = kappa v^2 d_0^2 / c reads kappa = hbar c / (v^2 d_0^2), which at
d_0 = 2.3 nm is 1.2e-19.  kappa = 1 needs d_0 = hbar c / v = 0.80 am, nine orders of
magnitude below the Casimir bound.  So the derived-unit route to K cannot close the
item with an O(1) coefficient at any admissible d_0 near the bound; it is a route only
if d_0 is predicted first.  That narrows what closes the item to d_0 alone.

RESULT 2 -- THE ILLUSTRATION CORRECTED.  comp 194's "3.5 keV / kappa" is arithmetic
that still holds as a formula, but with kappa = 1.2e-19 it is 2.9e13 GeV: the book's
own eq:pst-mass, m_0 = (4 pi^3 / 3) r_0^2 d_0 / c^2, evaluated at r_0 = v and
d_0 = 2.3 nm.  m_0 is linear in d_0, so it is (4 pi^3 / 3) v = 10.2 TeV exactly when
kappa = 1 and d_0 = hbar c / v.  The book calls eq:pst-mass a dimensional scale and
not a particle mass, and these numbers show why: at the Casimir bound it is 10^11
times the electroweak scale.  Appendix B's entry for comp 194 and the item's unit
sentence are corrected in the same cut as this file.

RESULT 3 -- THE DEPENDENCY GRAPH HAS ONE FREE NODE.  The sector's parameters are
v and m_h (measured), epsilon = m_h^2 / 4 (eq:radial-mass), the dimensionless quartic
b = epsilon / (2 v^2) = m_h^2 / (8 v^2) (eq:vacmanifold with r_0 = v), d_0 (bounded by
Casimir, not predicted), and the gradient coupling c, which eq:G-closed fixes from
d_0 and G: c = 6 pi d_0^2 / (G v^2), of dimension [M]^-2 as the dimensional note
says, and proportional to d_0^2.  K is a function of c and d_0 (comp 177).  Every
edge is an identity of the book, and the one node with no incoming edge is d_0.
The two routes that were named for fixing K without d_0, the Mosco limit (comp 177,
negative) and the derived unit (this file, not O(1)), both end at the same node.

CHECKS.  (1) Dimensions on (M, L, T): kappa = hbar c / (v^2 d_0^2) is dimensionless;
c = 6 pi d_0^2 / (G v^2) carries [M]^-2 in natural units.  (2) kappa at the bound,
the d_0 at which kappa = 1, and m_0 at both.  (3) m_0 is linear in d_0; its value at
the bound and at kappa = 1, and the d_0 at which it would equal 1 TeV.  (4) The
graph: a topological order of the dependency graph with exactly one source, d_0,
once v and m_h are given, computed by hand and checked by code.  (5) Tamper: with
r_0 left free (comp 194's implicit reading) the relation is one equation in two
unknowns and kappa is unconstrained; the reading the book takes removes that freedom.
"""

import math
import sympy as sp

HBARC_GEV_M = 1.973269804e-16   # hbar c in GeV m
V_GEV = 246.22                  # electroweak vacuum, r_0 = v
MH_GEV = 125.25
MPL_GEV = 1.220890e19           # Planck mass, G = 1 / M_P^2 in natural units
D0_M = 2.3e-9                   # Casimir bound of Chapter 15


def part1():
    print("  PART 1.  Dimensions, on (M, L, T) with [hbar] = M L^2 T^-1, [c] = L T^-1")
    M, L, T = sp.symbols('M L T', positive=True)
    hbar = M * L ** 2 / T
    c = L / T
    v2 = M * L ** 2 / T ** 2 / L     # r_0^2 is an energy per length (eq:mass-integral), as comp 194 checked
    d0 = L
    kappa = sp.simplify(hbar * c / (v2 * d0 ** 2))
    ok = kappa == 1
    print(f"      [hbar c / (r_0^2 d_0^2)] = {kappa}  (dimensionless)                             : {ok}")
    # natural units: G ~ M^-2, d_0 ~ M^-1, v ~ M  =>  c = 6 pi d_0^2 / (G v^2) ~ M^-2
    Mn = sp.symbols('M_nat', positive=True)
    c_dim = sp.simplify((Mn ** -1) ** 2 / (Mn ** -2 * Mn ** 2))
    ok2 = c_dim == Mn ** -2
    print(f"      [6 pi d_0^2 / (G v^2)] = {c_dim} in natural units, as the dimensional note after eq:G-closed says : {ok2}")
    return ok and ok2


def kappa_of(d0_m):
    d0 = d0_m / HBARC_GEV_M          # GeV^-1
    return 1.0 / (V_GEV ** 2 * d0 ** 2)


def m0_gev(d0_m):
    """eq:pst-mass with r_0 = v, in GeV: (4 pi^3 / 3) v^2 d_0 / (hbar c)."""
    return (4 * math.pi ** 3 / 3) * V_GEV ** 2 * d0_m / HBARC_GEV_M


def part2():
    print("  PART 2.  The derived-unit coefficient with r_0 = v")
    ok = True
    k_bound = kappa_of(D0_M)
    print(f"      kappa = hbar c / (v^2 d_0^2) at d_0 = 2.3 nm = {k_bound:.3e}")
    ok &= 1.0e-19 < k_bound < 1.4e-19
    d0_unit = HBARC_GEV_M / V_GEV
    print(f"      kappa = 1 at d_0 = hbar c / v = {d0_unit:.3e} m = {d0_unit * 1e18:.2f} am, {D0_M / d0_unit:.1e} below the Casimir bound")
    ok &= abs(kappa_of(d0_unit) - 1) < 1e-12
    m0_bound, m0_unit = m0_gev(D0_M), m0_gev(d0_unit)
    print(f"      m_0 = (4 pi^3/3) v^2 d_0 / (hbar c): {m0_bound:.2e} GeV at the bound, {m0_unit / 1e3:.2f} TeV at kappa = 1 (= (4 pi^3/3) v)")
    ok &= abs(m0_unit - (4 * math.pi ** 3 / 3) * V_GEV) < 1e-6 and 2.5e13 < m0_bound < 3.5e13
    # comp 194's number: (4 pi^3/3) hbar c / d_0 at the bound, in keV, times 1/kappa
    keV_over_kappa = (4 * math.pi ** 3 / 3) * HBARC_GEV_M / D0_M * 1e6     # keV
    print(f"      comp 194's illustration (4 pi^3/3) hbar c / d_0 = {keV_over_kappa:.2f} keV / kappa; divided by kappa = {k_bound:.2e} it is {keV_over_kappa * 1e-6 / k_bound:.2e} GeV, which is m_0 above : {abs(keV_over_kappa * 1e-6 / k_bound - m0_bound) / m0_bound < 1e-9}")
    ok &= abs(keV_over_kappa * 1e-6 / k_bound - m0_bound) / m0_bound < 1e-9
    d0_TeV = 1e3 / ((4 * math.pi ** 3 / 3) * V_GEV ** 2) * HBARC_GEV_M
    print(f"      m_0 is linear in d_0; m_0 = 1 TeV would need d_0 = {d0_TeV:.1e} m")
    ok &= abs(m0_gev(d0_TeV) - 1e3) < 1e-6
    print("      => the derived unit is not an O(1) route at any d_0 near the bound; it closes K only if d_0 is predicted.")
    return ok


def part3():
    print("  PART 3.  The dependency graph of K")
    G = 1.0 / MPL_GEV ** 2
    d0 = D0_M / HBARC_GEV_M
    c_coupling = 6 * math.pi * d0 ** 2 / (G * V_GEV ** 2)
    eps = MH_GEV ** 2 / 4
    b = eps / (2 * V_GEV ** 2)
    print(f"      measured: v = {V_GEV} GeV, m_h = {MH_GEV} GeV, G = {G:.3e} GeV^-2")
    print(f"      epsilon = m_h^2/4 = {eps:.1f} GeV^2 (eq:radial-mass);  b = epsilon/(2 v^2) = {b:.4f} (eq:vacmanifold at r_0 = v)")
    print(f"      c = 6 pi d_0^2/(G v^2) = {c_coupling:.2e} GeV^-2 at the Casimir bound, proportional to d_0^2 (eq:G-closed)")
    edges = {           # node: the nodes it is computed from
        'v': set(), 'm_h': set(), 'G': set(), 'd_0': set(),
        'epsilon': {'m_h'}, 'b': {'epsilon', 'v'},
        'c': {'d_0', 'G', 'v'}, 'K': {'c', 'd_0'}, 'kappa': {'v', 'd_0'}, 'm_0': {'v', 'd_0'},
    }
    given = {'v', 'm_h', 'G'}
    sources = sorted(n for n, deps in edges.items() if not deps and n not in given)
    def leaves(n):
        return {n} if not edges[n] else set().union(*(leaves(m) for m in edges[n]))
    measured_only = sorted(n for n in edges if n not in given and n != 'd_0' and leaves(n) <= given)
    need_d0 = sorted(n for n in edges if n not in given and n != 'd_0' and 'd_0' in leaves(n))
    stray = sorted(n for n in edges if not (leaves(n) <= given | {'d_0'}))
    ok = sources == ['d_0'] and stray == [] and need_d0 == ['K', 'c', 'kappa', 'm_0']
    print(f"      nodes with no incoming edge, v, m_h and G given: {sources}")
    print(f"      fixed by the measured inputs alone: {measured_only};  hanging on d_0: {need_d0};  on anything else: {stray}")
    print(f"      => one free node, d_0; K, c, kappa and m_0 all hang on it                    : {ok}")
    ok2 = 0.031 < b < 0.034 and c_coupling > 0
    return ok and ok2


def part4():
    print("  PART 4.  Tamper: leave r_0 free, as comp 194's illustration did")
    r0sq, d0, kappa, hbar, c = sp.symbols('r_0^2 d_0 kappa hbar c', positive=True)
    rel = sp.Eq(hbar, kappa * r0sq * d0 ** 2 / c)
    free = sp.solve(rel, kappa)[0]
    # with r_0 free, kappa is any positive number: pick two r_0^2 and get two kappa
    k1 = free.subs({r0sq: 1, d0: 1, hbar: 1, c: 1})
    k2 = free.subs({r0sq: 1e-19, d0: 1, hbar: 1, c: 1})
    ok = k1 != k2
    print(f"      kappa = hbar c / (r_0^2 d_0^2): with r_0^2 unfixed, kappa takes any value (two samples: {k1}, {k2:.0e}) : {ok}")
    print("      the book fixes r_0 = v (eq:G-closed, its dimensional note, sec:c-dimensional-chain), which is what turns the relation into Part 2's number.")
    return ok


def main():
    print("=" * 78)
    print("  COMPUTATION 197.  The normalisation item with r_0 = v: one unknown length")
    print("=" * 78)
    results = [
        ("dimensions: kappa dimensionless, c of dimension [M]^-2", part1()),
        ("kappa = 1.2e-19 at the Casimir bound; kappa = 1 at d_0 = 0.80 am; m_0 = 2.9e13 GeV at the bound, 10.2 TeV at kappa = 1", part2()),
        ("the dependency graph of K has one free node, d_0", part3()),
        ("tamper: with r_0 free the coefficient is unconstrained, which is the reading comp 194 took", part4()),
    ]
    print("-" * 78)
    for i, (name, r) in enumerate(results, 1):
        print(f"  {i}. {name}: {'PASS' if r else 'FAIL'}")
    allok = all(r for _, r in results)
    print("-" * 78)
    print("  VERDICT:", "PASS" if allok else "FAIL")
    print("""
  With r_0 = v, as the book has it, the derived unit of angular momentum carries the
  coefficient 1.2e-19 at the Casimir bound and is of order one only at d_0 = 0.80 am;
  comp 194's "3.5 keV / kappa" is 2.9e13 GeV at face value and is corrected.  The
  item's dependency graph has one free node, d_0.  The item stays open, as an
  assumption, and what closes it is now one thing: a prediction of d_0.""")
    return allok


if __name__ == "__main__":
    main()
