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))