back to table · edit · history · where entries came from · files · download
4271 bytes, as of the version from 2026-10-27 19:10 (current). Recorded here, not run.
"""Generalized Hermite polynomials for Painlevé IV -- numberdb.org/T557.
Run with SageMath (or a suitable passagemath installation):
sage -pip install numberdb
sage -python generate.py # verify every stored entry
sage -python generate.py --fill # write entries to this draft
sage -python checks.py # independent exact checks
Set NUMBERDB_API_KEY for authenticated reads and writes of the private draft.
For the campaign wrapper, NUMBERDB_KEY_FROM_STDIN=1 reads the key from stdin;
NUMBERDB_PUBLISH=1 writes entries, but never publishes or offers the table.
Every value is a monic polynomial over QQ in the unchanged variable x.
Compute physicists' Hermite polynomials by their three-term recurrence, then
compute the Wronskian by fraction-free elimination with exact remainder tests.
No floating-point computation, numerical differentiation, symmetry reduction,
or Painlevé differential recurrence is used in this generator.
See argument-selection.md for the two discrete indices and finite degree bound.
"""
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.polynomial.polynomial_ring_constructor import PolynomialRing
R = PolynomialRing(QQ, 'x')
x = R.gen()
MAX_DEGREE = 50
@lru_cache(None)
def hermite(k):
if k == 0:
return R.one()
if k == 1:
return 2*x
return 2*x*hermite(k-1) - 2*(k-1)*hermite(k-2)
def determinant(rows):
"""Bareiss determinant in QQ[x], checking every exact division."""
a = [list(row) for row in rows]
size = len(a)
if size == 0:
return R.one()
previous = R.one()
sign = 1
for k in range(size-1):
if a[k][k] == 0:
pivot_row = next((i for i in range(k+1,size) if a[i][k]), None)
if pivot_row is None:
return R.zero()
a[k],a[pivot_row] = a[pivot_row],a[k]
sign = -sign
pivot = a[k][k]
for i in range(k+1,size):
for j in range(k+1,size):
numerator = pivot*a[i][j] - a[i][k]*a[k][j]
a[i][j], remainder = numerator.quo_rem(previous)
assert remainder == 0, ('inexact Bareiss division',k,i,j)
a[i][k] = R.zero()
previous = pivot
return sign*a[-1][-1]
@lru_cache(None)
def generalized_hermite(m,n):
if m < 0 or n < 0:
raise ValueError('Indices must be nonnegative')
rows = [[hermite(m+j).derivative(i) for j in range(n)] for i in range(n)]
polynomial = determinant(rows)
leading = QQ(2)**(m*n+n*(n-1)//2)
for j in range(1,n):
leading *= factorial(j)
assert polynomial.degree() == m*n
assert polynomial.leading_coefficient() == leading
return polynomial * (QQ(1)/leading)
class GeneralizedHermite(numberdb.Generator):
table = 'T557'
parameters = ('m','n')
type = 'Q[]'
rigour = 'exact'
digits = 100 # Exact polynomial serialization does not round coefficients.
files = ('generate.py','checks.py','check.py','argument-selection.md',
'source-notes.md','skill-evidence.json','numerical-evidence.json')
def enumerate(self, max_degree=MAX_DEGREE):
for degree in range(1,max_degree+1):
for m in range(1,degree+1):
if degree % m == 0:
yield {'m':m,'n':degree//m}
def value(self, params, digits):
return generalized_hermite(int(params['m']),int(params['n']))
def authenticate():
if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
key = sys.stdin.read().strip()
if '=' in key and key.split('=',1)[0].replace('_','').isalnum():
key = key.split('=',1)[1].strip().strip('\"\'')
numberdb.configure(api_key=key)
if __name__ == '__main__':
authenticate()
generator = GeneralizedHermite()
if '--fill' in sys.argv or os.environ.get('NUMBERDB_PUBLISH') == '1':
print(generator.publish(message='Fill monic generalized Hermite polynomials through degree 50, with exact independent checks.'))
else:
report = generator.verify(sample=None)
print(report)
sys.exit(0 if report.ok else 1)