repair_checks_20261025.py

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

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

"""Reproduce and check the eight measured rows of numberdb.org/T476.

Run with SageMath and numberdb installed:
    sage -python repair_checks.py < api-key-file
For a public table, run without redirected input. No writes are performed.

This reproduces a transcription, not the Monte Carlo simulations. SOURCE
is independently read from Table III (page 15) of arXiv:1004.4983v3.
EARLIER uses Table 1 (page 6) of arXiv:cond-mat/0201180 and equations
(45)-(46) (page 22) of arXiv:hep-lat/9701007. All arithmetic is exact.
The printed uncertainties remain measurements, not proven bounds.
"""
import json
import re
import sys
from importlib.metadata import version

import numberdb.sage as numberdb
# Sage rational coercion inspects this module even for exact arithmetic.
import sage.rings.real_mpfr
from sage.rings.rational_field import QQ
from sage.version import version as sage_version

SOURCE = {
    'U0': '0.536(2)', 'U2': '4.713(7)', 'Uxi': '1.939(5)',
    'Qxi-minus': '1.020(5)', 'Q-plus': '0.01899(10)',
    'Q-minus': '0.00487(2)', 'u-star': '14.08(5)', 'Qc': '0.3293(2)',
}
EARLIER = {
    'U0': '0.532(3)', 'U2': '4.76(2)', 'Uxi': '1.956(7)',
    'Qxi-minus': '1.017(7)', 'Q-plus': '0.01880(8)',
    'Q-minus': '0.00472(5)', 'u-star': '14.3(1)', 'Qc': '0.3315(10)',
}


def decimal(text):
    whole, frac = text.split('.')
    return QQ(int(whole + frac)) / QQ(10 ** len(frac))


def published(text):
    match = re.fullmatch(r'(\d+\.\d+)\((\d+)\)', text)
    assert match, text
    centre, error = match.groups()
    return decimal(centre), QQ(int(error)) / QQ(10 ** len(centre.split('.')[1]))


def stored(text):
    centre, radius = text.split(' +/- ')
    return decimal(centre), decimal(radius)


def generate_rows():
    """Yield the exact printed centre and radius, with the source's precision."""
    for name, text in SOURCE.items():
        centre, error = re.fullmatch(r'(\d+\.\d+)\((\d+)\)', text).groups()
        places = len(centre.split('.')[1])
        radius = '0.' + error.zfill(places)
        yield name, centre + ' +/- ' + radius


def disjoint(a, b):
    return abs(a[0] - b[0]) > a[1] + b[1]


def check(document):
    # Known positive and negative controls establish the parsing and comparison.
    assert published('0.01899(10)') == (QQ(1899)/100000, QQ(1)/10000)
    assert stored('0.01899 +/- 0.00010') == published('0.01899(10)')
    assert not disjoint((QQ(1), QQ(1)/10), (QQ(1), QQ(1)/20))
    assert disjoint((QQ(1), QQ(1)/10), (QQ(2), QQ(1)/20))
    assert published('0.01899(10)') != stored('0.01899 +/- 0.00001')
    assert list(document['Numbers']) == list(SOURCE)
    assert document['Data properties']['rigour'] == 'measured'
    results = {}
    for name, number in generate_rows():
        entry = document['Numbers'][name]
        now = stored(entry['number'])
        assert now == published(SOURCE[name]) == stored(number), name
        assert 'CITE{Hasenbusch2010}' in entry['comment'], name
        earlier = published(EARLIER[name])
        distance_squared = (now[0] - earlier[0])**2 / (now[1]**2 + earlier[1]**2)
        assert distance_squared < 9, name
        results[name] = {
            'source_transcription_matches': True,
            'reproduced_number': number,
            'earlier_source': ('CaselleHasenbusch1997' if name in ('Qxi-minus', 'u-star') else 'Campostrini2002'),
            'quoted_intervals_disjoint': bool(disjoint(now, earlier)),
            'separation_squared_in_combined_error_units': str(distance_squared),
        }
    actual = {name for name, row in results.items() if row['quoted_intervals_disjoint']}
    assert actual == {'U2', 'Uxi', 'Q-plus', 'Q-minus', 'u-star', 'Qc'}
    return {'tid': 'T476', 'checked': len(results), 'all_match': True,
            'controls_passed': True, 'comparisons': results,
            'versions': {'sage': sage_version, 'numberdb': version('numberdb')}}


if __name__ == '__main__':
    key = sys.stdin.read().strip() if not sys.stdin.isatty() else ''
    if key:
        numberdb.configure(api_key=key)
    print(json.dumps(check(numberdb.table('T476')), indent=2))