checks.py

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

10475 bytes, as of the version from 2026-11-01 17:54 (current). Recorded here, not run.

"""Independent numerical and identity checks for numberdb.org/T655.

    sage -python checks.py > numerical-evidence.json
    sage -python checks.py --stored > stored-evidence.json

The second command reads the private draft using NUMBERDB_API_KEY, or stdin
when NUMBERDB_KEY_FROM_STDIN=1. It writes nothing to NumberDB.

The independent computation bisects the reciprocal source equation exactly,
then evaluates Shannon entropy with Arb. It does not call the generator's
stationary polynomial, root-bracketing code, or objective evaluation.
The checks also use the source's reciprocal expression, closed forms at n=2,3,
and its published five-decimal values for n=2..10. Every claimed decimal
interval must contain the whole independent enclosure, not just its midpoint.
"""
import json
import sys
from fractions import Fraction
from pathlib import Path
import platform

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 sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
from sage.version import version as sage_version
from numberdb._write import to_text

CHECK_BITS = 560
CHECK_STEPS = 520
R = RealBallField(CHECK_BITS)
I = RealIntervalField(CHECK_BITS)


def qtext(text):
    value = Fraction(str(text))
    return QQ(value.numerator) / QQ(value.denominator)


def written_bounds(text):
    """A NumberDB decimal denotes its midpoint plus/minus one final place."""
    text = str(text).lower()
    coefficient, exponent = (text.split('e') + ['0'])[:2] if 'e' in text else (text, '0')
    if '.' not in coefficient and 'e' not in text:
        center = qtext(text)
        return center, center
    places = len(coefficient.split('.')[1]) if '.' in coefficient else 0
    unit = QQ(10) ** (int(exponent) - places)
    center = qtext(text)
    return center - unit, center + unit


def finite_narrow(value, digits=130):
    assert value.is_finite() and value > 0
    interval = I(value)
    lo, hi = QQ(interval.lower()), QQ(interval.upper())
    assert (hi-lo) / lo < QQ(1) / (10**digits)
    return lo, hi


def contained(text, value):
    outer_lo, outer_hi = written_bounds(text)
    inner_lo, inner_hi = finite_narrow(value)
    assert outer_lo <= inner_lo <= inner_hi <= outer_hi, text


def independent(n):
    """Use CVZ (31)'s gamma equation, then KSS Lemma 5's entropy."""
    def equation(g):
        return QQ(1)/(g-1) - QQ(n)/(g**n-1) - QQ(n-1)/QQ(3)
    if n == 2:
        lower = upper = QQ(2)
        assert equation(lower) == 0
    else:
        lower, upper = QQ(1), QQ(2)
        assert equation(upper) < 0
        for unused in range(CHECK_STEPS):
            middle = (lower + upper)/QQ(2)
            residual = equation(middle)
            if residual == 0:
                lower = upper = middle
                break
            if residual > 0:
                lower = middle
            else:
                upper = middle
        assert lower > 1
        assert equation(lower) >= 0 >= equation(upper)
    gamma = R(I(lower, upper))
    weights = [gamma**(-j) for j in range(n)]
    normalizer = sum(weights)
    probability = [w/normalizer for w in weights]
    entropy = -sum(p*p.log() for p in probability)
    value = entropy.exp()
    reciprocal_value = ((gamma**n-1)/(gamma-1) *
                        (-R(QQ(2*(n-1))/QQ(3))*gamma.log()).exp())
    finite_narrow(value); finite_narrow(reciprocal_value)
    assert (value-reciprocal_value).contains_zero()
    assert (sum(probability)-1).contains_zero()
    assert (sum(j*probability[j] for j in range(n))-R(QQ(n-1)/QQ(3))).contains_zero()
    variance = sum((R(j)-R(QQ(n-1)/QQ(3)))**2*probability[j] for j in range(n))
    assert variance > 0
    return value, reciprocal_value, {'n':n,'gamma_lower':str(lower),'gamma_upper':str(upper),
                                     'endpoint_signs_certified':True,
                                     'entropy_ball':str(value),'reciprocal_ball':str(reciprocal_value)}


def records_of(document):
    # The website exports the two ordered parameters as a nested mapping.
    numbers=document['Numbers']
    if isinstance(numbers,list):
        return numbers
    result=[]
    for n, conventions in numbers.items():
        for convention, entry in conventions.items():
            if isinstance(entry,str): entry={'number':entry}
            result.append({'params':{'n':str(n),'convention':convention},**entry})
    return result


