checks.py

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

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

"""Independent checks for T610, global dimensions of SU(N) fusion categories.

    sage -python checks.py                  # preflight; JSON evidence on stdout
    sage -python checks.py --live           # also read and check T610 and T609

Needs generate.py, check.py and skill-evidence.json beside this file. The live
mode uses NUMBERDB_API_KEY if the tables require authenticated access. This
script never writes to the website. It compares the global S00 product with a
sum of quantum Weyl dimensions over every integrable weight, not a second call
to the aggregate product. A separate 600-bit evaluation of the exact
cyclotomic number checks the selected embedding and serialized intervals.
"""
import sys
import json
import math
import hashlib
import importlib.metadata
from pathlib import Path
from itertools import combinations
from decimal import Decimal
import numberdb.sage as numberdb
from sage.rings.integer_ring import ZZ
from sage.rings.rational_field import QQ
from sage.rings.real_arb import RealBallField
from sage.rings.complex_arb import ComplexBallField
from sage.env import SAGE_VERSION
from numberdb._write import to_text
from numberdb._generate import _stored_entries
from generate import GlobalDimensions, categories, exact_global, global_ball
from check import exactness, measure, names_its_rings

R = RealBallField(600)
C = ComplexBallField(600)
HERE = Path(__file__).resolve().parent


def qdecimal(text):
    numerator, denominator = Decimal(str(text)).as_integer_ratio()
    return QQ(numerator) / QQ(denominator)


def endpoints(text):
    text = str(text)
    if '.' not in text and 'e' not in text.lower():
        x = QQ(text)
        return x, x
    d = Decimal(text)
    x = qdecimal(text)
    ulp = QQ(10)**int(d.as_tuple().exponent)
    return x-ulp, x+ulp


def interval(text):
    lo, hi = endpoints(text)
    return R(lo).union(R(hi))


def small(ball, minimum=500):
    assert ball.is_finite(), 'nonfinite enclosure'
    assert ball > 0, 'not certified positive'
    assert ball.accuracy() >= minimum, ('insufficient accuracy', ball.accuracy())


def encloses(text, ball):
    small(ball)
    lo, hi = endpoints(text)
    if lo == hi:
        assert lo in ball, ('exact row fails', text, ball)
    else:
        assert ball > R(lo) and ball < R(hi), ('written enclosure fails', text, ball)


def independent_sum(N, k):
    """All integrable weights via strictly increasing shifted partitions.

    b=(0,b1,...,b(N-1)) runs over subsets of {0,...,N+k-1} containing 0.
    Reversing b yields ell_i+N-i and hence every alcove partition once.
    The squared dimension is the product of squared sine differences divided
    by the vacuum product. Summation uses no global-dimension formula.
    """
    m = N + k
    sine2 = [R.zero()] + [(R.pi()*j/m).sin()**2 for j in range(1,m)]
    denominator = R.one()
    for i in range(N):
        for j in range(i+1,N):
            denominator *= sine2[j-i]
    total = R.zero()
    count = 0
    for chosen in combinations(range(1,m),N-1):
        b = (0,) + chosen
        numerator = R.one()
        for i in range(N):
            for j in range(i+1,N):
                numerator *= sine2[b[j]-b[i]]
        total += numerator
        count += 1
    assert count == math.comb(m-1,N-1)
    answer = total / denominator
    small(answer)
    return answer, count


def embedded_exact(N,k):
    x = exact_global(N,k)
    z = (C.pi()*C(0,1)*2/(N+k)).exp()
    v = C.zero()
    for coefficient in reversed(x.polynomial().list()):
        v = v*z + C(coefficient)
    assert v.real().is_finite() and v.imag().is_finite() and 0 in v.imag()
    out=v.real()
    small(out)
    return out


def controls():
    for N,k,answer in [(2,1,2),(2,2,4),(2,4,12),(3,1,3),(3,3,36)]:
        value, _ = independent_sum(N,k)
        assert answer in value
        assert answer+1 not in value
    published,_=independent_sum(2,10)
    assert published.overlaps(24*(2+R(3).sqrt()))
    encloses('2.000000000000000000000000000000',R(2))
    try:
        encloses('3.000000000000000000000000000000',R(2))
    except AssertionError:
        pass
    else:
        raise AssertionError('deliberate-error control failed')
    assert endpoints('2')==(QQ(2),QQ(2))
    assert endpoints('1.25')==(QQ(124)/100,QQ(126)/100)


