checks.py

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

8001 bytes, as of the version from 2026-10-24 20:50 (current). Recorded here, not run.

"""Checks for non-phi4 Feynman periods -- numberdb.org/T466.

Run beside the attached generator and census:
    sage -python checks.py
    NUMBERDB_API_KEY=... sage -python checks.py --stored

Uses Arb zeta values independently of PARI, a known alternating depth-two
identity, a bounded finite double sum, exact graph tests, and source decimals.
The stored mode applies the comparisons to the decimals returned by the API.
"""
import numberdb.sage as numberdb
from sage.rings.real_arb import RealBallField
from sage.rings.rational_field import QQ
from sage.rings.real_mpfr import RealField
import ast,json,math,os,re,sys
from collections import Counter
from decimal import Decimal
from fractions import Fraction
from pathlib import Path
from generate import (NonPhi4Periods, records,compute,comparison,zeta,field,
                      wheel_labels,aliases)
from parse_census import canonical
from check import exactness,measure,names_its_rings,agrees_with
from numberdb._write import to_text
from numberdb._generate import _stored_entries

B=RealBallField(700)

def exact_decimal(text):
    f=Fraction(Decimal(str(text)))
    return QQ(f.numerator)/QQ(f.denominator)

def check_decimal(written,expected):
    """Test containment within the actual one-ULP interval of written digits."""
    centre=exact_decimal(written)
    exponent=Decimal(written).as_tuple().exponent
    ulp=QQ(10)**exponent
    assert expected.is_finite() and B(expected.rad())<B(ulp)/1000
    assert expected.lower()>B(centre-ulp).upper()
    assert expected.upper()<B(centre+ulp).lower()

def connected(vertices,edges):
    seen={next(iter(vertices))}
    while True:
        new=seen|{v for edge in edges if any(w in seen for w in edge) for v in edge}
        if new==seen:return seen==vertices
        seen=new

def graph_checks():
    count=0
    for key,row in records().items():
        edges=row['edges']; infinity=max(v for e in edges for v in e['vertices'])
        assert all(sum(e['weight'] for e in edges if v in e['vertices'])==4
                   for v in range(infinity+1)),('weighted degree',key)
        assert all(infinity in e['vertices'] for e in edges if e['weight']<0)
        es=[tuple(e['vertices']) for e in edges if infinity not in e['vertices']]
        vertices=set(range(infinity));n=len(vertices);m=len(es)
        assert len(set(tuple(sorted(e)) for e in es))==m
        assert connected(vertices,es)
        assert m==2*(m-n+1)==2*row['loops']
        assert max(sum(v in e for e in es) for v in vertices)>4
        # In a proper vertex subset, the induced graph maximizes edge count.
        # Checking all subsets proves N_gamma > 2h_gamma for every proper
        # connected edge subgraph; components then give the general case.
        for mask in range(1,(1<<n)-1):
            size=mask.bit_count()
            if size<2:continue
            induced=sum(bool(mask&(1<<a)) and bool(mask&(1<<b)) for a,b in es)
            assert induced<=2*size-3,('not primitive',key,mask)
        count+=1
    return count

def independent_single_zeta(expression):
    """A second arithmetic evaluator using Arb, only for single zeta terms."""
    def visit(n):
        if isinstance(n,ast.Constant) and type(n.value) is int:return B(n.value)
        if isinstance(n,ast.Name) and n.id=='Pi':return B.pi()
        if isinstance(n,ast.UnaryOp):
            a=visit(n.operand)
            return -a if isinstance(n.op,ast.USub) else a
        if isinstance(n,ast.Subscript):
            k=ast.literal_eval(n.slice)
            assert type(k) is int and k>1
            return B(k).zeta()
        assert isinstance(n,ast.BinOp)
        a=visit(n.left)
        if isinstance(n.op,ast.Pow):return a**int(ast.literal_eval(n.right))
        b=visit(n.right)
        if isinstance(n.op,ast.Add):return a+b
        if isinstance(n.op,ast.Sub):return a-b
        if isinstance(n.op,ast.Mult):return a*b
        if isinstance(n.op,ast.Div):return a/b
        raise ValueError(ast.dump(n))
    return visit(ast.parse(expression.replace('^','**'),mode='eval').body)

