"""Sprints 16-17: The Third Dimension and Cross-Dimensional Bridges (Theorems CD-CM).

Extracted from bridges.py for module restructure (v2.0).
"""

import math
from typing import Dict

import numpy as np

from .constants import (
    PHI, PHI_INV, T_STAR, T_STAR3, LAM_STAR, KAP_STAR, ETA_STAR,
    F_STAR, MU_SLOW, MU_FAST, RHO_STAR,
)
from .bridges import root_system_conservation, _free_energy
from .cascade import an_bcc_eigenvalues, bn_bcc_formula, cn_bcc_formula, dn_bcc_formula

# =============================================================================
# SPRINT 16: The Third Dimension (CD-CH)
# =============================================================================


def three_simplex_free_energy() -> Dict:
    """Define the 3-simplex free energy and Z3 equilibrium.

    Theorem CD (3-Simplex Free Energy Foundation):
    On the 3-simplex (lambda + kappa + eta_s + eta_d = 1), the Watkins
    free energy generalises to:

        F4 = -ln(lambda) + T3 * sum(p_i * ln(p_i))

    where T3 = phi/ln(3*phi) ≈ 1.024 is the 3-simplex critical
    temperature (LOWER than the 2-simplex T* ≈ 1.378).

    The Z3-symmetric equilibrium (kappa = eta_s = eta_d = rho*) has:
        rho* = (1 - 1/phi) / 3 ≈ 0.127
        F3* ≈ -0.630  (higher than 2-simplex F2* ≈ -0.800)

    The third dimension RAISES the equilibrium free energy: adding
    a degree of freedom makes the system less tightly bound.

    Returns:
        Dict with 3-simplex free energy analysis.
    """
    T3 = T_STAR3
    rho = RHO_STAR
    lam = LAM_STAR

    # 3-simplex free energy at Z3 equilibrium
    F3_star = (-math.log(lam)
               + T3 * (lam * math.log(lam)
                       + 3 * rho * math.log(rho)))

    # 2-simplex free energy for comparison
    F2_star = F_STAR

    # Temperature ratio
    T_ratio = T3 / T_STAR

    # Verify conservation
    conservation = lam + 3 * rho

    return {
        'T3': T3,
        'T_ratio': T_ratio,
        'lambda_star': lam,
        'rho_star': rho,
        'F3_star': F3_star,
        'F2_star': F2_star,
        'F_difference': F3_star - F2_star,
        'F3_above_F2': F3_star > F2_star,
        'conservation': conservation,
        'conservation_exact': abs(conservation - 1.0) < 1e-12,
    }


def three_simplex_hessian() -> Dict:
    """Compute the 3-simplex Hessian eigenvalues and modes.

    Theorem CE (3-Simplex Hessian Spectrum):
    At the Z3 equilibrium, the ambient Hessian is diag(A, C, C, C) where:
        A = 1/lambda*^2 + T3/lambda*  ≈ 4.275  (coherence self-interaction)
        C = T3/rho*                    ≈ 8.044  (non-lambda self-interaction)

    The RIEMANNIAN eigenvalues (intrinsic to the 3-simplex tangent plane)
    are:
        mu_coherence = (3A + C) / 4   ≈ 5.217  (SLOWEST — non-degenerate)
        mu_exchange   = C = T3/rho*   ≈ 8.044  (DOUBLY DEGENERATE)

    The exchange mode eigenvectors (0, 1, -1, 0) and (0, 0, 1, -1)
    govern how fast kappa, eta_s, eta_d equilibrate AMONG THEMSELVES.
    This mode has NO 2-simplex analogue — it is BORN in the third
    dimension.

    The coherence mode eigenvector (3, -1, -1, -1)/sqrt(12) governs
    how fast lambda adjusts relative to the others.  It is the SLOWEST
    mode, meaning coherence is the last quantity to equilibrate.

    Returns:
        Dict with Hessian spectrum analysis.
    """
    T3 = T_STAR3
    lam = LAM_STAR
    rho = RHO_STAR

    A = 1 / lam ** 2 + T3 / lam
    C = T3 / rho

    # Riemannian eigenvalues (closed forms)
    mu_coherence = (3 * A + C) / 4
    mu_exchange = C

    # Timescales
    tau_coherence = 1 / mu_coherence
    tau_exchange = 1 / mu_exchange

    # Coordinate eigenvalues (reduced Hessian)
    H11 = 1 / lam ** 2 + T3 / lam + T3 / rho
    H22 = T3 / rho + T3 / rho
    H12 = T3 / rho
    H_red = np.array([
        [H11, H12, H12],
        [H12, H22, H12],
        [H12, H12, H22]
    ])
    coord_eigs = sorted(np.linalg.eigvals(H_red).real)

    return {
        'A': A,
        'C': C,
        'mu_coherence': mu_coherence,
        'mu_exchange': mu_exchange,
        'tau_coherence': tau_coherence,
        'tau_exchange': tau_exchange,
        'exchange_degenerate': True,  # by Z3 symmetry
        'coherence_slowest': mu_coherence < mu_exchange,
        'scale_separation': mu_exchange / mu_coherence,
        'coordinate_eigenvalues': coord_eigs,
    }


