back to table · edit · history · where entries came from · files · download
4207 bytes, as of the version from 2026-10-29 07:39 (current). Recorded here, not run.
"""Dirichlet spectral determinants of Laplacians on hemispheres -- numberdb.org/T603.
Run with SageMath (install numberdb once with sage -pip install numberdb):
sage -python generate.py # verify the stored draft/table
sage -python generate.py --fill # write entries, NUMBERDB_API_KEY required
The unit-radius, unshifted scalar Dirichlet spectrum is k(k+d-1), with
multiplicity binomial(d+k-2,d-1), k>=1. Theorem 3.2 of Cunha and Freitas,
arXiv:2404.12114v1, is evaluated using exact signed Stirling and central
factorial coefficients and Arb enclosures. d=1 is handled as zeta(2s).
All dimensions 1..20 are included, determinant first and log determinant
second. See argument-selection.md for the finite-prefix rationale.
WORKING_DIGITS=150 is measured against 200-digit recomputations in checks.py.
The independent spectral continuation in independent.py supplies a second
method, not the justification for the proven Arb enclosures.
"""
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.complex_arb import ComplexBallField
from sage.rings.real_arb import RealBallField
WORKING_DIGITS = 150
MAX_DIMENSION = 20
def harmonic(n):
return sum((QQ(1)/QQ(k) for k in range(1,n+1)),QQ(0))
@lru_cache(None)
def stirling(n,k):
if n == 0:
return int(k == 0)
if k < 1 or k > n:
return 0
return stirling(n-1,k-1)-(n-1)*stirling(n-1,k)
def roots_polynomial(roots):
"""Exact coefficient list of product (X-r); no symbolic ring needed."""
c=[1]
for r in roots:
out=[0]*(len(c)+1)
for k,v in enumerate(c):
out[k]-=r*v
out[k+1]+=v
c=out
return c
@lru_cache(None)
def logdet(d, working=WORKING_DIGITS):
if not isinstance(d,int) or d<1:
raise ValueError('dimension must be a positive integer')
C=ComplexBallField(numberdb.bits(working))
R=RealBallField(numberdb.bits(working))
if d == 1:
return (2*R.pi()).log()
# The signed Stirling combination is valid for either parity.
zp=sum((QQ(stirling(d,k+1)+(-1)**(d-1+k)*stirling(d-1,k))
/QQ(factorial(d-1))*C(-k).zetaderiv(1)
for k in range(d)), C(0))
if d%2:
n=(d+1)//2
u=roots_polynomial([j*j for j in range(n-1)])
correction=-sum((QQ(2*u[i])/QQ(factorial(2*n-2))
*QQ((n-1)**(2*i+1))/QQ(2*i)
*(harmonic(i-1)/2-harmonic(2*i-1))
for i in range(1,n)),QQ(0))
else:
n=d//2
v=roots_polynomial([0]+[(2*j-1)**2 for j in range(1,n)])
correction=sum((QQ(v[i])/QQ(4**(n-1)*factorial(2*n-1))
*QQ((2*n-1)**(2*i))/QQ(4*i)
*(harmonic(i-1)/2-harmonic(2*i-1))
for i in range(1,n+1)),QQ(0))
result=-(zp+correction)
assert result.real().is_finite() and result.imag().is_finite()
assert result.real().accuracy() > 400 and result.imag().contains_zero()
return result.real()
class HemisphereDirichlet(numberdb.Generator):
table='T603'
parameters=('d','convention')
type='R'
digits=100
rigour='proven'
def enumerate(self, max_dimension=MAX_DIMENSION):
for d in range(1,max_dimension+1):
for convention in ('det','logdet'):
yield {'d':str(d),'convention':convention}
def value(self,params,digits):
L=logdet(int(params['d']),max(WORKING_DIGITS,digits+50))
if params['convention']=='det':
return L.exp()
if params['convention']=='logdet':
return L
raise ValueError('unknown convention')
if __name__=='__main__':
if os.environ.get('NUMBERDB_KEY_FROM_STDIN')=='1':
os.environ['NUMBERDB_API_KEY']=sys.stdin.read().strip()
g=HemisphereDirichlet()
if '--fill' in sys.argv or os.environ.get('NUMBERDB_PUBLISH')=='1':
print(g.publish(message='computed all 40 entries with exact coefficients and Arb enclosures'))
else:
result=g.verify(sample=None)
print(result)
sys.exit(0 if result.ok else 1)