back to table · edit · history · where entries came from · files · download
3087 bytes, as of the version from 2026-10-26 20:13 (current). Recorded here, not run.
"""Moments of the Brownian meander area -- numberdb.org/T526.
Run with SageMath (or a suitable passagemath installation):
sage -pip install numberdb
sage -python generate.py # verify the stored draft
sage -python generate.py --fill # fill with NUMBERDB_API_KEY set
The --fill operation writes entries to the existing draft. It does not offer,
review, or make the table public. Private reads also need an authorized key.
Janson (2007), equations (7), (194), (199), fixes the variance-t, unit-duration
normalization. All coefficients are exact rationals. Even moments are exact;
odd moments multiply a rational by an Arb enclosure of sqrt(pi/2).
The default selection is the first twelve positive moment orders; see
argument-selection.md. Working precision uses 180 guard bits; checks.py
measures the available precision and independently checks every stored value.
"""
import os
import sys
from math import factorial
from functools import lru_cache
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.real_arb import RealBallField
WORKING_GUARD = 180
MAX_ORDER = 12
@lru_cache(maxsize=None)
def auxiliary(n):
k, q = [QQ(-1)/QQ(2)], [QQ(1)]
for j in range(1, n+1):
k.append(QQ(3*j-4)/QQ(4)*k[j-1]
+ sum((k[i]*k[j-i] for i in range(1,j)), QQ(0)))
q.append(QQ(3*j-2)/QQ(2)*q[j-1]
+ 2*sum((k[i]*q[j-i] for i in range(1,j+1)), QQ(0)))
return tuple(k), tuple(q)
def rational_factor(n):
"""Return M_n, or M_n/sqrt(pi/2) for odd n, exactly."""
if n < 0:
raise ValueError('moment order must be nonnegative')
q = auxiliary(n)[1][n]
m = n//2
if n%2:
return QQ(factorial(n))*q/QQ(2**m*factorial(3*m+1))
return QQ(factorial(n)*4**(3*m)*factorial(3*m))*q/QQ(2**m*factorial(6*m))
class MeanderMoments(numberdb.Generator):
table = 'T526'
parameters = ('n',)
type = 'R'
digits = 100
rigour = 'proven'
files = ('generate.py', 'checks.py', 'check.py', 'argument-selection.md',
'derivation.md', 'skill-manifest.json')
def enumerate(self, max_order=MAX_ORDER):
for n in range(1, max_order+1):
yield {'n': str(n)}
def value(self, params, digits):
n = int(params['n'])
if n < 1:
raise ValueError('stored moment orders must be positive')
factor = rational_factor(n)
if n%2 == 0:
return factor
field = RealBallField(numberdb.bits(digits, losing=WORKING_GUARD))
return field(factor)*(field.pi()/field(2)).sqrt()
if __name__ == '__main__':
if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
os.environ['NUMBERDB_API_KEY'] = sys.stdin.read().strip()
generator = MeanderMoments()
if '--fill' in sys.argv or os.environ.get('NUMBERDB_PUBLISH') == '1':
print(generator.publish(message='Fill twelve independently checked Brownian meander area moments'))
else:
report = generator.verify(sample=None)
print(report)
sys.exit(0 if report.ok else 1)