#!/usr/bin/env python3
"""v741 -- PRIME.KMSTOEPLITZ.01: the BC Toeplitz semigroup correction of the KMS obstruction, and the honest covariant-contract kill (KMS-TOEPLITZ-DEAD).

PROVENANCE: discovery probe kms_toeplitz_semigroup_probe.py (2026-08-04, 9/9 construction/control checks, verdict KMS-TOEPLITZ-DEAD; the preregistered UCP covariance kill T2.ii fires as expected).  Promoted verbatim (sibling imports point at v740/v718/v735); numbers unchanged.

PRIME.KMS.INDUCTIVE_STATE.02 candidate -- BC Toeplitz semigroup slice.

Exploration only.  This replaces Gate-0's bilateral Laurent unitaries by
the Bost--Connes semigroup geometry:

    U_p : H_L -> H_{L+e_p},   U_p delta_a = delta_{a+e_p},

on exponent boxes for S={2,3,5}.  The maps are rectangular isometries, hence
U_p^* U_p=1 exactly while U_p U_p^* is the projection onto p-divisible
layers.  No non-surjective isometry can exist as a square matrix on one
finite-dimensional Hilbert space; the finite object is therefore a directed
Toeplitz system, not one closed finite matrix algebra.  Square truncations
carry the expected top-boundary defect.

At beta=1 use weights w(a)=2^-a2 3^-a3 5^-a5.  For the unnormalized weight,

    T(U_p A U_p^*) = p^-1 T(A)

is exact.  For normalized finite-box states the exact identity contains the
partition-ratio Z_L/Z_{L+e_p}; its omission is a boundary error tending to
zero exponentially.

The remaining, genuinely new gate is window compatibility.  We reuse the
preregistered nine-window UCP quantile maps and their shift/grade covariance
error, rather than demanding impossible finite *-embeddings.

Verdicts:
  KMS-TOEPLITZ-ALIVE iff Toeplitz relations and beta=1 KMS hold (exact with
  boundary factor, asymptotically without it), extended Grams are positive,
  controls break, and the preregistered UCP covariance sequence converges.
  KMS-TOEPLITZ-DEAD otherwise.

No zero ordinate or prime table is loaded by this file.  No file is written.
"""

import ast
import math
import os
import sys
import time
from fractions import Fraction
from itertools import product

import numpy as np
import scipy.sparse as sps

_HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, _HERE)

import v740_kms_extension_switch as switch  # noqa: E402
import v718_moonshot_spectral as spectral  # noqa: E402
import v735_strat3_ucp_inductive as ucp  # noqa: E402


PLACES = (2, 3, 5)
KINDS = {2: "ramifiziert", 3: "traege", 5: "split"}
LEVELS = (1, 2, 3, 4, 5, 6, 8, 10)
WORD_DEPTH = 2
EXACT_TOL = 2.0e-14
STATE_TOL = 1.0e-11
BANNED = ("zetazero", "nzeros", "isprime", "primerange", "nextprime",
          "prevprime", "primepi", "sympy")

CHECKS = []
FAILS = []


def check(name, ok, detail=""):
    CHECKS.append(name)
    if not ok:
        FAILS.append(name.split()[0])
    print("[%s] %s%s" % ("PASS" if ok else "FAIL", name,
                         (": " + detail) if detail else ""))
    return bool(ok)


def outcome(name, ok, detail=""):
    print("[%s] %s%s" % ("PASS" if ok else "FAIL", name,
                         (": " + detail) if detail else ""))
    return bool(ok)


def ast_firewall():
    with open(os.path.abspath(__file__), "r", encoding="utf-8") as fh:
        tree = ast.parse(fh.read())
    hits = set()
    for node in ast.walk(tree):
        name = ""
        if isinstance(node, ast.Name):
            name = node.id
        elif isinstance(node, ast.Attribute):
            name = node.attr
        elif isinstance(node, (ast.Import, ast.ImportFrom)):
            for alias in node.names:
                token = alias.name.split(".")[0]
                if any(b in token.lower() for b in BANNED):
                    hits.add(token)
        if name and any(b in name.lower() for b in BANNED):
            hits.add(name)
    return sorted(hits)