def dimensional_reduction_map() -> Dict:
    """Show how the 2-simplex embeds in the 3-simplex.

    Theorem CF (Dimensional Reduction Map):
    Constraining eta_s = eta_d on the 3-simplex recovers a 2-simplex
    with effective parameters:

        eta_eff = eta_s + eta_d = 2 * rho* = 2(1 - lambda*)/3

    The key ratio kappa_3 / kappa_2 = rho* / kap* = 2/3 EXACTLY.
    This is the same 2/3 that appears as F4's Bloch-Wigner volume ratio!

    Temperature shift: T3 / T* = ln(2*phi) / ln(3*phi) ≈ 0.743.
    The 3-simplex is COOLER — adding dimensions lowers the
    critical temperature.

    The generalised temperature formula T_n = phi / ln(n*phi) gives
    a monotonically decreasing sequence T1 > T2 > T3 > ... with
    T_infinity -> 0.

    Returns:
        Dict with dimensional reduction analysis.
    """
    rho = RHO_STAR
    kap2 = KAP_STAR

    kap_ratio = rho / kap2  # Should be 2/3
    T_ratio = T_STAR3 / T_STAR

    # Generalised temperature sequence
    temps = []
    for n in range(1, 8):
        T_n = PHI / math.log(n * PHI)
        temps.append({'n': n, 'T_n': T_n})

    temp_decreasing = all(temps[i]['T_n'] > temps[i + 1]['T_n']
                          for i in range(len(temps) - 1))

    # Eta effective in reduced 2-simplex
    eta_eff = 2 * rho

    return {
        'kappa_2simplex': kap2,
        'kappa_3simplex': rho,
        'kappa_ratio': kap_ratio,
        'kappa_ratio_is_two_thirds': abs(kap_ratio - 2 / 3) < 1e-12,
        'eta_effective': eta_eff,
        'T_ratio': T_ratio,
        'temperature_sequence': temps,
        'temperature_decreasing': temp_decreasing,
    }