def run(document=None):
    from generate import EllenbergGijswijt, constant, root_bracket
    gen=EllenbergGijswijt()
    # Controls run before any family comparison.
    assert written_bounds('3.14') == (QQ(313)/100, QQ(315)/100)
    control=R(QQ(1)/QQ(3))
    control_entropy=-control*control.log()-(1-control)*(1-control).log()
    closed2=R(3)/R(2)**(R(2)/3)
    assert (control_entropy.exp()-closed2).contains_zero()
    assert R(1) < closed2 < R(2)
    finite_narrow(closed2)
    independent2,other2,unused=independent(2)
    assert (independent2-closed2).contains_zero()
    assert not (independent2-R(2)).contains_zero()
    closed3=R(3)*(R(207)+33*R(33).sqrt())**(R(1)/3)/8
    finite_narrow(closed3)

    if document is None:
        records=[]
        for params in gen.enumerate():
            entry=dict(gen.value(params,100))
            entry['number']=to_text(entry['number'],digits=100)
            records.append({'params':params,**entry})
    else:
        records=records_of(document)
    expected=[(n,c) for n in range(2,33) for c in ('subrank','per-dimension')]
    actual=[(int(r['params']['n']),r['params']['convention']) for r in records]
    assert actual == expected
    written={key:r['number'] for key,r in zip(actual,records)}
    poly=PolynomialRing(QQ,'x'); x=poly.gen()
    certificates=[]; accuracies=[]; largest_width=QQ(0)
    rounded={2:'1.88988',3:'2.75510',4:'3.61072',5:'4.46158',6:'5.30973',
             7:'6.15620',8:'7.00155',9:'7.84612',10:'8.69012'}
    prev_j=None
    for n in range(2,33):
        c, reciprocal, certificate=independent(n)
        # Exact coefficient identity, independent of numerical root residuals.
        s=sum(x**j for j in range(n))
        p=3*x*s.derivative()-(n-1)*s
        assert p == sum((3*j-n+1)*x**j for j in range(n))
        reverse=sum((3*j-n+1)*x**(n-1-j) for j in range(n))
        assert (x-1)**2*reverse == 3*(x**n-1)-3*n*(x-1)-(n-1)*(x-1)*(x**n-1)
        lo,hi=root_bracket(n,numberdb.bits(100,losing=128)+32)
        if lo==hi: assert p(lo)==0
        else: assert p(lo)<0<p(hi)
        certificate.update(rho_lower=str(lo),rho_upper=str(hi))
        generated=constant(n,100)
        finite_narrow(generated)
        assert (generated-c).contains_zero()
        assert generated > 1 and generated < n
        glo, ghi = finite_narrow(generated)
        relative_width = (ghi-glo)/glo
        retained_bits = 0
        while relative_width < QQ(1)/(2**(retained_bits+1)):
            retained_bits += 1
        accuracies.append(retained_bits)
        for conv,value in [('subrank',c),('per-dimension',c/n)]:
            contained(written[n,conv],value)
            contained(written[n,conv],reciprocal if conv=='subrank' else reciprocal/n)
            inner=generated if conv=='subrank' else generated/n
            contained(written[n,conv],inner)
            lower,upper=finite_narrow(inner)
            largest_width=max(largest_width,(upper-lower)/lower)
        assert (R(I(*written_bounds(written[n,'subrank']))) -
                n*R(I(*written_bounds(written[n,'per-dimension'])))).contains_zero()
        if prev_j is not None: assert prev_j > c/n
        prev_j=c/n
        if n in rounded:
            contained(rounded[n],c)
            # Source calls these rounded, so also test half a final place.
            assert abs(c-R(qtext(rounded[n]))) < R(QQ(1)/200000)
        if n==2: contained(written[n,'subrank'],closed2)
        if n==3:
            contained(written[n,'subrank'],closed3)
            assert (c-closed3).contains_zero()
        certificates.append(certificate)

    local=Path(__file__).parent
    companion=json.loads((local/'entropy-reference.json').read_text()) if (local/'entropy-reference.json').exists() else numberdb.table('T339')
    bernoulli=companion['Numbers']['bernoulli']['1/3']
    for unit in ('nats','bits'):
        text=bernoulli[unit]
        if isinstance(text,dict): text=text['number']
        value=control_entropy if unit=='nats' else control_entropy/R(2).log()
        contained(text,value)
    evidence={
        'table':'T655','mode':'stored' if document is not None else 'preflight',
        'skill_manifest':'agents/runs/20261101T164559Z-build-skills/manifest.json',
        'skill_sha256':'a2b28d9953264d7b0ca62663785c2952190c5be6d6d3597fd695d9a54d606278',
        'versions':{'sage':sage_version,'python':platform.python_version(),'numberdb':numberdb.__version__},
        'entries':len(records),
        'serialized_longest_characters':max(len(r['number']) for r in records),
        'serialized_records_json_bytes':len(json.dumps(records).encode('utf8')),
        'dimensions':31,'conventions':['subrank','per-dimension'],
        'digits':100,'minimum_generator_accuracy_bits':min(accuracies),
        'maximum_generator_relative_interval_width':str(R(largest_width)),
        'independent_precision_bits':CHECK_BITS,'independent_bisection_steps':CHECK_STEPS,
        'checks':{'all_decimal_intervals_contain_both_computations':True,
                  'independent_entropy_and_reciprocal_expressions_agree':True,
                  'positive_finite_narrow_enclosures':True,'closed_forms_2_3':True,
                  'source_rounded_values_2_through_10':True,
                  'stationary_and_reciprocal_polynomial_identities_all_dimensions':True,
                  'normalization_conversion_all_dimensions':True,
                  'probability_sum_mean_and_positive_variance_all_dimensions':True,
                  'J_decreases_over_selected_dimensions':True,
                  'T339_bernoulli_one_third_nats_and_bits':True,
                  'control_rejects_incorrect_value_two':True},
        'root_certificates':certificates,'records':records}
    return evidence


if __name__=='__main__':
    from generate import configure_from_stdin
    configure_from_stdin()
    document=numberdb.table('T655') if '--stored' in sys.argv else None
    print(json.dumps(run(document),indent=2,ensure_ascii=False))