checks.py

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

6158 bytes, as of the version from 2026-11-02 08:35 (current). Recorded here, not run.

"""Independent controls and whole-range identities for numberdb.org/T672.

    sage -python checks.py                 # compute and test every value
    sage -python checks.py --stored        # test stored values; key on stdin

Printed DMO character data are retained unmodified in source-controls.json.
For the character evaluation only, use CTblLib's independent first nine
columns. The exact discrepancy and its mathematical diagnosis are recorded
there. These checks are build evidence, not an independent campaign critique.
"""
import json,sys
from pathlib import Path
import numberdb.sage as numberdb
from sage.rings.integer_ring import ZZ
from sage.rings.rational_field import QQ
from sage.rings.complex_arb import ComplexBallField
from generate import ONanCoefficients,CLASSES,MAX_GRADE,coefficients,isolate_integer,cosets,hauptmodul,FIRST

HERE=Path(__file__).parent

def plain(x):
    return x['number'] if isinstance(x,dict) else x


def expected_representation(control):
    return {(g,int(n)):ZZ(sum(control['gap_characters'][j][i]*m[j] for j in range(30)))
            for n,m in control['multiplicities'].items()
            for i,g in enumerate(control['classes'])}


def check_values(values):
    control=json.loads((HERE/'source-controls.json').read_text())
    companion=json.loads((HERE/'companion-controls.json').read_text())
    # Independently expand each eta product through q^1 with integer products.
    def mul(a,b):
        return [sum(a[j]*b[k-j] for j in range(k+1)) for k in range(3)]
    for N in range(2,8):
        exponents=({1:5,2:-1,3:1,6:-5} if N==6 else
                   {1:{2:24,3:12,4:8,5:6,7:4}[N],N:-{2:24,3:12,4:8,5:6,7:4}[N]})
        product=[1,0,0]
        for d,e in exponents.items():
            for k in range(d,3,d):
                factor=[1,-e,e*(e-1)//2] if k==1 else [1,0,-e]
                product=mul(product,factor)
        assert product[2]==FIRST[N]
    assert FIRST[1]==ZZ(companion['T79']['numbers']['1'])
    for N,monst in [(1,'1A'),(2,'2B'),(3,'3B'),(5,'5B'),(7,'7B')]:
        assert companion['T635']['numbers'][monst]['2']==f'X^2 - {2*FIRST[N]}'
    grades=[n for n in range(3,MAX_GRADE+1) if n%4 in (0,3)]
    assert list(values)==[(g,n) for g in CLASSES for n in grades]
    assert control['classes']==list(CLASSES)
    assert control['characters'][21][7]==5 and control['gap_characters'][21][7]==-5
    assert control['gap_characters'][20][:9]==control['gap_characters'][21][:9]
    assert (169290-(-5))%7==0 and (169290-5)%7!=0
    rep=expected_representation(control)
    assert rep['1A',3]==26752 and rep['1A',4]==143376 and rep['7A',7]==4
    errors=[(k,str(v),str(rep[k])) for k,v in values.items() if k in rep and v!=rep[k]]
    assert not errors,errors[:10]
    for n in grades:
        t=companion['T643']['numbers']
        assert values['1A',n]==(ZZ(plain(t['2'][str(n)]))-ZZ(plain(t['1'][str(n)])))/2
        assert values['4A',n]==values['4B',n]
        assert values['7A',n]==values['7B',n]
        for g,mod in [('3A',243),('5A',125),('7A',343)]:
            assert (values['1A',n]-values[g,n])%mod==0,(g,n,mod)
        assert (values['2A',n]-values['6A',n])%9==0
        if n%4==3:assert values['4A',n]==0
    degrees=companion['T255']['numbers']['ON']
    assert values['1A',3]==ZZ(plain(degrees['7']))
    assert values['1A',4]==1+ZZ(plain(degrees['12']))+ZZ(plain(degrees['18']))
    # A wrong sign must be detected by the external representation control.
    mutated=dict(values);mutated['7A',7]=-mutated['7A',7]
    assert mutated['7A',7]!=rep['7A',7]
    return {'entries':len(values),'character_decomposition_comparisons':len(rep),
            'zagier_trace_comparisons':len(grades),'alias_comparisons':2*len(grades),
            'prime_power_congruences':4*len(grades),'degree_comparisons':2,
            'order_four_odd_grade_zeros':sum(n%4==3 for n in grades),
            'hauptmodul_normalization_checks':7,'faber_companion_checks':5}


def ball_controls():
    C=ComplexBallField(1024)
    assert isolate_integer(C(26752))==26752
    # Known modular values control normalization before any trace is believed.
    assert 984 in hauptmodul(1,C(0,1)).real()
    assert 536 in hauptmodul(2,C(0,1)).real()
    for bad in [C(QQ(3)/2),C(2,1),C(C(0).real().parent()('0 +/- 2')),C('nan')]:
        try:isolate_integer(bad)
        except (AssertionError,ValueError,TypeError):pass
        else:raise AssertionError('Bad enclosure accepted')


def run(stored=False):
    ball_controls()
    if stored:
        doc=numberdb.table('T672')
        block=doc['Numbers']
        if isinstance(block,list):
            values={(r['params']['g'],int(r['params']['n'])):ZZ(r['number']) for r in block}
        else:
            values={(g,int(n)):ZZ(plain(v)) for g,rows in block.items() for n,v in rows.items()}
    else:
        gen=ONanCoefficients()
        values={(p['g'],int(p['n'])):gen.value(p,100) for p in gen.enumerate()}
    stats=check_values(values)
    # Higher precision is a stability check, not the independent algorithm.
    maxradius=0
    for n in range(3,MAX_GRADE+1):
        if n%4 not in (0,3):continue
        high=coefficients(n,1280)
        for N,(v,ball) in high.items():
            assert v==values[str(N)+'A',n]
            maxradius=max(maxradius,ball.real().rad(),ball.imag().rad())
    stats['higher_precision_coefficient_checks']=700
    stats['maximum_1024_bit_component_radius']=str(max(ball.real().rad() for n in range(3,MAX_GRADE+1) if n%4 in (0,3) for v,ball in coefficients(n).values()))
    stats['maximum_1280_bit_component_radius']=str(maxradius)
    stats['negative_entries']=sum(v<0 for v in values.values())
    stats['zero_entries']=sum(v==0 for v in values.values())
    stats['max_characters']=max(len(str(v)) for v in values.values())
    stats['stored']=stored
    print('CHECKS_JSON',json.dumps(stats,sort_keys=True))
    if not stored:
        print('VALUES_JSON',json.dumps([{'params':{'g':g,'n':str(n)},'number':str(v)} for (g,n),v in values.items()]))
    return stats


if __name__=='__main__':
    stored='--stored' in sys.argv
    if stored:numberdb.configure(api_key=sys.stdin.read().strip())
    run(stored)