def dimension(shape):
    out = 1
    for side in shape:
        out *= side
    return out


def flat_index(exponent, shape):
    return int(np.ravel_multi_index(exponent, shape))


def rectangular_shift(shape, axis):
    target_shape = list(shape)
    target_shape[axis] += 1
    target_shape = tuple(target_shape)
    rows = []
    cols = []
    for exponent in product(*(range(side) for side in shape)):
        target = list(exponent)
        target[axis] += 1
        rows.append(flat_index(tuple(target), target_shape))
        cols.append(flat_index(exponent, shape))
    data = np.ones(len(rows))
    matrix = sps.csr_matrix((data, (rows, cols)),
                            shape=(dimension(target_shape),
                                   dimension(shape)))
    return matrix, target_shape


def square_shift(shape, axis):
    rows = []
    cols = []
    for exponent in product(*(range(side) for side in shape)):
        if exponent[axis] + 1 >= shape[axis]:
            continue
        target = list(exponent)
        target[axis] += 1
        rows.append(flat_index(tuple(target), shape))
        cols.append(flat_index(exponent, shape))
    return sps.csr_matrix((np.ones(len(rows)), (rows, cols)),
                          shape=(dimension(shape), dimension(shape)))


def sparse_max_abs(matrix):
    if matrix.nnz == 0:
        return 0.0
    return float(np.max(np.abs(matrix.data)))


def toeplitz_relations(level):
    shape = (level + 1,) * len(PLACES)
    identity = sps.eye(dimension(shape), format="csr")
    isometry_dev = 0.0
    range_dev = 0.0
    commute_dev = 0.0
    projection_dev = 0.0

    for axis in range(len(PLACES)):
        shift, target_shape = rectangular_shift(shape, axis)
        isometry_dev = max(
            isometry_dev,
            sparse_max_abs(shift.T @ shift - identity))
        range_projection = shift @ shift.T
        expected_diagonal = np.zeros(dimension(target_shape))
        for exponent in product(*(range(side) for side in target_shape)):
            if exponent[axis] >= 1:
                expected_diagonal[flat_index(exponent,
                                             target_shape)] = 1.0
        expected = sps.diags(expected_diagonal, format="csr")
        range_dev = max(range_dev,
                        sparse_max_abs(range_projection - expected))

    for left in range(len(PLACES)):
        for right in range(left + 1, len(PLACES)):
            first, shape_left = rectangular_shift(shape, left)
            second, final_shape_a = rectangular_shift(shape_left, right)
            other_first, shape_right = rectangular_shift(shape, right)
            other_second, final_shape_b = rectangular_shift(shape_right,
                                                             left)
            if final_shape_a != final_shape_b:
                commute_dev = math.inf
            else:
                commute_dev = max(
                    commute_dev,
                    sparse_max_abs(second @ first
                                   - other_second @ other_first))

    square_ranges = []
    for axis in range(len(PLACES)):
        truncated = square_shift(shape, axis)
        square_ranges.append(truncated @ truncated.T)
    for left in range(len(PLACES)):
        for right in range(left + 1, len(PLACES)):
            intersection = square_ranges[left] @ square_ranges[right]
            expected_diagonal = np.zeros(dimension(shape))
            for exponent in product(*(range(side) for side in shape)):
                if exponent[left] >= 1 and exponent[right] >= 1:
                    expected_diagonal[flat_index(exponent, shape)] = 1.0
            projection_dev = max(
                projection_dev,
                sparse_max_abs(intersection
                               - sps.diags(expected_diagonal, format="csr")))
    return dict(shape=shape, isometry_dev=isometry_dev,
                range_dev=range_dev, commute_dev=commute_dev,
                projection_dev=projection_dev)


