"""v99 -- Koide flow time: canonical generator, m_tau data-fragility, and the
conditional discrete-step prediction.  [I] generator + [N] sensitivity +
[P] conditional m_tau values.  Corrects the ROBUSTNESS of one v93 negative.

v93 (FR.KOIDE.05) recorded the honest negative "flow time t = 2.838 is not
an integer => literal discrete iteration pole = F^n(source) EXCLUDED; the
missing P2 object is a continuous-time generator".  This script does three
things to that statement:

  [I] 1. THE CONTINUOUS GENERATOR HAS A CANONICAL FORM.  The v82 flow
         rho -> mu^t rho is generated by the autonomous ODE
             dq/dt = (Delta/N_fam) * (q-2)(q-5) = (Delta/N_fam) * det B(q),
         with Delta = 6 log(3/2) the established transfer gap and
         (q-2)(q-5) = det B(K+xQ) in the branch coordinate q = -3x.
         The time-1 map of this flow IS the v82 Moebius map F (machine-
         checked).  So the missing P2 object is precisely a QFT mechanism
         producing "gap x anchor-block quadric / family count" -- the form
         is canonical, only its physical derivation is open.
  [N] 2. THE NON-INTEGRALITY OF t IS DATA-FRAGILE (correction of v93's
         robustness, not of its arithmetic).  rho_pole = -2.2e-6 sits so
         close to the branch point that t is hypersensitive to m_tau
         (PDG 1776.93 +- 0.09 MeV): t(-1 sigma) = 2.35, t(central) = 2.84,
         and Q crosses 2/3 INSIDE the error band (at about +0.46 sigma),
         where t -> infinity.  Within +0.5 sigma, t passes through EVERY
         integer >= 3.  The v93 exclusion of pole = F^n(source) therefore
         holds only at the central value -- it is NOT robust.
  [P] 3. CONDITIONAL DISCRETE-STEP PREDICTIONS (registry untouched; these
         are typed conditional, NOT predictions of record):
             pole = F^2(source):  m_tau = 1776.6690 MeV  (-2.9 sigma,
                                  EXCLUDED by current data [N]);
             pole = F^3(source):  m_tau = 1776.9427 MeV  (+0.14 sigma) --
                                  n = 3 = N_fam steps, one per family;
             pole = F^4(source):  m_tau = 1776.9667 MeV  (+0.41 sigma);
             Q = 2/3 exactly:     m_tau = 1776.9690 MeV  (+0.43 sigma).
         Current data cannot separate n = 3 / n = 4 / exact-branch; the
         decision needs sigma(m_tau) ~ 0.01 MeV (Belle II).  The n = 3
         value is stable under the source variant (exact ladder vs the
         -phi0/24 conjecture: shift 0.0002 MeV).
  [I] 4. LOOK-ELSEWHERE FIREWALL (documented destroyed candidate): a scale
         reading t = ln(M_scal/m_tau)/ln(W) matched W = 46080 = |W(D5)|x
         |W(A3)| to 1e-4 -- but the SAME hypersensitivity makes the
         self-consistent m_tau land within 0.1 sigma for ANY W in a wide
         range (negative controls W = 40320, 51840 both give pulls < 0.04
         sigma).  The t-scale reading carries no information at current
         m_tau precision; the candidate is REJECTED and recorded so it is
         not re-fished.

STATUS: P2 unchanged in type ([P], one identification) but sharper on both
ends: the generator form is canonical [I], and the discrete/continuous
dichotomy is now an EXPERIMENTAL question (m_tau at 0.01 MeV) rather than a
settled negative.
"""
import mpmath as mp

from tfpt_constants import check, summary, reset, phi0, N_fam, c3, Mbar

# PDG 2024 pole masses (MeV)
M_E, M_MU = mp.mpf('0.51099895069'), mp.mpf('105.6583755')
MTAU, SIG_MTAU = mp.mpf('1776.93'), mp.mpf('0.09')
MU_RATE = (mp.mpf(2) / 3)**6
DELTA = 6 * mp.log(mp.mpf(3) / 2)


def koide(a, b, c):
    return (a + b + c) / (mp.sqrt(a) + mp.sqrt(b) + mp.sqrt(c))**2


def rho(q):
    return (q - 2) / (5 - q)


def F(q):
    return 2 * (569 * q - 3325) / (665 * q - 3517)


def q_of_rho(r):
    return (2 + 5 * r) / (1 + r)


def source_rho():
    me = mp.mpf(16) / 7 * phi0**5
    mmu = mp.mpf(4) / 3 * phi0**3
    mtau = mp.mpf(7) / 6 * phi0**2
    return rho(N_fam * koide(me, mmu, mtau))


def t_flow(mtau):
    return mp.log(rho(N_fam * koide(M_E, M_MU, mtau)) / source_rho()) \
        / mp.log(MU_RATE)


def mtau_for_rho(r_target):
    q_target = q_of_rho(r_target) / N_fam
    return mp.findroot(lambda m: koide(M_E, M_MU, m) - q_target,
                       mp.mpf('1776.94'))