def three_simplex_flow(dt: float = 0.001, max_steps: int = 10000,
                       convergence_tol: float = 1e-6) -> Dict:
    """Gradient flow on the 3-simplex converges to Z3 equilibrium.

    Theorem CG (3-Simplex Gradient Flow):
    Starting from an ASYMMETRIC point on the 3-simplex where
    kappa ≠ eta_s ≠ eta_d, the Watkins gradient flow converges to
    the Z3-symmetric golden equilibrium (lambda*, rho*, rho*, rho*).

    The flow exhibits TWO-PHASE dynamics analogous to BV:

    Phase 1 (Internal Equilibration): kappa, eta_s, eta_d rapidly
        equilibrate among themselves at rate mu_exchange ≈ 8.044.
        The system achieves Z3 symmetry (kap ≈ eta_s ≈ eta_d) quickly.

    Phase 2 (Coherence Tuning): lambda slowly adjusts toward lambda*
        at rate mu_coherence ≈ 5.217.  This is the bottleneck.

    The scale separation mu_exchange / mu_coherence ≈ 1.54 means
    the internal modes equilibrate ~50% faster than coherence.

    Returns:
        Dict with 3-simplex flow analysis.
    """
    T3 = T_STAR3
    rho = RHO_STAR

    # Start from asymmetric point
    lam, kap, eta_s, eta_d = 0.55, 0.20, 0.15, 0.10

    z3_threshold = 1e-4  # When is Z3 symmetry achieved?
    z3_step = None
    converge_step = None

    for step in range(max_steps):
        eps = 1e-15
        g_l = -1 / max(lam, eps) + T3 * (math.log(max(lam, eps)) + 1)
        g_k = T3 * (math.log(max(kap, eps)) + 1)
        g_s = T3 * (math.log(max(eta_s, eps)) + 1)
        g_d = T3 * (math.log(max(eta_d, eps)) + 1)
        mean_g = (g_l + g_k + g_s + g_d) / 4

        ng_l = g_l - mean_g
        ng_k = g_k - mean_g
        ng_s = g_s - mean_g
        ng_d = g_d - mean_g

        grad_norm = math.sqrt(ng_l ** 2 + ng_k ** 2 + ng_s ** 2 + ng_d ** 2)

        # Check Z3 symmetry
        max_asym = max(abs(kap - eta_s), abs(eta_s - eta_d), abs(kap - eta_d))
        if z3_step is None and max_asym < z3_threshold:
            z3_step = step

        if grad_norm < convergence_tol:
            converge_step = step
            break

        lam -= dt * ng_l
        kap -= dt * ng_k
        eta_s -= dt * ng_s
        eta_d -= dt * ng_d

        lam = max(lam, 1e-12)
        kap = max(kap, 1e-12)
        eta_s = max(eta_s, 1e-12)
        eta_d = max(eta_d, 1e-12)
        total = lam + kap + eta_s + eta_d
        lam, kap, eta_s, eta_d = lam / total, kap / total, eta_s / total, eta_d / total

    final_dist = math.sqrt(
        (lam - LAM_STAR) ** 2
        + (kap - rho) ** 2
        + (eta_s - rho) ** 2
        + (eta_d - rho) ** 2
    )

    tau_z3 = z3_step * dt if z3_step is not None else None
    tau_total = converge_step * dt if converge_step is not None else max_steps * dt

    return {
        'final_state': {
            'lambda': lam, 'kappa': kap,
            'eta_s': eta_s, 'eta_d': eta_d,
        },
        'final_distance': final_dist,
        'converged': final_dist < 1e-4,
        'z3_achieved_step': z3_step,
        'converge_step': converge_step,
        'tau_z3': tau_z3,
        'tau_total': tau_total,
        'z3_faster_than_convergence': (
            tau_z3 is not None and tau_total > 0
            and tau_z3 < tau_total * 0.5
        ),
        'z3_symmetric_final': (
            abs(kap - eta_s) < 1e-6
            and abs(eta_s - eta_d) < 1e-6
        ),
    }


