Research source · python

verify-peripheral-filling-base-change.py

site/public/evidence/dehn-filled-quantum-trace/verify-peripheral-filling-base-change.py

225 lines. Source is displayed for inspection; it is not executed by this page.

File fingerprint

SHA-256: 9867739ad438b6f60e8e69b051215cb28399d3ab46dca55f5115a94d3e50d2d8

#!/usr/bin/env python3
"""Exact checks for the empty-sector peripheral filling ideal.

The script uses only integer arithmetic.  It verifies:

1. the Frohman--Gelca product-to-sum law in the rank-two quantum torus;
2. covariance of the two solid-torus filling generators under SL(2,Z);
3. the exact classical factorization showing that the second generator is
   radical-redundant at t=1, although it is essential quantum mechanically.

These identities do not prove ordinary-skein excision or a filled quantum
trace.  The companion obstruction note explains why empty-sector peripheral
relations are insufficient.  No numerical approximation or manifold census
is used.
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Dict, Iterable, Tuple


Vector = Tuple[int, int]
QKey = Tuple[int, int, int]  # t exponent, first torus exponent, second torus exponent
LKey = Tuple[int, int]       # commuting eigenvalue exponents


def det(u: Vector, v: Vector) -> int:
    return u[0] * v[1] - u[1] * v[0]


@dataclass(frozen=True)
class QuantumElement:
    """Finite Z-linear combinations of t^k E_(a,b).

    Multiplication is E_u E_v = t^det(u,v) E_(u+v).
    """

    terms: Dict[QKey, int]

    def __post_init__(self) -> None:
        clean = {key: value for key, value in self.terms.items() if value}
        object.__setattr__(self, "terms", clean)

    def __add__(self, other: "QuantumElement") -> "QuantumElement":
        result = dict(self.terms)
        for key, value in other.terms.items():
            result[key] = result.get(key, 0) + value
        return QuantumElement(result)

    def __sub__(self, other: "QuantumElement") -> "QuantumElement":
        return self + other.scale(-1)

    def scale(self, scalar: int) -> "QuantumElement":
        return QuantumElement({key: scalar * value for key, value in self.terms.items()})

    def __mul__(self, other: "QuantumElement") -> "QuantumElement":
        result: Dict[QKey, int] = {}
        for (kt, a, b), c in self.terms.items():
            for (lt, x, y), d in other.terms.items():
                exponent = kt + lt + det((a, b), (x, y))
                key = (exponent, a + x, b + y)
                result[key] = result.get(key, 0) + c * d
        return QuantumElement(result)

    def apply_sl2(self, matrix: Tuple[Tuple[int, int], Tuple[int, int]]) -> "QuantumElement":
        (a, b), (c, d) = matrix
        if a * d - b * c != 1:
            raise ValueError("matrix is not in SL(2,Z)")
        return QuantumElement(
            {
                (kt, a * x + b * y, c * x + d * y): coefficient
                for (kt, x, y), coefficient in self.terms.items()
            }
        )


def e(u: Vector, t_power: int = 0) -> QuantumElement:
    return QuantumElement({(t_power, u[0], u[1]): 1})


def scalar_t(t_power: int, coefficient: int = 1) -> QuantumElement:
    return QuantumElement({(t_power, 0, 0): coefficient})


def k(u: Vector, t_power: int = 0) -> QuantumElement:
    return e(u, t_power) + e((-u[0], -u[1]), t_power)


def add_vectors(u: Vector, v: Vector) -> Vector:
    return (u[0] + v[0], u[1] + v[1])


def subtract_vectors(u: Vector, v: Vector) -> Vector:
    return (u[0] - v[0], u[1] - v[1])


def product_to_sum_rhs(u: Vector, v: Vector) -> QuantumElement:
    intersection = det(u, v)
    return k(add_vectors(u, v), intersection) + k(subtract_vectors(u, v), -intersection)


def filling_generators(rho: Vector, slope: Vector) -> Tuple[QuantumElement, QuantumElement]:
    """Frohman--Gelca generators in their t-convention.

    The ordered basis satisfies det(rho, slope)=1.  The first relation is the
    meridian disk relation; the second records the framing change.
    """

    if det(rho, slope) != 1:
        raise ValueError("expected det(rho, slope)=1")
    first = k(slope) + scalar_t(2) + scalar_t(-2)
    second = k(add_vectors(rho, slope)) + k(rho, -3)
    return first, second


@dataclass(frozen=True)
class LaurentElement:
    terms: Dict[LKey, int]

    def __post_init__(self) -> None:
        clean = {key: value for key, value in self.terms.items() if value}
        object.__setattr__(self, "terms", clean)

    def __add__(self, other: "LaurentElement") -> "LaurentElement":
        result = dict(self.terms)
        for key, value in other.terms.items():
            result[key] = result.get(key, 0) + value
        return LaurentElement(result)

    def __mul__(self, other: "LaurentElement") -> "LaurentElement":
        result: Dict[LKey, int] = {}
        for (a, b), c in self.terms.items():
            for (x, y), d in other.terms.items():
                key = (a + x, b + y)
                result[key] = result.get(key, 0) + c * d
        return LaurentElement(result)


def monomial(a: int, b: int, coefficient: int = 1) -> LaurentElement:
    return LaurentElement({(a, b): coefficient})


def classical_k(u: Vector) -> LaurentElement:
    return monomial(*u) + monomial(-u[0], -u[1])


def exact_product_to_sum_checks() -> int:
    checked = 0
    vectors: Iterable[Vector] = (
        (-3, 2), (-2, -1), (-1, 3), (0, 1), (1, 0), (1, 2), (2, -3), (3, 1)
    )
    for u in vectors:
        for v in vectors:
            assert k(u) * k(v) == product_to_sum_rhs(u, v)
            checked += 1
    return checked


def exact_sl2_checks() -> int:
    matrices = (
        ((1, 0), (0, 1)),
        ((0, -1), (1, 0)),
        ((1, 1), (0, 1)),
        ((2, 1), (1, 1)),
        ((-1, 0), (0, -1)),
    )
    rho, slope = (1, 0), (0, 1)
    standard = filling_generators(rho, slope)
    checked = 0
    for matrix in matrices:
        transformed_rho = (
            matrix[0][0] * rho[0] + matrix[0][1] * rho[1],
            matrix[1][0] * rho[0] + matrix[1][1] * rho[1],
        )
        transformed_slope = (
            matrix[0][0] * slope[0] + matrix[0][1] * slope[1],
            matrix[1][0] * slope[0] + matrix[1][1] * slope[1],
        )
        transported = tuple(generator.apply_sl2(matrix) for generator in standard)
        direct = filling_generators(transformed_rho, transformed_slope)
        assert transported == direct
        checked += 1
    return checked


def exact_classical_factorization_checks() -> Tuple[LaurentElement, LaurentElement]:
    rho, slope = (1, 0), (0, 1)
    one = monomial(0, 0)
    s_plus_one = monomial(0, 1) + one

    first = classical_k(slope) + one + one
    first_factorization = monomial(0, -1) * s_plus_one * s_plus_one
    assert first == first_factorization

    second = classical_k(add_vectors(rho, slope)) + classical_k(rho)
    second_factorization = s_plus_one * (monomial(1, 0) + monomial(-1, -1))
    assert second == second_factorization

    # Evaluation at the filled eigenvalue s=-1 kills both generators.
    for element in (first, second):
        by_r: Dict[int, int] = {}
        for (r_power, s_power), coefficient in element.terms.items():
            by_r[r_power] = by_r.get(r_power, 0) + coefficient * ((-1) ** s_power)
        assert all(value == 0 for value in by_r.values())

    return first, second


def main() -> None:
    products = exact_product_to_sum_checks()
    matrices = exact_sl2_checks()
    first, second = exact_classical_factorization_checks()

    print(f"product-to-sum identities checked: {products}")
    print(f"SL(2,Z) covariance checks: {matrices}")
    print("classical meridian relation: K_s + 2 = s^(-1)(s+1)^2")
    print("classical framing relation: K_(rho+s) + K_rho = (s+1)(rho+rho^(-1)s^(-1))")
    print(f"first classical support size: {len(first.terms)}")
    print(f"second classical support size: {len(second.terms)}")
    print("all exact checks passed")


if __name__ == "__main__":
    main()