back to table · edit · history · where entries came from · files · download
3174 bytes, as of the version from 2026-10-26 21:30 (current). Recorded here, not run.
"""Wright constants for connected graph enumeration -- numberdb.org/T528.
Run with SageMath (or compatible passagemath):
sage -pip install numberdb
sage -python generate.py
sage -python generate.py --fill # NUMBERDB_API_KEY must authorize this draft
The default command verifies all stored entries. --fill sends entries and
attachments to the existing table; it does not make a draft public or offer it.
Janson, Probability Surveys 4 (2007), equations (6), (7), (20) and (36).
Only graph excess k is free. The default selection is 0 <= k <= 11;
argument-selection.md explains the convention and editorial endpoint.
All K coefficients and integer/half-integer Gamma simplifications are exact
rationals. Odd k gives an exact rational. Even k gives a rational multiple
of sqrt(2*pi), enclosed by Arb at at least 512 bits. The attached checks
measure supported precision and containment in each written decimal interval.
"""
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.real_arb import RealBallField
MIN_WORKING_BITS = 512
WORKING_GUARD = 128
@lru_cache(None)
def k_coefficients(n):
values = [QQ(-1) / 2]
for j in range(1, n + 1):
values.append(QQ(3*j - 4) / 4 * values[j - 1]
+ sum((values[i] * values[j-i] for i in range(1, j)), QQ(0)))
return tuple(values)
def rational_factor(k):
"""Return q, with rho_k=q for odd k and q*sqrt(2*pi) for even k."""
if k < 0:
raise ValueError('Stored entries have nonnegative excess')
K = k_coefficients(k + 1)[k + 1]
m = k // 2
if k % 2 == 0:
return QQ(2)**(1-m) * K / QQ(factorial(3*m))
return (QQ(2)**(5*m+5) * K * QQ(factorial(3*m+2))
/ QQ(factorial(6*m+4)))
class WrightConstants(numberdb.Generator):
table = 'T528'
parameters = ('k',)
type = 'R'
digits = 100
rigour = 'proven'
files = ('generate.py', 'checks.py', 'check.py', 'argument-selection.md',
'numerical-evidence.md', 'skill-manifest.json')
def enumerate(self, max_excess=11):
for k in range(max_excess + 1):
yield {'k': str(k)}
def value(self, params, digits):
k = int(params['k'])
q = rational_factor(k)
if k % 2:
return q
R = RealBallField(max(MIN_WORKING_BITS,
numberdb.bits(digits, losing=WORKING_GUARD)))
return R(q) * (2 * R.pi()).sqrt()
if __name__ == '__main__':
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('\'"')
os.environ['NUMBERDB_API_KEY'] = key
generator = WrightConstants()
if '--fill' in sys.argv or os.environ.get('NUMBERDB_PUBLISH') == '1':
print(generator.publish(message='Fill excesses 0 through 11 with exact rationals and certified 100-digit enclosures'))
else:
report = generator.verify(sample=None)
print(report)
sys.exit(0 if report.ok else 1)