checks.py

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

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

"""Independent checks for numberdb.org/T594.

Run: sage -python checks.py > checks-output.jsonl
The final JSON record contains numerical evidence and reproducibility outputs.
With --stored (or NUMBERDB_CHECK_STORED=1) read T594 and check every written
interval against the independently obtained exact number. Supply a key for
the private draft via NUMBERDB_API_KEY, or NUMBERDB_KEY_FROM_STDIN=1.

The independent algorithm sums edge subsets by degree parity at each vertex.
It tracks the number of odd-degree completed vertices up to four, giving
W_j(t) = sum_{A: |odd(A)|=j} t^|A| for j=0,2,4, with integer coefficients.
It never calls the spin-transfer routine to build those polynomials.

Expansion of cosh(H)^N sum_j W_j(t) tanh(H)^j gives
D2 = N W0 + 2 W2 and
D4 = (3N^2-2N)W0 + (12N-16)W2 + 24W4.
At t=tanh(Kc)=sqrt(2)-1, the moments are D2/W0 and D4/W0.
Control: the edgeless single vertex has W0=1, W2=W4=0, hence M2=M4=1,
U=2/3. A single bond has W0=1,W2=t,W4=0, M2=2+2t, M4=8+8t.
These nonzero known answers run before the rectangle checks.

The complete even-subgraph polynomial W0 also recovers every coefficient of
P(1,b), independently of the spin-cut construction. Direct enumeration of
spin assignments checks all bivariate coefficients for N <= 16.
"""
import os
import sys
import json
import time
import hashlib
import platform
import importlib.metadata
from collections import Counter, defaultdict
from math import comb
from pathlib import Path

import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.real_arb import RealBallField
from sage.rings.real_mpfi import RealIntervalField
from numberdb._write import to_text
from generate import BinderCumulants, BC, FIELD, A, cut_counts, moment_sums, exact_cumulant


def odd_subgraph_polynomials(width, height):
    """Independent edge-subset transfer; each edge is chosen or omitted once."""
    edges = 2*width*height-width-height
    bits = edges+1
    radix_mask = (1 << bits)-1
    dp = {(0,0):1}
    for row in range(height):
        for col in range(width):
            nxt = defaultdict(int)
            for (mask, odd), polynomial in dp.items():
                incoming = (mask >> col) & 1
                for right in range(2 if col+1 < width else 1):
                    for down in range(2 if row+1 < height else 1):
                        count = odd + (incoming ^ right ^ down)
                        if count > 4:
                            continue
                        newmask = mask & ~(1 << col)
                        if right:
                            newmask ^= 1 << (col+1)
                        if down:
                            newmask |= 1 << col
                        nxt[newmask, count] += polynomial << (bits*(right+down))
            dp = nxt
    answer = {}
    for odd in (0,2,4):
        packed = dp.get((0,odd),0)
        answer[odd] = [(packed >> (bits*j)) & radix_mask for j in range(edges+1)]
    assert all(mask==0 and odd%2==0 for mask,odd in dp)
    return answer


def poly_at(coefficients, x):
    answer = x.parent()(0)
    for c in reversed(coefficients):
        answer = answer*x + c
    return answer


def independent_moments(width,height,t=BC):
    p=odd_subgraph_polynomials(width,height)
    w0,w2,w4=[poly_at(p[k],t) for k in (0,2,4)]
    sites=width*height
    m2=(sites*w0+2*w2)/w0
    m4=((3*sites*sites-2*sites)*w0+(12*sites-16)*w2+24*w4)/w0
    return m2,m4,p


def high_to_cut(w0,sites,edges):
    """Clear powers of two in the high-temperature identity coefficientwise."""
    coefficients=[]
    for j in range(edges+1):
        val=sum(c*sum((-1)**r*comb(l,r)*comb(edges-l,j-r)
                       for r in range(max(0,j-(edges-l)),min(l,j)+1))
                for l,c in enumerate(w0) if c)
        if edges >= sites:
            divisor=1 << (edges-sites)
            assert val % divisor == 0
            val //= divisor
        else:
            val *= 1 << (sites-edges)
        coefficients.append(val)
    return coefficients