def symmetry_breaking_landscape() -> Dict:
    """Compute the free energy cost of breaking Z3 symmetry.

    Theorem CH (Symmetry-Breaking Landscape):
    Along the exchange mode direction (eta_s increases, eta_d decreases
    by the same amount, kappa and lambda fixed), the free energy
    cost of asymmetry delta = eta_s - eta_d is:

        Delta_F(delta) ≈ (mu_exchange / 2) * delta^2

    with mu_exchange = T3/rho* ≈ 8.044.  The Z3 equilibrium is a
    TRUE MINIMUM in all directions — there is NO spontaneous
    symmetry breaking.  Structured and destructive entropy are
    equally weighted at equilibrium.

    Breaking the symmetry (making eta_s > eta_d, i.e. preferring
    structured exploration over destructive noise) costs free energy
    quadratically.  The STIFFNESS of this cost is mu_exchange ≈ 8.044,
    which is 54% stiffer than the coherence mode (5.217).

    This means the system RESISTS asymmetric entropy splitting more
    strongly than it resists coherence perturbations.

    Returns:
        Dict with symmetry-breaking analysis.
    """
    T3 = T_STAR3
    lam = LAM_STAR
    rho = RHO_STAR

    mu_exchange = T3 / rho
    mu_coherence = (3 * (1 / lam ** 2 + T3 / lam) + mu_exchange) / 4

    # Compute F along symmetry-breaking direction
    # Fix lambda = lambda*, kappa = rho*
    # Vary: eta_s = rho + delta/2, eta_d = rho - delta/2
    deltas = [0.001 * i for i in range(-50, 51)]
    F_values = []
    F_eq = (-math.log(lam)
            + T3 * (lam * math.log(lam)
                    + 3 * rho * math.log(rho)))

    for delta in deltas:
        eta_s = rho + delta / 2
        eta_d = rho - delta / 2
        if eta_s <= 0 or eta_d <= 0:
            continue
        F_val = (-math.log(lam)
                 + T3 * (lam * math.log(lam)
                         + rho * math.log(rho)
                         + eta_s * math.log(eta_s)
                         + eta_d * math.log(eta_d)))
        F_values.append({
            'delta': delta,
            'F': F_val,
            'delta_F': F_val - F_eq,
        })

    # Quadratic fit: Delta_F ≈ (mu_exchange/2) * delta^2 / 4
    # (factor of 4 because the Riemannian eigenvector is (0,0,1,-1)/sqrt(2)
    #  and delta is the coordinate difference, not the tangent vector norm)
    # Actually: the exchange eigenvector in (lam,kap,eta_s,eta_d) is (0,0,1,-1)/sqrt(2)
    # The tangent vector for delta perturbation is (0,0,1/2,-1/2), norm = 1/sqrt(2) * delta/sqrt(2) = delta/2
    # So Delta_F = (mu_exchange/2) * (delta/sqrt(2))^2 = mu_exchange * delta^2 / 4
    #
    # Let's just check numerically
    small_delta_entries = [e for e in F_values if 0 < abs(e['delta']) < 0.01]
    if small_delta_entries:
        e = small_delta_entries[-1]
        numerical_curvature = 2 * e['delta_F'] / (e['delta'] ** 2)
    else:
        numerical_curvature = 0

    stiffness_ratio = mu_exchange / mu_coherence

    return {
        'mu_exchange': mu_exchange,
        'mu_coherence': mu_coherence,
        'stiffness_ratio': stiffness_ratio,
        'exchange_stiffer': stiffness_ratio > 1.0,
        'numerical_curvature': numerical_curvature,
        'predicted_curvature': mu_exchange / 2,
        'curvature_match': (
            abs(numerical_curvature - mu_exchange / 2) / (mu_exchange / 2) < 0.01
            if mu_exchange > 0 else False
        ),
        'no_spontaneous_breaking': all(
            e['delta_F'] >= -1e-12 for e in F_values
        ),
        'n_landscape_points': len(F_values),
    }


# =============================================================================
# SPRINT 17: Cross-Dimensional Bridges (CI-CM)
# =============================================================================