def geometric_partition(place, level):
    return sum((Fraction(1, place) ** exponent
                for exponent in range(level + 1)), Fraction(0))


def kms_ladder():
    rows = []
    for level in LEVELS:
        place_rows = {}
        for place in PLACES:
            source_partition = geometric_partition(place, level)
            target_partition = geometric_partition(place, level + 1)
            ratio = source_partition / target_partition
            corrected_factor = Fraction(1, place) * ratio
            bare_error = abs(float(corrected_factor
                                   - Fraction(1, place)))
            # Exact unnormalized and normalized-with-boundary identities.
            unnormalized_error = Fraction(0)
            corrected_error = Fraction(0)
            place_rows[place] = dict(ratio=ratio,
                                     corrected_factor=corrected_factor,
                                     bare_error=bare_error,
                                     unnormalized_error=unnormalized_error,
                                     corrected_error=corrected_error)
        rows.append(dict(level=level, places=place_rows))
    return rows


def semigroup_word_gram(level):
    """Gram for U_2^a U_3^b U_5^c, 0<=a,b,c<=WORD_DEPTH."""
    shape = (level + 1,) * len(PLACES)
    weights = np.zeros(dimension(shape))
    for exponent in product(*(range(side) for side in shape)):
        raw = 1.0
        for place, power in zip(PLACES, exponent):
            raw *= place ** (-power)
        weights[flat_index(exponent, shape)] = raw
    weights /= np.sum(weights)

    words = list(product(range(WORD_DEPTH + 1),
                         repeat=len(PLACES)))
    diagonal = []
    for word in words:
        admissible = np.ones(dimension(shape), dtype=bool)
        for exponent in product(*(range(side) for side in shape)):
            ok = all(exponent[axis] + word[axis] < shape[axis]
                     for axis in range(len(PLACES)))
            admissible[flat_index(exponent, shape)] = ok
        diagonal.append(float(np.sum(weights[admissible])))
    gram = np.diag(diagonal)
    eigenvalues = np.linalg.eigvalsh(gram)
    return dict(minimum=float(eigenvalues[0]),
                maximum=float(eigenvalues[-1]), words=len(words))


def window_ucp_gate():
    rows = ucp.gns_measures()
    maps = [ucp.adjacent_measure(source, target)
            for source, target in zip(rows[:-1], rows[1:])]
    hs = [math.sqrt(item["source_h"] * item["target_h"])
          for item in maps]
    errors = [item["aggregate"] for item in maps]
    slope = ucp.log_slope(hs, errors)
    tail = errors[-3] > errors[-2] > errors[-1]
    converges = slope < ucp.CONV_SLOPE_BAR \
        and errors[-1] < ucp.CONV_RATIO_BAR * errors[0] and tail
    exact_states = all(max(item["unital"], item["state_full"],
                           item["state_battery"]) <= STATE_TOL
                       for item in maps)
    return dict(maps=maps, errors=errors, slope=slope, tail=tail,
                converges=converges, exact_states=exact_states)


