repair_checks.py

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

4700 bytes, as of the version from 2026-10-25 06:26 (current). Recorded here, not run.

"""Independent repair checks for scaling dimensions -- numberdb.org/T475.

Run: sage -python repair_checks.py document-before.json
Or:  sage -python repair_checks.py --stored < key-file
With agents/sage.sh, mount document-before.json alongside this file, or pipe
the key on stdin and set NUMBERDB_KEY_FROM_STDIN=1 for fresh API values.
No writes; no bootstrap solve or independent precision certification.
"""
import json
import os
import re
import sys
from fractions import Fraction
from pathlib import Path

import numberdb.sage as numberdb
# Initialize Sage's real-field dependency before rational/Python coercions.
from sage.rings.real_mpfr import RealField
from sage.rings.rational_field import QQ
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
from sage.version import version as sage_version


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


def quoted_interval(text):
    center, radius = text.split(' +/- ')
    c, r = rational(center), rational(radius)
    assert 0 < r < QQ(1) / 100
    return c - r, c + r


def parenthetical(text):
    center, uncertainty = re.fullmatch(r'(\d+\.\d+)\((\d+)\)', text).groups()
    c = rational(center)
    r = QQ(uncertainty) / QQ(10)**len(center.split('.')[1])
    return c-r, c+r


def run(document):
    # Known-answer controls for both parsers.
    assert quoted_interval('1.25 +/- 0.001') == (QQ(1249)/1000, QQ(1251)/1000)
    assert parenthetical('1.25(1)') == (QQ(31)/25, QQ(63)/50)
    # Read independently from Chester et al., arXiv:1912.03324v2 (40)-(42)
    # and arXiv:2011.14647v2 (21)-(23), not imported from the generator.
    source = {
        'xy': {'phi': '0.519088(22)', 's': '1.51136(22)', 't': '1.23629(11)'},
        'heisenberg': {'phi': '0.518936(67)', 's': '1.59488(81)', 't': '1.20954(32)'},
    }
    assert list(document['Parameters']) == ['class', 'operator']
    assert set(document['Numbers']) == set(source)
    comparisons = []
    for universality, operators in source.items():
        assert set(document['Numbers'][universality]) == set(operators)
        for operator, text in operators.items():
            actual = quoted_interval(document['Numbers'][universality][operator]['number'])
            assert actual == parenthetical(text)
            comparisons.append({'class': universality, 'operator': operator,
                                'source': text, 'endpoints': list(map(str, actual))})

    ring = PolynomialRing(QQ, names=('alpha', 'beta', 'gamma', 'delta'))
    a, b, g, d = ring.gens()
    rushbrooke = a + 2*b + g - 2
    widom = g - b*(d-1)
    griffiths = a + b*(1+d) - 2
    assert griffiths == rushbrooke - widom
    field = PolynomialRing(QQ, names=('phi', 'singlet')).fraction_field()
    p, s = field.gens()
    eta = 2*p-1
    assert 1+eta == 2*p
    nu = 1/(3-s)
    a, b, g, d = 2-3*nu, p*nu, (3-2*p)*nu, (3-p)/p
    residuals = [a+2*b+g-2, g-b*(d-1), g-nu*(2-eta), 2-a-3*nu,
                 a+b*(1+d)-2]
    assert all(r == 0 for r in residuals)
    count = 0
    for universality in source:
        pl, pu = quoted_interval(document['Numbers'][universality]['phi']['number'])
        sl, su = quoted_interval(document['Numbers'][universality]['s']['number'])
        for phi in (pl, (pl+pu)/2, pu):
            for singlet in (sl, (sl+su)/2, su):
                nu = 1/(3-singlet)
                eta = 2*phi-1
                alpha = 2-3*nu
                beta = phi*nu
                gamma = (3-2*phi)*nu
                delta = (3-phi)/phi
                assert 1+eta == 2*phi
                assert alpha+2*beta+gamma == 2
                assert gamma == beta*(delta-1)
                assert gamma == nu*(2-eta)
                assert 2-alpha == 3*nu
                assert alpha+beta*(1+delta) == 2
                count += 6
    return {'sage_version': sage_version, 'source_interval_checks': comparisons,
            'symbolic_checks': ['Griffiths = Rushbrooke - Widom',
                                'two-point exponent 1+eta = 2*Delta_phi',
                                'all five scaling identities'],
            'exact_substitution_equalities': count,
            'bootstrap_recomputed': False, 'all_passed': True}


if __name__ == '__main__':
    if '--stored' in sys.argv or os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
        client = numberdb.Client(api_key=sys.stdin.read().strip())
        document = numberdb.table('T475', client=client)
    else:
        source_path = Path(sys.argv[1]) if len(sys.argv) > 1 else Path(__file__).with_name('document-before.json')
        document = json.loads(source_path.read_text())
    print(json.dumps(run(document), indent=2))