def dimensional_free_energy_cost() -> Dict:
    """Compute the free energy penalty for adding a dimension.

    Theorem CI (Dimensional Free Energy Cost):
    For each exceptional root system R, the cost of lifting from the
    2-simplex to the 3-simplex (at their respective temperatures) is:

        Delta_dim(R) = F_3sim(R) - F_2sim(R)

    where F_nsim(R) evaluates the n-simplex free energy at R's
    Z_n-symmetric projection.

    Key results:
    1. Delta_dim INCREASES monotonically: F4 < E6 < E7 < E8.
    2. E8's dimensional cost (0.170) MATCHES the equilibrium
       dimensional cost F3* - F2* = 0.170 to better than 0.1%.
    3. Systems closer to equilibrium pay MORE for the extra dimension —
       they are more tightly bound to the 2-simplex.

    Returns:
        Dict with dimensional cost analysis for each system.
    """
    T2 = T_STAR
    T3 = T_STAR3

    # Equilibrium dimensional cost
    F2_eq = F_STAR
    F3_eq = (-math.log(LAM_STAR)
             + T3 * (LAM_STAR * math.log(LAM_STAR)
                     + 3 * RHO_STAR * math.log(RHO_STAR)))
    delta_eq = F3_eq - F2_eq

    results = []
    for name in ['F4', 'E6', 'E7', 'E8']:
        r = root_system_conservation(name)
        lam = r['lambda_R']

        # 2-simplex: symmetric projection (lam, (1-lam)/2, (1-lam)/2)
        kap2 = (1 - lam) / 2
        F_2sim = (-math.log(lam)
                  + T2 * (lam * math.log(lam)
                          + 2 * kap2 * math.log(kap2)))

        # 3-simplex: Z3 projection (lam, (1-lam)/3, (1-lam)/3, (1-lam)/3)
        rho3 = (1 - lam) / 3
        F_3sim = (-math.log(lam)
                  + T3 * (lam * math.log(lam)
                          + 3 * rho3 * math.log(rho3)))

        delta = F_3sim - F_2sim

        results.append({
            'system': name,
            'F_2sim': F_2sim,
            'F_3sim': F_3sim,
            'delta_dim': delta,
        })

    deltas = [r['delta_dim'] for r in results]
    monotone = all(deltas[i] < deltas[i + 1] for i in range(len(deltas) - 1))

    e8 = next(r for r in results if r['system'] == 'E8')
    e8_matches_eq = abs(e8['delta_dim'] - delta_eq) / abs(delta_eq) < 0.005

    return {
        'systems': results,
        'delta_equilibrium': delta_eq,
        'cost_monotone_increasing': monotone,
        'e8_delta': e8['delta_dim'],
        'e8_matches_equilibrium': e8_matches_eq,
    }


def cross_dimensional_conditioning() -> Dict:
    """Compare Hessian condition numbers across dimensions.

    Theorem CJ (Cross-Dimensional Conditioning):
    The condition number kappa(H) = mu_fast/mu_slow DROPS dramatically
    when moving from the 2-simplex to the 3-simplex:

        F4:  5.80 -> 3.22  (44% reduction)
        E6:  4.90 -> 2.57  (48% reduction)
        E7:  4.06 -> 1.97  (51% reduction)
        E8:  3.59 -> 1.64  (54% reduction)

    Adding a dimension makes the free energy landscape MORE ISOTROPIC
    at every root system point.  The exchange mode provides additional
    relaxation directions that reduce anisotropy.

    The reduction is MONOTONICALLY INCREASING through the cascade:
    E8 benefits most from the extra dimension (54% reduction).

    Returns:
        Dict with cross-dimensional conditioning analysis.
    """
    T2 = T_STAR
    T3 = T_STAR3

    results = []
    for name in ['F4', 'E6', 'E7', 'E8']:
        r = root_system_conservation(name)
        lam = r['lambda_R']

        # 2-simplex Hessian at symmetric projection
        kap2 = (1 - lam) / 2
        H11 = 1 / lam ** 2 + T2 / lam + T2 / kap2
        H22 = T2 / kap2 + T2 / kap2
        H12 = T2 / kap2
        tr2 = H11 + H22
        det2 = H11 * H22 - H12 ** 2
        disc2 = math.sqrt(max(tr2 ** 2 - 4 * det2, 0))
        cond_2 = ((tr2 + disc2) / 2) / ((tr2 - disc2) / 2) if (tr2 - disc2) > 0 else float('inf')

        # 3-simplex Riemannian eigenvalues at Z3 projection
        rho3 = (1 - lam) / 3
        A3 = 1 / lam ** 2 + T3 / lam
        C3 = T3 / rho3
        mu_coh = (3 * A3 + C3) / 4
        mu_exch = C3
        cond_3 = max(mu_coh, mu_exch) / min(mu_coh, mu_exch)

        reduction = 1 - cond_3 / cond_2

        results.append({
            'system': name,
            'cond_2sim': cond_2,
            'cond_3sim': cond_3,
            'reduction_fraction': reduction,
        })

    reductions = [r['reduction_fraction'] for r in results]
    reduction_monotone = all(reductions[i] < reductions[i + 1]
                             for i in range(len(reductions) - 1))

    return {
        'systems': results,
        'all_improved': all(r['cond_3sim'] < r['cond_2sim'] for r in results),
        'reduction_monotone_increasing': reduction_monotone,
        'e8_reduction': reductions[-1],
        'min_reduction': min(reductions),
    }