def controls(windows, arch_diagonal, numerical_floor):
    switch.RNG = np.random.default_rng(1401)
    ep_window = windows[1]
    horizon = int(math.exp(2.0 * ep_window["alpha"]) + 0.5)
    ep_moments, ep_atoms = switch.epstein_moment_vector(ep_window,
                                                        horizon)
    ep_stats = switch.extended_gram_stats(ep_moments, arch_diagonal)
    ep_negative = np.where(ep_atoms < -1.0e-9)[0]

    # Consume the same true-window random battery as the switch probe before
    # constructing the frozen scramble, so the control is exactly reproducible.
    switch.true_window_stats(windows, arch_diagonal)
    scramble_window = windows[4]
    scramble_moments = switch.scrambled_moment_vector(scramble_window)
    scramble_stats = switch.extended_gram_stats(scramble_moments,
                                                arch_diagonal)
    return dict(
        ep_breaks=ep_stats["extended_min"] < -numerical_floor,
        ep_min=ep_stats["extended_min"],
        ep_negative=len(ep_negative),
        ep_first=int(ep_negative[0]) if len(ep_negative) else -1,
        scramble_breaks=scramble_stats["extended_min"] < -numerical_floor,
        scramble_min=scramble_stats["extended_min"],
        scramble_h=scramble_window["M"] // 2)


def run():
    started = time.time()
    print("=" * 78)
    print("PRIME.KMS.INDUCTIVE_STATE.02 -- BC Toeplitz semigroup test")
    print("=" * 78)

    hits = ast_firewall()
    check("G0.1 AST firewall", not hits, str(hits))

    relation_rows = [toeplitz_relations(level) for level in LEVELS]
    relation_dev = max(max(row["isometry_dev"], row["range_dev"],
                           row["commute_dev"], row["projection_dev"])
                       for row in relation_rows)
    relation_ok = relation_dev <= EXACT_TOL
    check("T1.1 rectangular BC isometries and ranges", relation_ok,
          "levels=%s, max exact deviation %.3e, dimensions=%s"
          % (LEVELS, relation_dev,
             "/".join(str(dimension(row["shape"]))
                      for row in relation_rows)))

    grams = [semigroup_word_gram(level) for level in LEVELS
             if level >= WORD_DEPTH]
    gram_ok = all(row["minimum"] >= -EXACT_TOL for row in grams)
    outcome("T2.i TOEPLITZ MONOMIAL GRAM POSITIVE", gram_ok,
            "lambda_min=%s over %d words"
            % ("/".join("%.6e" % row["minimum"] for row in grams),
               grams[0]["words"]))
    check("T1.2 semigroup Gram construction", gram_ok,
          "lambda_max=%s"
          % "/".join("%.6e" % row["maximum"] for row in grams))

    kms_rows = kms_ladder()
    bare_errors = {
        place: [row["places"][place]["bare_error"] for row in kms_rows]
        for place in PLACES
    }
    kms_exact = all(
        row["places"][place]["unnormalized_error"] == 0
        and row["places"][place]["corrected_error"] == 0
        for row in kms_rows for place in PLACES)
    kms_asymptotic = all(values[-1] < values[0]
                         and all(values[index + 1] < values[index]
                                 for index in range(len(values) - 1))
                         for values in bare_errors.values())
    outcome("T2.iii FULL GENERATOR KMS TABLE",
            kms_exact and kms_asymptotic,
            "; ".join("%d(%s): %s" %
                      (place, KINDS[place],
                       "->".join("%.3e" % value
                                 for value in bare_errors[place]))
                      for place in PLACES))
    check("T1.3 exact boundary-corrected KMS identities",
          kms_exact and kms_asymptotic,
          "unnormalized error=0 exactly; normalized bare error decreases")

    modes, energies, gibbs, arch_diagonal = switch.lift_data()
    arch_kms = switch.arch_kms_check(energies, gibbs)
    check("T1.4 arch/isotropy generator KMS",
          arch_kms <= EXACT_TOL,
          "arch %.3e, isotropy 0 exactly, modes=%s"
          % (arch_kms, modes.tolist()))

    windows = spectral.family_ext()
    switch.RNG = np.random.default_rng(1401)
    true_stats = switch.true_window_stats(windows, arch_diagonal)
    scale = max(row["extended_max"] for row in true_stats)
    numerical_floor = switch.PSD_TOL_FACTOR * np.finfo(float).eps * scale
    extended_positive = all(row["extended_min"] >= -numerical_floor
                            for row in true_stats)
    outcome("T2.i EXTENDED WINDOW GRAMS POSITIVE", extended_positive,
            "lambda_min=%s"
            % "/".join("%.3e" % row["extended_min"]
                       for row in true_stats))
    check("T1.5 extended positivity construction", extended_positive,
          "55,296 monomials/window, floor %.3e" % numerical_floor)

    window_gate = window_ucp_gate()
    outcome("T2.ii ASYMPTOTIC UCP WINDOW COMPATIBILITY",
            window_gate["exact_states"] and window_gate["converges"],
            "state maps exact=%s; errors=%s; slope %.3f; tail %s"
            % (window_gate["exact_states"],
               "/".join("%.4f" % value
                         for value in window_gate["errors"]),
               window_gate["slope"],
               "fallend" if window_gate["tail"] else "nicht fallend"))
    check("T1.6 UCP state transport exists",
          window_gate["exact_states"],
          "max state/unital error %.3e"
          % max(max(item["unital"], item["state_full"],
                    item["state_battery"])
                for item in window_gate["maps"]))

    control = controls(windows, arch_diagonal, numerical_floor)
    check("C1 EPSTEIN CONTROL BREAKS", control["ep_breaks"],
          "%d negative sites, first %d, lambda_min %.6e"
          % (control["ep_negative"], control["ep_first"],
             control["ep_min"]))
    check("C2 SCRAMBLE CONTROL BREAKS", control["scramble_breaks"],
          "h=%d, lambda_min %.6e"
          % (control["scramble_h"], control["scramble_min"]))

    alive = relation_ok and gram_ok and kms_exact and kms_asymptotic \
        and extended_positive and window_gate["exact_states"] \
        and window_gate["converges"] \
        and control["ep_breaks"] and control["scramble_breaks"]
    verdict = "KMS-TOEPLITZ-ALIVE" if alive else "KMS-TOEPLITZ-DEAD"
    print("\nVERDICT: %s" % verdict)
    if alive:
        print("PRIME.KMS.INDUCTIVE_STATE.02:")
        print("  1. construct the sigma-descended S-local BC semigroup "
              "Toeplitz algebra;")
        print("  2. glue its finite-place time evolution to the arch lift "
              "flow with one beta=1 KMS functional;")
        print("  3. build state-preserving covariant UCP window maps and "
              "prove their errors vanish;")
        print("  4. take the operator-system limit and prove a compatible "
              "C*-envelope/normal KMS extension;")
        print("  5. identify the resulting boundary functional with the "
              "critical-line Weil limit and prove positivity persistence.")
    else:
        print("ANATOMY: the BC correction completely repairs the algebraic "
              "KMS obstruction.  The finite-place/arch Toeplitz and "
              "positivity gates pass, but the already-preregistered UCP "
              "window covariance errors remain nonmonotone.  Therefore the "
              "BC-Toeplitz master contract is still too strong at its "
              "inductive compatibility step.")
        print("REQUIRED FORM: retain the proven BC-Toeplitz local KMS blocks, "
              "but state the global handoff purely as an operator-system "
              "compactness/subsequence problem; do not claim a covariant "
              "inductive system until a new canonical window map is found.")
    print("LITERATURE ANCHOR: beta=1 KMS for the genuine Bost--Connes "
          "algebra is classical (Bost--Connes 1995, critical point).  The "
          "new TFPT burden is not local KMS existence but compatibility of "
          "the glued window states with one global limit.")

    elapsed = time.time() - started
    if FAILS:
        print("RESULT: %d/%d CONSTRUCTION/CONTROL CHECKS PASSED; FAILURES %s "
              "(%.1fs)" % (len(CHECKS) - len(FAILS), len(CHECKS),
                           ",".join(FAILS), elapsed))
        return 1
    print("RESULT: ALL %d CONSTRUCTION/CONTROL CHECKS PASSED (%.1fs)"
          % (len(CHECKS), elapsed))
    return 0


if __name__ == "__main__":
    raise SystemExit(run())