def brute_spins(m,n):
    # Explicit graph edges, independently of row bit transitions.
    edges=[(r*n+c,r*n+c+1) for r in range(m) for c in range(n-1)]
    edges += [(r*n+c,(r+1)*n+c) for r in range(m-1) for c in range(n)]
    counts=Counter()
    for state in range(1 << (m*n)):
        spins=[1-2*((state >> v)&1) for v in range(m*n)]
        k=sum(s==-1 for s in spins)
        d=sum(spins[u]!=spins[v] for u,v in edges)
        counts[k,d]+=1
    return dict(counts)


def exact_enclosure(x,prec=600):
    balls=RealBallField(prec)
    return balls(QQ(x[0]))+balls(QQ(x[1]))*balls(2).sqrt()


def serialized_contains(text,x):
    """Check the full declared decimal interval using exact rational endpoints."""
    # Current table emits plain decimals; reject other forms rather than guess.
    sign=-1 if text.startswith('-') else 1
    t=text.lstrip('+-');assert '.' in t and 'e' not in t.lower()
    whole,fraction=t.split('.')
    center=QQ(sign*int(whole+fraction))/QQ(10**len(fraction))
    ulp=QQ(1)/QQ(10**len(fraction))
    interval=RealIntervalField(600)(exact_enclosure(x))
    assert QQ(interval.lower()) > center-ulp
    assert QQ(interval.upper()) < center+ulp
    return True