def run():
    reset()
    mp.mp.dps = 40
    print("v99 Koide flow time (generator, m_tau fragility, conditional steps)")

    # 1. canonical generator: dq/dt = (Delta/N_fam)(q-2)(q-5); time-1 map = F
    def flow_time1(q0):
        f = lambda t_, q: [(DELTA / N_fam) * (q[0] - 2) * (q[0] - 5)]
        return mp.odefun(f, 0, [q0])(1)[0]
    probes = [mp.mpf('1.2'), mp.mpf('1.9939'), mp.mpf('2.7')]
    check("CANONICAL GENERATOR [I]: the time-1 map of dq/dt = "
          "(Delta/N_fam)(q-2)(q-5) = (Delta/N_fam) det B(q) IS the v82 "
          "Moebius map F (3 probe points, 1e-12)",
          all(abs(flow_time1(q0) - F(q0)) < mp.mpf('1e-12')
              for q0 in probes))
    check("(equivalently: rho(t) = e^{-Delta t} rho(0); e^{-Delta} = "
          "(2/3)^6 = mu exactly)",
          abs(mp.e**(-DELTA) - MU_RATE) < mp.mpf('1e-35'))

    # 2. data fragility of the flow time
    check("flow time at the PDG central value: t = 2.8385 (v93 import)",
          t_flow(MTAU), mp.mpf('2.838456'), tol=mp.mpf('1e-5'))
    check("DATA-FRAGILE [N]: t(-1 sigma) = 2.347, t(-0.5 sigma) = 2.523 "
          "-- t moves by ~0.5 steps within one sigma of m_tau",
          abs(t_flow(MTAU - SIG_MTAU) - mp.mpf('2.34693')) < mp.mpf('1e-4')
          and abs(t_flow(MTAU - SIG_MTAU / 2) - mp.mpf('2.52323'))
          < mp.mpf('1e-4'))
    m_branch = mtau_for_rho(mp.mpf(0))
    pull_branch = (m_branch - MTAU) / SIG_MTAU
    check("Q crosses 2/3 INSIDE the error band: at m_tau = 1776.9690 MeV "
          "= +0.43 sigma (there t -> infinity; within +0.5 sigma t passes "
          "every integer >= 3) => the v93 exclusion of pole = F^n(source) "
          "is NOT robust",
          pull_branch, mp.mpf('0.4337'), tol=mp.mpf('1e-3'))

    # 3. conditional discrete-step values (typed [P]; registry untouched)
    r_src = source_rho()
    preds = {n: mtau_for_rho(r_src * MU_RATE**n) for n in (2, 3, 4)}
    pulls = {n: (preds[n] - MTAU) / SIG_MTAU for n in preds}
    check("pole = F^2(source) EXCLUDED [N]: m_tau = 1776.6690 MeV = "
          "-2.9 sigma",
          pulls[2], mp.mpf('-2.900'), tol=mp.mpf('1e-2'))
    check("CONDITIONAL [P]: pole = F^3(source) (n = 3 = N_fam steps, one "
          "per family) predicts m_tau = 1776.9427 MeV (+0.14 sigma)",
          preds[3], mp.mpf('1776.94268'), tol=mp.mpf('1e-7'))
    check("neighbours not separable yet: n = 4 gives 1776.9667 (+0.41 "
          "sigma), exact branch 1776.9690 (+0.43 sigma); decision needs "
          "sigma(m_tau) ~ 0.01 MeV (Belle II) -- the kill criterion",
          abs(pulls[4] - mp.mpf('0.408')) < mp.mpf('1e-2')
          and abs(preds[4] - m_branch) < mp.mpf('0.01') * 3)
    me_alt = mtau_for_rho(-phi0 / 24 * MU_RATE**3)
    check("n = 3 value is source-variant stable: -phi0/24 source shifts it "
          "by only 0.0002 MeV",
          abs(me_alt - preds[3]) < mp.mpf('0.001'))

    # 4. look-elsewhere firewall
    Mscal = c3**mp.mpf('3.5') * Mbar          # GeV
    def mtau_scale_reading(W):
        f = lambda m: t_flow(m) - mp.log(Mscal / (m / 1000)) / mp.log(W)
        return mp.findroot(f, mp.mpf('1776.93'))
    pulls_W = {W: (mtau_scale_reading(mp.mpf(W)) - MTAU) / SIG_MTAU
               for W in (46080, 40320, 51840)}
    check("FIREWALL [I/N]: the scale reading t = ln(M_scal/m_tau)/ln(W) is "
          "destroyed by negative controls -- W = 46080, 40320, 51840 ALL "
          "give |pull| < 0.1 sigma (the t-reading carries no information "
          "at current m_tau precision; candidate REJECTED, not re-fished)",
          all(abs(mp.re(p)) < mp.mpf('0.1') for p in pulls_W.values()))

    check("STATUS: P2 type unchanged ([P], one identification); generator "
          "form canonical [I]; discrete-vs-continuous now an EXPERIMENTAL "
          "question (m_tau at 0.01 MeV), not a settled negative; freeze "
          "registry untouched", True)

    return summary("v99 Koide flow time")


if __name__ == "__main__":
    raise SystemExit(1 if run() else 0)