def three_simplex_root_flow() -> Dict:
    """Run gradient flow from root system points on the 3-simplex.

    Theorem CK (3-Simplex Root System Flow):
    Starting from each exceptional root system's Z3-projected point
    on the 3-simplex, the gradient flow converges to the golden
    equilibrium with FASTER convergence than on the 2-simplex.

    The 3-simplex flow time is approximately T3/T* ≈ 0.74 times
    the 2-simplex flow time — the lower temperature produces a
    weaker gradient but the better conditioning compensates.

    Returns:
        Dict with 3-simplex flow analysis from root system points.
    """
    T3 = T_STAR3
    dt = 0.001
    max_steps = 10000
    convergence_tol = 1e-6
    rho_eq = RHO_STAR

    results = []
    for name in ['F4', 'E6', 'E7', 'E8']:
        r = root_system_conservation(name)
        lam_init = r['lambda_R']
        rho_init = (1 - lam_init) / 3

        lam, kap, eta_s, eta_d = lam_init, rho_init, rho_init, rho_init
        converge_step = None

        for step in range(max_steps):
            eps = 1e-15
            g_l = -1 / max(lam, eps) + T3 * (math.log(max(lam, eps)) + 1)
            g_k = T3 * (math.log(max(kap, eps)) + 1)
            g_s = T3 * (math.log(max(eta_s, eps)) + 1)
            g_d = T3 * (math.log(max(eta_d, eps)) + 1)
            mean_g = (g_l + g_k + g_s + g_d) / 4

            grad_norm = math.sqrt(
                (g_l - mean_g) ** 2 + (g_k - mean_g) ** 2
                + (g_s - mean_g) ** 2 + (g_d - mean_g) ** 2
            )

            if grad_norm < convergence_tol:
                converge_step = step
                break

            lam -= dt * (g_l - mean_g)
            kap -= dt * (g_k - mean_g)
            eta_s -= dt * (g_s - mean_g)
            eta_d -= dt * (g_d - mean_g)

            lam = max(lam, 1e-12)
            kap = max(kap, 1e-12)
            eta_s = max(eta_s, 1e-12)
            eta_d = max(eta_d, 1e-12)
            total = lam + kap + eta_s + eta_d
            lam, kap, eta_s, eta_d = lam / total, kap / total, eta_s / total, eta_d / total

        final_dist = math.sqrt(
            (lam - LAM_STAR) ** 2
            + (kap - rho_eq) ** 2
            + (eta_s - rho_eq) ** 2
            + (eta_d - rho_eq) ** 2
        )
        tau = converge_step * dt if converge_step is not None else max_steps * dt

        results.append({
            'system': name,
            'tau_3sim': tau,
            'converged': final_dist < 1e-4,
            'z3_preserved': abs(kap - eta_s) < 1e-6 and abs(eta_s - eta_d) < 1e-6,
        })

    # Time ordering: E8 fastest
    taus = [r['tau_3sim'] for r in results]
    time_ordering = taus == sorted(taus, reverse=True)

    return {
        'systems': results,
        'all_converged': all(r['converged'] for r in results),
        'all_z3_preserved': all(r['z3_preserved'] for r in results),
        'time_ordering_correct': time_ordering,
    }