def run_checks(stored_document=None):
    start=time.monotonic()
    # Controls are run before any measurements are believed.
    m2,m4,p=independent_moments(1,1)
    assert p=={0:[1],2:[0],4:[0]}
    assert m2==m4==1
    assert FIELD(1)-m4/(3*m2*m2)==QQ(2)/3
    m2,m4,p=independent_moments(1,2)
    assert p=={0:[1,0],2:[0,1],4:[0,0]}
    assert m2==2+2*BC and m4==8+8*BC
    assert cut_counts(1,2)==brute_spins(1,2)
    assert exact_cumulant(2,2)==QQ(1)/8+A/4
    print(json.dumps({'controls':'single spin, single bond, four-cycle passed'}),flush=True)
    g=BinderCumulants(); rows=[]; all_counts={}; minbits=100000
    stored={}
    if stored_document is not None:
        block=stored_document['Numbers']
        if isinstance(block,list):
            for entry in block:
                p=entry['params']
                stored[int(p['m']),int(p['n'])]=entry['number']
        else:
            for m,group in block.items():
                for n,entry in group.items():
                    stored[int(m),int(n)]=entry['number'] if isinstance(entry,dict) else entry
        assert set(stored)=={(p['m'],p['n']) for p in g.enumerate()}
    for params in g.enumerate():
        m,n=params['m'],params['n']; sites=m*n;edges=2*sites-m-n
        counts=cut_counts(m,n)
        assert sum(counts.values()) == 2**sites
        # P(z,1)=(1+z)^N, P(z,0)=1+z^N, and spin reversal.
        assert {k:sum(c for (kk,d),c in counts.items() if kk==k)
                for k in range(sites+1)}=={k:comb(sites,k) for k in range(sites+1)}
        assert {(k,d):c for (k,d),c in counts.items() if d==0}=={(0,0):1,(sites,0):1}
        assert all(counts.get((sites-k,d),0)==c for (k,d),c in counts.items())
        assert cut_counts(n,m)==counts
        if sites <=16:
            assert brute_spins(m,n)==counts
        h2,h4,hpoly=independent_moments(m,n)
        f=high_to_cut(hpoly[0],sites,edges)
        assert f==[sum(c for (k,dd),c in counts.items() if dd==d) for d in range(edges+1)]
        s0,s2,s4=moment_sums(m,n)
        assert h2==s2/s0 and h4==s4/s0
        independent_u=FIELD(1)-h4/(3*h2*h2)
        assert independent_u==exact_cumulant(m,n)
        # Infinite-temperature independent spins and zero-temperature aligned spins.
        q0,q2,q4=moment_sums(m,n,QQ(1))
        assert q2/q0==sites and q4/q0==3*sites*sites-2*sites
        assert 1-q0*q4/(3*q2*q2)==QQ(2)/(3*sites)
        q0,q2,q4=moment_sums(m,n,QQ(0))
        assert q2/q0==sites**2 and q4/q0==sites**4
        assert 1-q0*q4/(3*q2*q2)==QQ(2)/3
        # Independent positive-weight ball evaluation avoids the quadratic basis.
        ball=RealBallField(600); b=ball(2).sqrt()-1
        q0,q2,q4=moment_sums(m,n,b)
        direct=1-q0*q4/(3*q2*q2)
        assert direct.is_finite() and direct.accuracy()>500
        val=g.value(params,100)
        assert val.is_finite() and 0<val<QQ(2)/3
        assert val.overlaps(direct)
        bits=int(val.accuracy());minbits=min(minbits,bits)
        text=to_text(val,digits=100)
        serialized_contains(text,independent_u)
        if stored:
            serialized_contains(str(stored[m,n]),independent_u)
        rows.append({'m':m,'n':n,'number':text,'relative_accuracy_bits':bits,
                     'exact_coefficients':[str(QQ(independent_u[i])) for i in (0,1)],
                     'moment2_coefficients':[str(QQ(h2[i])) for i in (0,1)],
                     'moment4_coefficients':[str(QQ(h4[i])) for i in (0,1)],
                     'independent_edge_check':True,'all_even_subgraph_coefficients':True,
                     'direct_spin_enumeration':sites<=16,'stored_interval_checked':bool(stored)})
        all_counts[f'{m},{n}']=[[k,d,c] for (k,d),c in sorted(counts.items())]
        print(json.dumps({'checked':[m,n],'relative_accuracy_bits':bits}),flush=True)
    # Record versions and policy binding with the actual evidence.
    manifest='agents/runs/20261028T234955Z-build-skills/manifest.json'
    skill_hash='28ecbeeccb0c5e5d6eb541b5a5b0f88aec47b154374d909085116d34f5629199'
    evidence={'table':'T594','skill_manifest':manifest,
              'skill_sha256':{'local':skill_hash,'live':skill_hash},
              'versions':{'python':platform.python_version(),
                          'sage':__import__('sage.version', fromlist=['version']).version,
                          'numberdb':importlib.metadata.version('numberdb')},
              'entries':len(rows),'minimum_relative_accuracy_bits':minbits,
              'working_bits':numberdb.bits(100,losing=96),
              'longest_serialized_number':max(len(r['number']) for r in rows),
              'number_characters':sum(len(r['number']) for r in rows),
              'direct_enumeration_rectangles':sum(r['direct_spin_enumeration'] for r in rows),
              'seconds':time.monotonic()-start,'all_checks_passed':True,'rows':rows}
    return {'numerical_evidence':evidence,'cut_counts':all_counts}


if __name__=='__main__':
    document=None
    if os.environ.get('NUMBERDB_KEY_FROM_STDIN')=='1':
        key=sys.stdin.read().strip()
        if '=' in key and key.split('=',1)[0].replace('_','').isalnum():
            key=key.split('=',1)[1].strip().strip('\"\'')
        os.environ['NUMBERDB_API_KEY']=key
        document=numberdb.table('T594')
    if '--stored' in sys.argv or os.environ.get('NUMBERDB_CHECK_STORED')=='1':
        document=numberdb.table('T594')
    print(json.dumps(run_checks(document)),flush=True)