repair-hensel-check.py

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

4650 bytes, as of the version from 2026-11-02 11:21 (current). Recorded here, not run.

"""Check the Hensel certificate displayed by numberdb.org/T675.

Run: sage -python repair-hensel-check.py
Keep the unchanged attached frobenius-input.json beside this file. The checker
reads document-before.json beside it when present; otherwise it reads T675
using numberdb's configured API key. It writes no values and imports no
root-lifting code. Its JSON output records exact residue/derivative checks.
"""
import hashlib
import importlib.metadata
import json
import platform
import re
from pathlib import Path
import numberdb.sage as numberdb
from sage.rings.integer_ring import ZZ
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
from sage.version import version as sage_version

WORK = Path(__file__).resolve().parent
POLICY = {
    'manifest': 'agents/runs/20261102T111650Z-repair-skills/manifest.json',
    'local_sha256': 'a2b28d9953264d7b0ca62663785c2952190c5be6d6d3597fd695d9a54d606278',
    'live_sha256': 'a2b28d9953264d7b0ca62663785c2952190c5be6d6d3597fd695d9a54d606278',
}
R = PolynomialRing(ZZ, 'T')
x = R.gen()


def certificate(q, r, p, n):
    modulus = p**n
    residual = q(r) % modulus
    derivative = q.derivative()(r) % p
    assert residual == 0
    assert derivative != 0
    assert r % p != 0
    return int(residual), int(derivative)


def main():
    # Exact-root positive control, plus singular-root and false-root controls.
    q = (x-2)*(x-5)*(x-25)*(x-125)
    assert certificate(q, ZZ(2), ZZ(5), 35) == (0, 3)
    negative_controls = 0
    for polynomial, r in (((x-2)**2, ZZ(2)), (q, ZZ(3))):
        try:
            certificate(polynomial, r, ZZ(5), 35)
        except AssertionError:
            negative_controls += 1
    assert negative_controls == 2
    document_path = WORK / 'document-before.json'
    if document_path.exists():
        raw = document_path.read_bytes()
        document = json.loads(raw)
    else:
        document = numberdb.table('T675')
        raw = json.dumps(document, ensure_ascii=False).encode()
    factor_raw = (WORK / 'frobenius-input.json').read_bytes()
    data = json.loads(factor_raw)
    assert data['source_table'] == 'T674'
    results = []
    for template, fibres in document['Numbers'].items():
        for z, primes in fibres.items():
            for p_text, entry in primes.items():
                p = ZZ(p_text)
                assert p.is_prime(proof=True)
                match = re.fullmatch(r'(\d+) \+ O\((\d+)\^(\d+)\)', entry['number'])
                assert match, entry['number']
                r, recorded_p, n = map(ZZ, match.groups())
                assert p == recorded_p
                assert p**(n-1) < ZZ(10)**100 <= p**n
                factor = data['Numbers'][template][z][p_text]
                if isinstance(factor, dict):
                    factor = factor['number']
                P = R(factor)
                assert P.degree() == 4 and P[0] == 1
                a = -P[1]
                assert P[2] % p == 0 and P[3] == -p**3*a and P[4] == p**6
                Q = R(list(reversed(P.list())))
                residual, derivative = certificate(Q, r, p, n)
                assert (r-a) % p == 0
                assert derivative == a**3 % p
                inverse = r.inverse_mod(p**n)
                assert P(inverse) % p**n == 0
                results.append({'template': template, 'z': z, 'p': int(p),
                                'N': int(n), 'Q_mod_pN': residual,
                                'derivative_mod_p': derivative})
    assert len(results) == 358
    report = {
        'table': 'T675', 'purpose': 'Verify the corrected displayed Hensel condition',
        'policy': POLICY,
        'versions': {'sage': sage_version, 'python': platform.python_version(),
                     'numberdb': importlib.metadata.version('numberdb')},
        'document_sha256': hashlib.sha256(raw).hexdigest(),
        'frobenius_input_sha256': hashlib.sha256(factor_raw).hexdigest(),
        'controls': {'known_root_2': True, 'singular_root_rejected': True,
                     'nonroot_rejected': True},
        'checked_entries': len(results),
        'all_root_residuals_zero': True, 'all_derivatives_nonzero_mod_p': True,
        'all_inverse_residues_annihilate_P': True,
        'all_moduli_minimal_for_100_decimal_digits': True,
        'exponent_min': min(v['N'] for v in results),
        'exponent_max': max(v['N'] for v in results),
        'limitation': 'Factors are the unchanged reviewed input; this repair does not recompute Frobenius factors or alter stored values.',
        'results': results,
    }
    print(json.dumps(report, indent=2))


if __name__ == '__main__':
    main()