generate.py

back to table · edit · history · where entries came from · files · download

3500 bytes, as of the version from 2026-10-29 14:26 (current). Recorded here, not run.

"""Global dimensions of SU(N) fusion categories -- numberdb.org/T610.

Run with SageMath and the numberdb package:
    sage -pip install numberdb
    sage -python generate.py                 # verify every stored entry
    sage -python generate.py --fill-draft    # write entries with NUMBERDB_API_KEY

The latter writes entries only; it does not offer or publish the draft.
The global dimension is the inverse squared vacuum S-matrix element. Exact
cyclotomic arithmetic detects rational values; Arb evaluates the positive
embedding, including the positive square root for the total dimension.
The 96-bit guard is measured in numerical-evidence.json. The selection and
its noncanonical bounds are documented in argument-selection.md.
"""
import sys
from functools import lru_cache
import numberdb.sage as numberdb
from sage.rings.integer_ring import ZZ
from sage.rings.rational_field import QQ
from sage.rings.number_field.number_field import CyclotomicField
from sage.rings.real_arb import RealBallField

WORKING_GUARD = 96
SHIFTED_LEVEL_BOUND = 16
SU2_LEVEL_BOUND = 20


def categories():
    selected = {(N, k) for N in range(2, SHIFTED_LEVEL_BOUND)
                for k in range(1, SHIFTED_LEVEL_BOUND - N + 1)}
    for k in range(1, SU2_LEVEL_BOUND + 1):
        selected.add((2, k))
        if k >= 2:
            selected.add((k, 2))
    return sorted(selected)


@lru_cache(maxsize=None)
def exact_global(N, k):
    """In Q(zeta_m), (2 sin(pi*j/m))^2 = 2-zeta_m^j-zeta_m^-j."""
    m = N + k
    K = CyclotomicField(m)
    zeta = K.gen()
    denominator = K.one()
    for j in range(1, N):
        denominator *= (2 - zeta**j - zeta**(-j))**(N-j)
    return K(N * ZZ(m)**(N-1)) / denominator


@lru_cache(maxsize=None)
def global_ball(N, k, bits):
    R = RealBallField(bits)
    m = N + k
    denominator = R.one()
    for j in range(1, N):
        denominator *= (2 * (R.pi() * j / m).sin())**(2*(N-j))
    return R(N * ZZ(m)**(N-1)) / denominator


class GlobalDimensions(numberdb.Generator):
    table = 'T610'
    parameters = ('N', 'k', 'normalisation')
    type = 'R'
    digits = 100
    rigour = 'proven'
    files = ('generate.py', 'checks.py', 'check.py', 'argument-selection.md',
             'numerical-evidence.json', 'skill-evidence.json', 'source-notes.md')

    def enumerate(self):
        for N, k in categories():
            for form in ('global', 'total'):
                yield {'N': N, 'k': k, 'normalisation': form}

    def value(self, params, digits):
        N, k = int(params['N']), int(params['k'])
        form = params['normalisation']
        if N < 2 or k < 1 or form not in ('global', 'total'):
            raise ValueError('N >= 2, k >= 1, normalisation global or total required')
        exact = exact_global(N, k)
        if exact in QQ:
            rational = QQ(exact)
            assert rational > 0
            if form == 'global':
                return rational
            if rational.is_square():
                return rational.sqrt()
        ball = global_ball(N, k, numberdb.bits(digits, losing=WORKING_GUARD))
        assert ball.is_finite() and ball > 0
        return ball if form == 'global' else ball.sqrt()


if __name__ == '__main__':
    generator = GlobalDimensions()
    if '--fill-draft' in sys.argv:
        print(generator.publish(message='Fill global and total SU(N) dimensions with certified enclosures.'))
    else:
        report = generator.verify(sample=None)
        print(report)
        sys.exit(0 if report.ok else 1)