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

Computation 122 -- F8 linearity: what the substrate side actually needs
                   (decoupling = symmetry; value = vacuum normalisation;
                    linearity controls only O(1/D))
=========================================================================
STATUS (v26.30+): the hard-research follow-up to Comp 121. Comp 121 closed
the all-orders decoupling EXACTLY, leaving F8 (H_Higgs = X_bar exactly
linear) as the one load-bearing joint on the substrate side. This
computation dismantles that worry by isolating EXACTLY what role F8's
linearity plays, and finds it is far weaker than "the whole substrate side
hangs on it".

THE DECOMPOSITION OF F8
=======================
F8 derives H_Higgs from three constraints. Trace them precisely:

  (iii) UNIFORMITY (S_D-symmetry, = P1 distinguishability). A symmetric
        function of BINARY bits depends only on the count K = sum_a B_a:
        for exchangeable binary variables the only symmetric information
        is "how many are 1". So H_Higgs = g(X_bar) for SOME function g,
        X_bar = K/D.  EXACT, no remainder.

  (i) ADDITIVITY  H = sum_a h(B_a).  But B_a in {0,1}, and ANY function of
        a single binary variable is affine: h(B) = h(0) + (h(1)-h(0)) B.
        There is no nonlinear single-bit term to have. So additive +
        uniform  ==>  g is AFFINE in X_bar, EXACTLY (no O(1/D) remainder).
        The ONLY way to get a nonlinear g is a CROSS-bit term B_a B_b
        (e.g. K^2 = sum_a B_a + 2 sum_{a<b} B_a B_b), i.e. an interaction
        between bits that P1 declares independent.

  (ii) matched scaling fixes the per-site unit 1/D (the slope/normalisation).

WHAT EACH RESULT ACTUALLY NEEDS
===============================
  - DECOUPLING / Z_Gamma4 = 1 / field-strength character (Comp 121):
    needs only H_Higgs = g(X_bar) for SOME g (sufficiency of X_bar). That
    is (iii) UNIFORMITY alone -- EXACT, P1. Linearity NOT needed. Comp 121
    already verified the factorisation for quartic and mixed g.

  - LEADING VALUE e^-1:  by the LLN, X_bar -> 1/2 a.s., so
        Z_H(beta) = E_mu[exp(-beta g(X_bar))] -> exp(-beta g(1/2)).
    This depends on g ONLY through g(1/2) (the per-site energy at the
    symmetric vacuum). With the binary-gap temperature beta = 2 (Comp 112),
    e^-1 follows from g(1/2) = 1/2 -- a single VACUUM-NORMALISATION
    condition, NOT full linearity. Linear g = X_bar gives g(1/2) = 1/2
    automatically; but ANY g with g(1/2) = 1/2 gives the same leading e^-1.

  - The finite-D O(1/D) correction depends on g'(1/2), g''(1/2): this is
    the ONLY thing linearity (g'' = 0) controls that symmetry +
    normalisation do not. It is the same substrate-limit O(1/D) caveat
    every PST quantity carries.