def dimensional_stability_ordering() -> Dict:
    """Rank root systems by stability across dimensions.

    Theorem CL (Dimensional Stability Ordering):
    Define the dimensional stability ratio as:

        sigma(R) = mu_coherence_3sim(R) / mu_slow_2sim(R)

    This measures how much the coherence eigenvalue changes when
    adding a dimension.  A ratio near 1 means the system is
    dimensionally stable.

    Result: sigma INCREASES through the cascade:
        sigma(F4) < sigma(E6) < sigma(E7) < sigma(E8)

    E8 is the MOST dimensionally stable — its coherence eigenvalue
    barely changes (sigma ≈ 0.87) when going from 2-simplex to
    3-simplex.  F4 changes the most (sigma ≈ 0.76).

    This means E8's coherence structure is robust across dimensions,
    while F4's is fragile.

    Returns:
        Dict with dimensional stability analysis.
    """
    T2 = T_STAR
    T3 = T_STAR3

    results = []
    for name in ['F4', 'E6', 'E7', 'E8']:
        r = root_system_conservation(name)
        lam = r['lambda_R']

        # 2-simplex slow eigenvalue
        kap2 = (1 - lam) / 2
        H11 = 1 / lam ** 2 + T2 / lam + T2 / kap2
        H22 = T2 / kap2 + T2 / kap2
        H12 = T2 / kap2
        tr2 = H11 + H22
        det2 = H11 * H22 - H12 ** 2
        disc2 = math.sqrt(max(tr2 ** 2 - 4 * det2, 0))
        mu_slow_2 = (tr2 - disc2) / 2

        # 3-simplex coherence eigenvalue
        rho3 = (1 - lam) / 3
        A3 = 1 / lam ** 2 + T3 / lam
        C3 = T3 / rho3
        mu_coh_3 = (3 * A3 + C3) / 4

        sigma = mu_coh_3 / mu_slow_2

        results.append({
            'system': name,
            'mu_slow_2sim': mu_slow_2,
            'mu_coh_3sim': mu_coh_3,
            'sigma': sigma,
        })

    sigmas = [r['sigma'] for r in results]
    monotone = all(sigmas[i] < sigmas[i + 1] for i in range(len(sigmas) - 1))

    return {
        'systems': results,
        'sigma_monotone_increasing': monotone,
        'e8_most_stable': sigmas[-1] == max(sigmas),
        'e8_sigma': sigmas[-1],
        'f4_sigma': sigmas[0],
    }


def n_simplex_temperature_sequence(n_max: int = 10) -> Dict:
    """The generalised temperature sequence T_n = phi/ln(n*phi).

    Theorem CM (n-Simplex Temperature Sequence):
    The Watkins critical temperature on the (n-1)-simplex is:

        T_n = phi / ln(n * phi)

    This is MONOTONICALLY DECREASING with n, starting from:
        T_1 = phi/ln(phi) ≈ 3.362  (1-simplex, trivial)
        T_2 = phi/ln(2*phi) ≈ 1.378  (2-simplex, original)
        T_3 = phi/ln(3*phi) ≈ 1.024  (3-simplex, Sprint 16)

    The ratio T_n/T_2 = ln(2*phi)/ln(n*phi) gives the temperature
    DISCOUNT from adding dimensions.

    The equilibrium free energy F_n* also changes with dimension:
    adding dimensions RAISES the equilibrium free energy
    (weaker binding) while LOWERING the temperature (weaker flow).

    Returns:
        Dict with temperature sequence and cross-dimensional data.
    """
    temps = []
    for n in range(1, n_max + 1):
        T_n = PHI / math.log(n * PHI)
        rho_n = (1 - LAM_STAR) / n if n > 0 else 0

        # Free energy at Z_n equilibrium (n-simplex)
        if rho_n > 0:
            F_n = (-math.log(LAM_STAR)
                   + T_n * (LAM_STAR * math.log(LAM_STAR)
                            + n * rho_n * math.log(rho_n)))
        else:
            F_n = float('nan')

        temps.append({
            'n': n,
            'T_n': T_n,
            'rho_n': rho_n,
            'F_n': F_n,
            'T_ratio': T_n / T_STAR,
        })

    T_vals = [t['T_n'] for t in temps]
    F_vals = [t['F_n'] for t in temps if not math.isnan(t['F_n'])]

    return {
        'sequence': temps,
        'temperature_decreasing': all(
            T_vals[i] > T_vals[i + 1] for i in range(len(T_vals) - 1)
        ),
        'F_increasing': all(
            F_vals[i] < F_vals[i + 1] for i in range(len(F_vals) - 1)
        ),
        'T_2': temps[1]['T_n'],
        'T_3': temps[2]['T_n'],
        'T_10': temps[9]['T_n'],
    }