def controls():
    # Nonzero known answers, before using either library as a check.
    assert (B(2).zeta()-B.pi()**2/6).contains_zero()
    assert B(3).zeta()>1
    R=field(200)
    assert abs(zeta((2,1),False,200)-R(B(3).zeta().mid()))<R(10)**-190
    assert abs(zeta((3,1),False,200)-R((B(4).zeta()/4).mid()))<R(10)**-190
    assert abs(zeta((1,1),True,200)-R((B(2).log()**2/2).mid()))<R(10)**-190
    assert abs(zeta((3,),True,200)+R((QQ(3)/4*B(3).zeta()).mid()))<R(10)**-190
    # Independent finite nested sum; tail < zeta(3)/(4 N^4).
    R=RealField(200);h=R(0);s=R(0);N=10000
    for n in range(1,N+1):
        s+=h/R(n)**5
        h+=1/R(n)**3
    gap=R(zeta((5,3),False,200))-s
    assert R('0.03')<s<R('0.04') and 0<gap<R(B(3).zeta().mid())/(4*R(N)**4)
    return {'zeta21':'zeta(3)','zeta31':'zeta(4)/4','Li11(-1)':'log(2)^2/2',
            'Li3(-1)':'-3*zeta(3)/4','zeta53_partial_sum_terms':N,'zeta53_tail_bound':str(R(B(3).zeta().mid())/(4*R(N)**4))}

def main(stored=False):
    control_report=controls()
    graph_count=graph_checks()
    g=NonPhi4Periods()
    values={f"{p['loops']},{p['index']}":g.value(p,100) for p in g.enumerate()}
    assert not exactness(values)
    assert not names_its_rings(str(Path(__file__).with_name('generate.py')))
    if stored:
        written=_stored_entries(numberdb.table('T466'))
        assert set(written)==set(values)
    else:written={k:to_text(v['number'],digits=100) for k,v in values.items()}
    single_count=0;source_max=0;agreement_min=999
    for key,text in written.items():
        row=records()[key];ex=row['expression'];source=row['source_decimal']
        high=compute(ex,200)
        delta=abs(high-field(200)(source))*field(200)(10)**len(source.split('.')[1])
        assert delta<1
        source_max=max(source_max,float(delta));agreement_min=min(agreement_min,comparison(ex))
        # The stored rounding must also contain the recomputation. This is
        # an arithmetic comparison, not a claim that PARI gives a ball.
        mid=field(200)(text);ulp=field(200)(10)**Decimal(text).as_tuple().exponent
        assert abs(high-mid)<ulp
        if not re.search(r'zeta\[[^\]]*,',ex):
            check_decimal(text,independent_single_zeta(ex));single_count+=1
    expected_wheels={'5,1':5,'6,1':6,'7,21':7,'8,162':8}
    assert wheel_labels()==expected_wheels
    # Check helper performs an exact comparison of two 100-digit spellings.
    wheel_text={k:written[k] for k in expected_wheels}
    independent=lambda k:to_text(math.comb(2*expected_wheels[k]-2,expected_wheels[k]-1)*B(2*expected_wheels[k]-3).zeta(),digits=100)
    assert not agrees_with(wheel_text,independent)
    for key,target in aliases().items():
        assert canonical(records()[key]['expression'])==canonical(records()[target]['expression'])
        assert written[key]==written[target]
    cross=json.loads(Path(__file__).with_name('cross-equality-proofs.json').read_text())
    phi=_stored_entries(numberdb.table('T464')) if stored else json.loads(Path(__file__).with_name('cross-source-values.json').read_text())
    for key,item in cross.items():
        assert canonical(item['phi4_expression'])==canonical(item['nonphi4_expression'])
        assert abs(exact_decimal(written[key])-exact_decimal(phi[item['target']]))<=QQ(10)**Decimal(written[key]).as_tuple().exponent
    summary={'stored':stored,'values_checked':len(written),'graph_checks':graph_count,'independent_arb_single_zeta_entries':single_count,'wheels':expected_wheels,'cross_table_equalities':len(cross),'internal_equalities':len(aliases()),'max_source_error_ulps':source_max,'min_agreement_digits':agreement_min,'measurement':measure(values),'controls':control_report}
    print(json.dumps(summary,indent=2))
    return summary

if __name__=='__main__':
    if os.environ.get('NUMBERDB_KEY_FROM_STDIN'):numberdb.configure(api_key=sys.stdin.read().strip())
    main('--stored' in sys.argv or os.environ.get('CHECK_STORED')=='1')