NET: the substrate side does NOT hinge on H_Higgs being exactly linear.
Decoupling = exact (symmetry). Leading e^-1 = vacuum normalisation
g(1/2) = 1/2 + binary gap beta = 2, robust to nonlinear deformations of g.
Linearity is the clean sufficient condition (it makes g(1/2) = 1/2
automatic AND gives the closed-form Bernoulli MGF) and controls only the
O(1/D). And linearity itself is not a free choice: it is additivity, and
additivity is P1 independence read at the level of the energy -- cross-bit
energy terms are interactions between independent distinctions.
=========================================================================
"""

import math
import numpy as np
from itertools import product


def Z_H(D, beta, g):
    """E_mu[exp(-beta g(X_bar))] exactly via the binomial multiplicity."""
    return sum(math.comb(D, k) / 2**D * math.exp(-beta * g(k / D))
               for k in range(D + 1))


def symmetric_depends_only_on_count(D):
    """Demonstrate: a generic symmetric function of binary bits is constant
    on each count-level k. Return max within-level spread for a random
    symmetric function built by symmetrising a random function."""
    rng = np.random.default_rng(0)
    # random per-config values, then symmetrise by averaging over the orbit
    # (orbit = all configs with the same count) -- trivially constant on k.
    # Instead, test the CONVERSE: build an explicitly symmetric f and show it
    # is a function of k. Use f(C) = product/sum of a symmetric polynomial.
    coeffs = rng.normal(size=4)
    levels = {}
    for C in product((0, 1), repeat=D):
        k = sum(C)
        # an arbitrary SYMMETRIC function: depends only on elementary
        # symmetric polynomials of the bits; for binary bits e_j(C) is a
        # function of k alone, so any symmetric f is a function of k.
        val = (coeffs[0] + coeffs[1] * k + coeffs[2] * k * (k - 1) / 2
               + coeffs[3] * math.comb(k, 3))
        levels.setdefault(k, []).append(val)
    return max(max(v) - min(v) for v in levels.values())


def main():
    print("=" * 72)
    print("Computation 122: what the substrate side needs of F8 linearity")
    print("=" * 72)
    print()

    e_inv = math.exp(-1.0)

    # ---- 0. symmetric function of binary bits = function of the count ------
    print("0.  UNIFORMITY (S_D) => H_Higgs = g(X_bar) for SOME g  (EXACT)")
    print("-" * 72)
    for D in (6, 10):
        spread = symmetric_depends_only_on_count(D)
        print(f"    D={D}: a symmetric function's within-count-level spread "
              f"= {spread:.1e}  -> function of k = D*X_bar alone")
    print("    Any symmetric function of binary bits depends only on the")
    print("    count. So H_Higgs = g(X_bar). This is P1 uniformity, exact;")
    print("    it is ALL the decoupling (Comp 121) needs -- not linearity.")
    print()

    # ---- 1. additive + binary => affine, exactly (no remainder) ------------
    print("1.  ADDITIVITY + BINARY BITS => g AFFINE, EXACTLY")
    print("-" * 72)
    print("    A single-bit function h(B), B in {0,1}, is h(0)+(h(1)-h(0))B,")
    print("    affine -- there is NO nonlinear single-bit term. So a SUM of")
    print("    per-site terms is affine in K=sum B_a, i.e. affine in X_bar.")
    print("    A nonlinear g needs CROSS-bit terms. Demonstrate on K^2:")
    for D in (5, 8):
        # K^2 = sum_a B_a + 2 sum_{a<b} B_a B_b  -> the cross term is forced
        rng = np.random.default_rng(1)
        C = rng.integers(0, 2, D)
        K = C.sum()
        diagonal = C.sum()                              # sum_a B_a (= K)
        cross = sum(C[a] * C[b] for a in range(D) for b in range(a + 1, D))
        print(f"    D={D}: K^2={K**2}, (sum B_a) + 2*(sum_{{a<b}}B_aB_b) = "
              f"{diagonal + 2*cross}  -> match={K**2 == diagonal + 2*cross}")
    print("    => nonlinear-in-X_bar  <=>  cross-bit interaction terms,")
    print("       which P1 (independent distinctions) forbids at the energy.")
    print()

    # ---- 2. leading value depends on g ONLY through g(1/2) ------------------
    print("2.  LEADING VALUE  Z_H(beta=2) -> exp(-2 g(1/2)),  NOT linearity")
    print("-" * 72)
    beta = 2.0
    # several g, all with g(1/2) = 1/2 (linear + nonlinear deformations)
    gs_norm = {
        "linear      x":          lambda x: x,
        "quad-deform x+0.8(x-.5)^2": lambda x: x + 0.8 * (x - 0.5) ** 2,
        "cubic-def   x+1.5(x-.5)^3": lambda x: x + 1.5 * (x - 0.5) ** 3,
        "tanh-ish":               lambda x: 0.5 + 0.5 * math.tanh(3 * (x - 0.5)) / math.tanh(1.5),
    }
    print("    g's chosen with g(1/2)=1/2 (linear AND nonlinear):")
    print(f"      {'g':>26} {'g(1/2)':>8} {'Z_H(D=2000)':>14} {'->e^-1?':>9}")
    for name, g in gs_norm.items():
        z = Z_H(2000, beta, g)
        print(f"      {name:>26} {g(0.5):>8.4f} {z:>14.8f} "
              f"{'yes' if abs(z - e_inv) < 5e-3 else 'NO':>9}")
    print(f"      (e^-1 = {e_inv:.8f})")
    print("    All g with g(1/2)=1/2 -> e^-1 to leading order, linear or not.")
    print()
    print("    The nonlinear-vs-linear difference is O(1/D):")
    g_lin = lambda x: x
    g_nl = lambda x: x + 0.8 * (x - 0.5) ** 2
    print(f"      {'D':>6} {'|Z_nl - Z_lin|':>16} {'diff*D':>10}")
    for D in (20, 100, 500, 2500):
        d = abs(Z_H(D, beta, g_nl) - Z_H(D, beta, g_lin))
        print(f"      {D:>6} {d:>16.3e} {d*D:>10.4f}")
    print("    diff*D -> const: linearity controls only the O(1/D) term.")
    print()

    # ---- 3. the load-bearing knob is g(1/2), not linearity -----------------
    print("3.  THE LOAD-BEARING CONDITION IS g(1/2)=1/2 (VACUUM NORM.)")
    print("-" * 72)
    print("    Sweep a LINEAR g = s*x with different vacuum values g(1/2)=s/2;")
    print("    the value tracks exp(-2 g(1/2)), away from e^-1 unless g(1/2)=1/2:")
    print(f"      {'slope s':>8} {'g(1/2)':>8} {'Z_H(D=2000)':>14} "
          f"{'exp(-2 g(1/2))':>15}")
    for s in (0.6, 0.8, 1.0, 1.2, 1.4):
        g = lambda x, s=s: s * x
        z = Z_H(2000, beta, g)
        print(f"      {s:>8.2f} {s/2:>8.3f} {z:>14.8f} "
              f"{math.exp(-2*s/2):>15.8f}")
    print("    Value = exp(-2 g(1/2)) exactly in the limit. e^-1 <=> g(1/2)=1/2.")
    print("    Linear g=X_bar gives g(1/2)=1/2 automatically (= site-mean).")
    print()

    # ---- 4. assessment ------------------------------------------------------
    print("=" * 72)
    print("ASSESSMENT: F8 linearity is not the load-bearing joint feared")
    print("=" * 72)
    print()
    print("  - DECOUPLING (Comp 121): needs only H_Higgs = g(X_bar), i.e. P1")
    print("    UNIFORMITY (S_D-symmetry). EXACT, no linearity. The whole")
    print("    Z_Gamma4 = 1 / field-strength result is unconditional on F8's")
    print("    linearity.")
    print("  - LEADING VALUE e^-1: = exp(-beta g(1/2)) with beta = 2 (binary")
    print("    gap, Comp 112). Needs only the VACUUM NORMALISATION g(1/2)=1/2,")
    print("    robust to nonlinear deformations of g. Linear H_Higgs gives")
    print("    g(1/2)=1/2 automatically (the mean of X_bar is the site-mean).")
    print("  - LINEARITY controls ONLY the O(1/D) correction to the value --")
    print("    the same substrate-limit caveat every PST quantity carries.")
    print("  - And linearity is not a free choice: additive + binary = affine")
    print("    EXACTLY; a nonlinear g requires cross-bit terms B_a B_b, which")
    print("    are interactions between P1-independent distinctions. Additivity")
    print("    is P1 independence read at the level of the energy.")
    print()
    print("  NET: the substrate-side closure of (B) does not hinge on H_Higgs")
    print("  being exactly linear. Its structure (decoupling) is exact from")
    print("  symmetry; its value (e^-1) needs a vacuum normalisation + the")
    print("  binary-gap temperature; linearity, itself the energy-level form")
    print("  of P1 independence, refines only the O(1/D). The F8 joint flagged")
    print("  after Comp 121 bears far less weight than 'the whole thing hangs")
    print("  on exact linearity' -- it is a robustness statement, not a gap.")


if __name__ == "__main__":
    main()
