back to table · edit · history · where entries came from · files · download
4059 bytes, as of the version from 2026-10-29 03:59 (current). Recorded here, not run.
"""Ray–Singer torsion of lens spaces -- numberdb.org/T599.
Run with SageMath and the numberdb client installed:
sage -pip install numberdb
sage -python generate.py # verify every stored entry
sage -python generate.py --fill # write numbers to the existing draft
sage -python checks.py # independent local checks
Writing requires NUMBERDB_API_KEY, or NUMBERDB_KEY_FROM_STDIN=1 and a key
on stdin. --fill sends entries and attached sources; it does not publish or
ask for review. The default selection is documented in argument-selection.md.
Kitaoka, SIGMA 18 (2022), 091, Proposition 5.1: for the action (1,q)
and complex character u, use q^{-1} modulo p, without squaring or inverting T.
The calculation uses Arb sine balls at max(500, bits(digits)+160) bits.
Rational values are proved by reducing T^2 modulo the cyclotomic polynomial;
only when that remainder is a rational square is an exact rational returned.
No inference of exactness is made from approximate digits.
"""
import numberdb.sage as numberdb
from sage.rings.integer_ring import ZZ
from sage.rings.rational_field import QQ
from sage.rings.real_arb import RealBallField
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
from functools import lru_cache
from math import gcd
import os
import sys
WORKING_GUARD = 160
MINIMUM_BITS = 500
P_MAX = 20
POLYNOMIALS = PolynomialRing(QQ, 'x')
X = POLYNOMIALS.gen()
def check_domain(p, q, u):
if p < 2 or not (1 <= q < p and gcd(p, q) == 1 and 1 <= u < p):
raise ValueError('Require p >= 2, 1 <= q,u < p, and gcd(p,q)=1')
@lru_cache(None)
def cyclotomic(p):
return POLYNOMIALS.cyclotomic_polynomial(p)
def exact_rational(p, q, u):
"""All rational cases, decided by exact arithmetic, not recognition."""
r = pow(q, -1, p)
v = (u * r) % p
squared = ((2-X**u-X**(p-u)) * (2-X**v-X**(p-v))) % cyclotomic(p)
if squared.degree() == 0:
c = QQ(squared[0])
if c > 0 and c.is_square():
return c.sqrt()
return None
def torsion_ball(p, q, u, digits=100):
check_domain(p, q, u)
field = RealBallField(max(MINIMUM_BITS, numberdb.bits(digits, losing=WORKING_GUARD)))
v = (u * pow(q, -1, p)) % p
value = 4 * (field.pi() * field(QQ(u)/p)).sin() * (field.pi() * field(QQ(v)/p)).sin()
assert value.is_finite() and value > 0
assert abs(value) > field(value.rad()) * (ZZ(2)**numberdb.bits(digits, losing=32))
return value
class LensTorsion(numberdb.Generator):
table = 'T599'
parameters = ('p', 'q', 'u')
type = 'R'
digits = 100
rigour = 'proven'
files = ('generate.py', 'checks.py', 'argument-selection.md', 'numerical-evidence.json',
'skill-evidence.json', 'sources.md')
def enumerate(self, p_max=P_MAX):
for p in range(2, p_max + 1):
for q in range(1, p):
if gcd(p, q) != 1:
continue
r = pow(q, -1, p)
if q != min(q, p-q, r, p-r):
continue
for u in range(1, p//2 + 1):
yield {'p': p, 'q': q, 'u': u}
def value(self, params, digits):
p, q, u = (int(params[k]) for k in self.parameters)
check_domain(p, q, u)
exact = exact_rational(p, q, u)
return exact if exact is not None else torsion_ball(p, q, u, digits)
if __name__ == '__main__':
client = None
if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
key = sys.stdin.read().strip()
if '=' in key and key.split('=', 1)[0].isupper():
key = key.split('=', 1)[1].strip().strip('\"\'')
client = numberdb.Client(api_key=key)
generator = LensTorsion()
if '--fill' in sys.argv:
print(generator.publish(client=client, message='Compute complex-line lens-space torsion with certified balls and exact rational cases'))
else:
report = generator.verify(sample=None, client=client)
print(report)
sys.exit(0 if report.ok else 1)