back to table · edit · history · where entries came from · files · download
3580 bytes, as of the version from 2026-11-09 16:19 (current). Recorded here, not run.
"""Asymptotic coefficients of the Bettin–Conrey reciprocity function -- numberdb.org/T693.
Run with SageMath or passagemath and the numberdb package:
sage -pip install numberdb # install the client once
sage -python generate.py # verify every stored entry
sage -python generate.py --fill # fill this draft with an API key
This implements Akatsuka–Murakami (2402.14216v1), equation (5.2).
Exact polynomials in x=pi^2 are constructed before evaluation in Arb balls.
The correction index is ell=0,...,60; see argument-selection.md. The generator
can compute a further coefficient by coefficient_polynomials(ell)[ell].
The 192-bit working margin is measured in checks.py; see numerical-evidence.md.
No source values, numerical inputs or other generator modules are needed.
"""
import os
import sys
from functools import lru_cache
from math import factorial
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.integer_ring import ZZ
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
from sage.rings.real_arb import RealBallField
from sage.arith.misc import bernoulli
MAX_ORDER = 60
WORKING_GUARD = 192
R = PolynomialRing(QQ, 'x')
x = R.gen()
@lru_cache(maxsize=None)
def coefficient_polynomials(limit=MAX_ORDER):
"""Q_k=z^k P_k(z), evaluated formally at z^2=-4x; then equation (5.2)."""
q = [R.one()]
for k in range(1, limit + 1):
# Differentiate exp(-z lambda(u)) coefficient by coefficient.
value = R.zero()
for r in range(1, k + 1, 2):
value -= QQ(r) * bernoulli(r + 1) / QQ(factorial(r + 1)) * (-4*x)**((r+1)//2) * q[k-r]
q.append(value / QQ(k))
coefficients = []
for ell in range(limit + 1):
value = R.zero()
for k in range(ell + 1):
# H(k+1,j)/4^j, with j=ell-k, computed by its product.
h = QQ.one()
for j in range(1, ell-k+1):
h *= QQ(4*(k+1)**2-(2*j-1)**2) / QQ(16*j)
value += h*q[k]
coefficients.append(value)
return tuple(coefficients)
def evaluate(poly, digits=100, extra=WORKING_GUARD):
if poly.degree() <= 0:
return QQ(poly[0])
field = RealBallField(numberdb.bits(digits, losing=extra))
value = poly(field.pi()**2)
assert value.is_finite() and value.accuracy() >= numberdb.bits(digits)
return value
class BettinConreyAsymptotic(numberdb.Generator):
table = 'T693'
parameters = ('ell',)
type = 'R'
digits = 100
rigour = 'proven'
files = ('generate.py', 'checks.py', 'check.py', 'argument-selection.md',
'derivation.md', 'numerical-evidence.md', 'skill-evidence.json',
'checks-output.json', 'dry-run.log', 'coefficient-polynomials.json')
def enumerate(self):
for ell in range(MAX_ORDER + 1):
yield {'ell': ell}
def value(self, params, digits):
ell = int(params['ell'])
assert ell >= 0
return evaluate(coefficient_polynomials(max(MAX_ORDER, ell))[ell], digits)
if __name__ == '__main__':
if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
numberdb.configure(api_key=sys.stdin.read().strip())
generator = BettinConreyAsymptotic()
if '--fill' in sys.argv or os.environ.get('NUMBERDB_PUBLISH') == '1':
print(generator.publish(message='Fill all 61 signed asymptotic coefficients with certified 100-digit values'))
else:
report = generator.verify(sample=None)
print(report)
sys.exit(0 if report.ok else 1)