back to table · edit · history · where entries came from · files · download
4266 bytes, as of the version from 2026-11-10 01:14 (current). Recorded here, not run.
"""Elliptic dilogarithm companion J at CM torsion points -- numberdb.org/T701.
Run with SageMath or passagemath:
sage -pip install numberdb
sage -python generate.py # verify every stored entry
sage -python generate.py --submit # write entries to the existing draft
Submission needs NUMBERDB_API_KEY. It does not offer or publish the draft.
Download checks.py and argument-selection.md for validation and selection.
Brunault (14) fixes J_q. With L=-log|q|, a=r/N, R=|q|, the omitted
one-sided sum starting at exponent t=M+a or M+1-a is bounded by
L R^t/(1-R^t) * (t/(1-R) + R/(1-R)^2).
Indeed |log|1-z|| <= |z|/(1-|z|) for |z|<1. This follows from the
absolutely convergent logarithm series, and summing (t+k) R^(t+k)
gives the displayed majorant. Both tails are added to the Arb ball.
All arithmetic, including arguments and the Bernoulli term, is enclosed.
The 128 extra working bits allow cancellation and rounding; checks.py
measures the minimum retained accuracy over the entire enumeration.
"""
import os
import sys
from math import gcd
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.real_arb import RealBallField
from sage.rings.complex_arb import ComplexBallField
DISCRIMINANTS = (-3, -4, -7, -8, -11, -12, -16, -19, -27, -28, -43, -67, -163)
WORKING_GUARD = 128
def parameters():
for delta in DISCRIMINANTS:
b = delta % 2
for order in range(3, 7):
for r in range(order):
for s in range(order):
if gcd(gcd(order, r), s) != 1:
continue
if (r, s) > ((-r) % order, (-s) % order):
continue
if (2*r) % order == 0 and (b*r) % order == 0:
continue
yield dict(Delta=delta, N=order, r=r, s=s)
def evaluate(delta, order, r, s, digits=100, metadata=False):
"""Evaluate reduced coordinates, including omitted zeros for checks."""
precision = numberdb.bits(digits, losing=WORKING_GUARD)
R = RealBallField(precision)
C = ComplexBallField(precision)
b = int(delta) % 2
a = QQ(int(r) % int(order)) / QQ(order)
s = int(s) % int(order)
L = R.pi() * R(-int(delta)).sqrt()
rho = (-L).exp()
q = (-1 if b else 1) * rho
phase = (C.gen(0)*R.pi()*QQ(2*s-b*(int(r) % int(order)))/QQ(order)).exp()
x = C((-L*a).exp()) * phase
inverse_term = C(q) / x
value = L**2 * R(a**3 - QQ(3)*a**2/2 + a/2) / 3
tolerance = R(2)**(-precision+28)
def bound(t):
rt = (-L*t).exp()
return L*rt/(1-rt) * (t/(1-rho)+rho/(1-rho)**2)
zp, zm = x, inverse_term
for n in range(1000):
# The unit-circle factor log|z| is exactly zero, even at z=1.
if n+a != 0:
value -= L*(n+a)*(1-zp).log().real()
value += L*(n+1-a)*(1-zm).log().real()
M = n+1
tail = bound(M+a) + bound(M+1-a)
if tail < tolerance:
value = value.add_error(tail)
assert value.is_finite()
return (value, M, tail) if metadata else value
zp *= q
zm *= q
raise ArithmeticError('Tail did not reach the certified tolerance')
class Table(numberdb.Generator):
table = 'T701'
parameters = ('Delta', 'N', 'r', 's')
type = 'R'
digits = 100
rigour = 'proven'
def enumerate(self):
yield from parameters()
def value(self, params, digits):
values = [int(params[k]) for k in self.parameters]
# tau^2+tau+1=0 and tau*u=u-1 at u=(tau+2)/3.
# Reindexing K under lambda -> tau*lambda multiplies K by 1/tau.
# Periodicity therefore forces K=D=J=0 at this fixed point.
if values == [-3, 3, 1, 2]:
return 0
return evaluate(*values, digits=digits)
if __name__ == '__main__':
if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
numberdb.configure(api_key=sys.stdin.read().strip())
g = Table()
if '--submit' in sys.argv or os.environ.get('NUMBERDB_PUBLISH') == '1':
print(g.publish(message='Compute J in ball arithmetic with explicit tails'))
else:
report = g.verify(sample=None)
print(report)
sys.exit(0 if report.ok else 1)