"""Check the precision correction for numberdb.org/T477.

Run with SageMath (numberdb installed):
  sage -python repair-checks.py T477-live-before.json
Or pipe an API key on stdin to check the current private draft:
  cat "$NUMBERDB_KEY_FILE" | sage -python repair-checks.py

This script writes nothing to NumberDB. Source bounds are from Markot (2021),
Section 7.5, DOI 10.1007/s10898-021-01086-z, fetched 2026-10-25 at
https://pmc.ncbi.nlm.nih.gov/articles/PMC8550790/?pdf=1 .
The decimal intervals are interpreted with NumberDB's one-last-place radius.
"""
import json
import sys
from decimal import Decimal
from pathlib import Path
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.real_mpfr import RealField  # initializes QQ string coercion
from sage.version import version as sage_version


def rational(text):
    if '/' in text:
        return QQ(text)
    value = Decimal(text)
    sign, digits, exponent = value.as_tuple()
    mantissa = int(''.join(map(str, digits))) * (-1 if sign else 1)
    return QQ(mantissa) * QQ(10) ** int(exponent)


def interval(text):
    center = rational(text)
    if '.' not in text and 'e' not in text.lower():
        return center, center
    radius = QQ(10) ** int(Decimal(text).as_tuple().exponent)
    return center - radius, center + radius


def significant_digits(text):
    return len(Decimal(text).as_tuple().digits)


assert significant_digits('0.0012300') == 5
assert significant_digits('11.463944032450') == 14
assert interval('3.14') == (QQ(313)/QQ(100), QQ(315)/QQ(100))
assert interval('1/2') == (QQ(1)/QQ(2), QQ(1)/QQ(2))
assert interval('4') == (QQ(4), QQ(4))
if len(sys.argv) > 1:
    document = json.loads(Path(sys.argv[1]).read_text())
else:
    client = numberdb.Client(api_key=sys.stdin.read().strip())
    document = numberdb.table('T477', client=client)
bounds = {
    '31': ('0.2175472916191243', '0.2175472916191280'),
    '32': ('0.2131745625898764', '0.2131745625898779'),
    '33': ('0.2113283841432631', '0.2113283841432645'),
}
results = []
for n, (low, high) in bounds.items():
    lo, hi = rational(low), rational(high)
    assert QQ(0) < lo < hi
    certified = {'separation': (lo, hi),
                 'container': (QQ(2)+QQ(2)/hi, QQ(2)+QQ(2)/lo)}
    for form, (a, b) in certified.items():
        text = document['Numbers'][n][form]['number']
        lower, upper = interval(text)
        assert lower <= a <= b <= upper, (n, form)
        digits = significant_digits(text)
        assert digits == (13 if (n, form) == ('31', 'separation') else 14)
        results.append({'n': n, 'normalisation': form, 'number': text,
                        'significant_digits': digits,
                        'contains_certified_interval': True,
                        'certified_lower': str(a), 'certified_upper': str(b)})
for n, pair in document['Numbers'].items():
    drow, srow = pair['separation'], pair['container']
    dlo, dhi = interval(drow['number'] if isinstance(drow, dict) else drow)
    slo, shi = interval(srow['number'] if isinstance(srow, dict) else srow)
    assert dlo > QQ(0) and slo > QQ(2)
    transformed = (QQ(2)+QQ(2)/dhi, QQ(2)+QQ(2)/dlo)
    assert max(slo, transformed[0]) <= min(shi, transformed[1]), n
assert len(document['Numbers']) == 99
print(json.dumps({'table': 'T477', 'sage_version': sage_version,
                  'controls_passed': True, 'certified_rows': results,
                  'conversion_interval_checks_passed': 99,
                  'scope': 'Precision counts and source-bound containment, not a new optimality proof.'}, indent=2))
