back to table · edit · history · where entries came from · files · download
3372 bytes, as of the version from 2026-10-28 00:06 (current). Recorded here, not run.
"""Morris integrals for circular ensembles with a coalescing charge -- numberdb.org/T565.
Run with SageMath and the numberdb package:
sage -pip install numberdb
sage -python generate.py # verify stored entries
sage -python checks.py # independent integral checks
To fill the existing draft, set NUMBERDB_API_KEY and NUMBERDB_FILL_DRAFT=1.
Filling entries does not publish or offer the draft for review.
The default selection is beta=1,2,4; n=1,...,10; k=0,...,4.
Every Gamma argument is integral or half-integral. Exact rational reduction
produces q*pi**p. Values with p=0 are returned exactly; other values use
100-digit real balls with 96 guard bits. See argument-selection.md and
numerical-evidence.json for the selection and measured precision.
"""
import os
import sys
from math import factorial
from pathlib import Path
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.real_arb import RealBallField
WORKING_GUARD = 96
def gamma_half_integer(twice_argument):
"""Return q,e with Gamma(twice_argument/2) = q*sqrt(pi)**e."""
a = int(twice_argument)
assert a >= 2
if a % 2 == 0:
return QQ(factorial(a // 2 - 1)), 0
m = (a - 1) // 2
return QQ(factorial(2 * m)) / QQ(4**m * factorial(m)), 1
def exact_form(beta, n, k):
"""Morris's product in exact Q times an integral power of pi."""
beta, n, k = int(beta), int(n), int(k)
assert beta in (1, 2, 4) and n >= 1 and k >= 0
q, sqrt_power = QQ(1), 0
for j in range(n):
for a, sign in ((2 + 2*k*beta + j*beta, 1),
(2 + (j+1)*beta, 1),
(2 + k*beta + j*beta, -2),
(2 + beta, -1)):
coefficient, exponent = gamma_half_integer(a)
q *= coefficient**sign
sqrt_power += sign*exponent
assert sqrt_power % 2 == 0
return q, sqrt_power // 2
class MorrisIntegrals(numberdb.Generator):
table = 'T565'
parameters = ('beta', 'n', 'k')
type = 'R'
digits = 100
rigour = 'proven'
files = ('generate.py', 'checks.py', 'independent-checks.md',
'argument-selection.md', 'numerical-evidence.json',
'skill-manifest.json')
def enumerate(self):
for beta in (1, 2, 4):
for n in range(1, 11):
for k in range(5):
yield {'beta': str(beta), 'n': str(n), 'k': str(k)}
def value(self, params, digits):
q, p = exact_form(*(params[name] for name in self.parameters))
if p == 0:
return q
field = RealBallField(numberdb.bits(digits, losing=WORKING_GUARD))
return field(q) * field.pi()**p
if __name__ == '__main__':
if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
key = sys.stdin.read().strip()
if '=' in key:
key = key.split('=', 1)[1].strip().strip('\"\'')
os.environ['NUMBERDB_API_KEY'] = key
generator = MorrisIntegrals()
if os.environ.get('NUMBERDB_FILL_DRAFT') == '1' or os.environ.get('NUMBERDB_PUBLISH') == '1':
result = generator.publish(message='Fill 150 Morris integrals checked by independent angular moment matrices')
print(result)
else:
result = generator.verify(sample=None)
print(result)
sys.exit(0 if result.ok else 1)