def main(live=False):
    controls()
    g=GlobalDimensions()
    params=list(g.enumerate())
    expected={(N,k,f) for N,k in categories() for f in ('global','total')}
    assert len(params)==234 and len(expected)==234
    assert len(categories())==117
    values={}
    texts={}
    exact_rows={}
    accuracies=[]
    widths=[]
    for p in params:
        key=(p['N'],p['k'],p['normalisation'])
        value=g.value(p,100)
        values[key]=value
        texts[key]=to_text(value,100)
        if not hasattr(value, 'rad'):
            exact_rows[','.join(map(str,key))]=str(value)
        else:
            small(value,400)
            accuracies.append(int(value.accuracy()))
            widths.append(str(2*value.rad()))
    assert not exactness(values)
    assert not names_its_rings(str(HERE/'generate.py'))
    sums={}
    counts={}
    for N,k in categories():
        sums[N,k],counts[N,k]=independent_sum(N,k)
        algebraic=embedded_exact(N,k)
        assert sums[N,k].overlaps(algebraic),('sum vs exact product',N,k)
        for form,answer in [('global',sums[N,k]),('total',sums[N,k].sqrt())]:
            encloses(texts[N,k,form],answer)
        assert (interval(texts[N,k,'total'])**2).overlaps(interval(texts[N,k,'global']))
        if k==1:
            assert exact_global(N,k)==N
    dual_pairs=0
    for N,k in categories():
        if k>=2:
            assert (k,N) in sums
            assert k*exact_global(N,k)==N*exact_global(k,N)
            assert (k*interval(texts[N,k,'global'])).overlaps(N*interval(texts[k,N,'global']))
            dual_pairs+=1
    for k in range(1,21):
        total=R(QQ(k+2)/2).sqrt()/(R.pi()/(k+2)).sin()
        encloses(texts[2,k,'total'],total)
    table_stored=None
    companion_categories=0
    if live:
        table_stored=numberdb.table('T610')
        stored=_stored_entries(table_stored)
        assert set(stored)=={','.join(map(str,key)) for key in texts}
        for key in texts:
            N,k,form=key
            word=stored[','.join(map(str,key))]
            answer=sums[N,k] if form=='global' else sums[N,k].sqrt()
            encloses(word,answer)
            if key in values and not hasattr(values[key], 'rad'):
                assert endpoints(word)==(QQ(values[key]),QQ(values[key]))
        for N,k in categories():
            D=interval(stored[f'{N},{k},total'])
            G=interval(stored[f'{N},{k},global'])
            assert (D**2).overlaps(G)
            if k>=2:
                assert (k*G).overlaps(N*interval(stored[f'{k},{N},global']))
            if k==1:
                assert endpoints(stored[f'{N},{k},global'])==(QQ(N),QQ(N))
            if N==2:
                rhs=R(QQ(k+2)/2).sqrt()/(R.pi()/(k+2)).sin()
                encloses(stored[f'{N},{k},total'],rhs)
        companion=numberdb.table('T609')
        groups={}
        for identity,text in _stored_entries(companion).items():
            N,k,weight=identity.split(',',2)
            pair=(int(N),int(k))
            groups.setdefault(pair,[]).append(interval(text))
        assert len(groups)==37
        for (N,k),dims in groups.items():
            assert len(dims)==math.comb(N+k-1,N-1)
            s=sum((d*d for d in dims),R.zero())
            small(s,300)
            assert s.overlaps(interval(stored[f'{N},{k},global']))
            assert s.overlaps(sums[N,k])
            companion_categories+=1
    serial=measure(texts)
    serial['longest_at']=list(serial['longest_at'])
    evidence={
      'table':'T610','stage':'build','live_readback_checked':live,
      'skill':json.loads((HERE/'skill-evidence.json').read_text()),
      'versions':{'sage':SAGE_VERSION,'numberdb':importlib.metadata.version('numberdb')},
      'category_count':117,'entry_count':len(texts),'exact_rows':exact_rows,
      'working_bits':numberdb.bits(100,losing=96),'minimum_generator_accuracy_bits':min(accuracies),
      'minimum_independent_sum_accuracy_bits':min(int(x.accuracy()) for x in sums.values()),
      'independent_working_bits':600,
      'independently_summed_simple_objects':sum(counts.values()),
      'largest_alcove':max(counts.values()),
      'duality_oriented_pairs_checked':dual_pairs,
      'companion_alcoves_from_live_T609':companion_categories,
      'serialized_measure':serial,
      'checks':['known-answer and deliberate-error controls','all full-alcove sums',
                'all exact cyclotomic embeddings','all written enclosures',
                'every rational written exactly','positive square-root conversion',
                'all level-rank partners','all level-one global values',
                'all 20 SU(2) totals against Kitaev-Preskill equation (4)'],
      'source_sha256':{n:hashlib.sha256((HERE/n).read_bytes()).hexdigest()
          for n in ['generate.py','checks.py','check.py','argument-selection.md','source-notes.md']},
      'per_category':[{'N':N,'k':k,'alcove_size':counts[N,k],
           'sum_accuracy_bits':int(sums[N,k].accuracy()),
           'global':texts[N,k,'global'],'total':texts[N,k,'total'],
           'global_ball_radius':str(global_ball(N,k,429).rad())} for N,k in categories()]}
    print(json.dumps(evidence,indent=2))
    return evidence


if __name__=='__main__':
    main('--live' in sys.argv)