back to table · edit · history · where entries came from · files · download
5292 bytes, as of the version from 2026-10-30 08:21 (current). Recorded here, not run.
"""Neumann spectral determinants of regular polygons -- numberdb.org/T621.
Run with SageMath or passagemath and numberdb installed:
sage -pip install numberdb # once
sage -python generate.py # verify every stored entry
sage -python generate.py --fill # fill the existing draft, API key required
The operator is -d_x^2-d_y^2 with homogeneous Neumann boundary conditions on the
regular n-gon of circumradius one, omitting its constant zero mode. Entries are det and its natural log,
in that order for n=3,...,30. See argument-selection.md for the selection.
Aurell--Salomonson (hep-th/9304031), (23)--(24), gives the polygon formula.
Kalvin (1910.00104v2), (3.15) and Lemma A.1, gives a finite corner formula.
All divisions of exact coefficients use QQ. Arb encloses the exact rational
arguments and carries errors through log-Gamma, zeta derivative, and exp.
The 180 guard bits are checked by checks.py, including the decimal intervals.
The finite Dirichlet corner computation is adapted from the attached
generator of numberdb.org/T620, fetched 2026-10-30. Kalvin (2610.35383v1),
Theorem 1.1, gives det_N/det_D = area * (1-2/n)^(-n/2).
The independent integral and separated-spectrum controls are in checks.py.
This script writes entries only when --fill is explicit. It cannot offer,
review, or make a table public. Authentication may be piped on stdin with
NUMBERDB_KEY_FROM_STDIN=1; otherwise use NUMBERDB_API_KEY.
"""
import os
import sys
from functools import lru_cache
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
WORKING_GUARD = 180
@lru_cache(maxsize=None)
def ingredients(prec):
field = RealBallField(prec)
z = ComplexBallField(prec)(-1).zetaderiv(1)
assert z.real().is_finite() and z.imag().is_finite() and z.imag().contains_zero()
return field, z.real()
def corner(a, prec):
"""F(a), with a positive exact rational; no floating-point coefficients."""
a = QQ(a)
p, q = a.numerator(), a.denominator()
field, zp = ingredients(prec)
half = QQ(1) / 2
dedekind = sum(((QQ(j) / p - half) * (QQ((j*q) % p) / p - half)
for j in range(1, p)), QQ(0))
b = zp / (p*q) - field(q).log() / (12*p*q)
b += (QQ(1)/4 + dedekind) * field(QQ(q)/p).log()
for k in range(1, p):
b += (half - QQ(k)/p) * field(QQ((k*q) % p)/p).log_gamma()
for j in range(1, q):
b += (half - QQ(j)/q) * field(QQ((j*p) % q)/q).log_gamma()
f = b - a*zp + (a-1/a)/12 * field(2).log()
f -= (a-1)/4 * (2*field.pi()).log()
assert f.is_finite()
return f
@lru_cache(maxsize=None)
def dirichlet_logdet(n, prec):
n = int(n)
if n < 3:
raise ValueError('The number of sides must be at least three')
field, _ = ingredients(prec)
h = QQ(1)/n
a = 1-2*h
c = QQ(n-1)/(6*(n-2))
log_scale = (field(1+h).log_gamma() + field(a).log_gamma()
- field(1-h).log_gamma())
result = 2*c*log_scale + field(n).log()/(3*(n-2)) - n*corner(a, prec)
assert result.is_finite()
return result
@lru_cache(maxsize=None)
def polygon_logdet(n, prec):
"""Log determinant of the positive Neumann spectrum, circumradius one."""
n = int(n)
if n < 3:
raise ValueError('The number of sides must be at least three')
field, _ = ingredients(prec)
alpha = QQ(n-2)/n
area = QQ(n)/2 * (2*field.pi()/n).sin()
result = dirichlet_logdet(n, prec) + area.log() - QQ(n)/2*field(alpha).log()
assert result.is_finite()
return result
class PolygonNeumannDeterminants(numberdb.Generator):
table = 'T621'
parameters = ('n', 'convention')
type = 'R'
digits = 100
rigour = 'proven'
files = ('generate.py', 'checks.py', 'family_checks.py',
'argument-selection.md', 'derivation.md', 'skill-evidence.json',
'sources.json', 'checks-prefill-evidence.json', 'dependency-versions.json')
def enumerate(self, maximum=30):
for n in range(3, maximum+1):
for convention in ('det', 'logdet'):
yield {'n': str(n), 'convention': convention}
def value(self, params, digits):
value = polygon_logdet(int(params['n']), numberdb.bits(digits, losing=WORKING_GUARD))
if params['convention'] == 'det':
return value.exp()
if params['convention'] == 'logdet':
return value
raise ValueError('Unknown convention')
def authenticated_client():
if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
key = sys.stdin.read().strip()
if '=' in key and key.split('=', 1)[0].replace('_', '').isupper():
key = key.split('=', 1)[1].strip().strip('\"\'')
return numberdb.Client(api_key=key)
return numberdb.Client()
if __name__ == '__main__':
gen = PolygonNeumannDeterminants()
client = authenticated_client()
if '--fill' in sys.argv or os.environ.get('NUMBERDB_PUBLISH') == '1':
print(gen.publish(client=client, message='Fill 56 certified Neumann polygon determinants and logarithms'))
else:
report = gen.verify(sample=None, client=client)
print(report)
sys.exit(0 if report.ok else 1)