back to table · edit · history · where entries came from · files · download
5438 bytes, as of the version from 2026-10-27 19:10 (current). Recorded here, not run.
"""Independent exact checks for numberdb.org/T557.
sage -python checks.py
sage -python checks.py --stored
For a private draft use NUMBERDB_API_KEY or NUMBERDB_KEY_FROM_STDIN=1.
NUMBERDB_CHECK_STORED=1 is the wrapper equivalent of --stored.
The independent polynomial construction uses the closed Hermite coefficient
sum and the differential recurrence in n; it imports no arithmetic helpers
from generate.py. The final driver imports the generator only to obtain the
values being tested and to compare their enumeration.
"""
import json
import os
import sys
import time
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
from sage.env import SAGE_VERSION
from check import exactness, agrees_with, measure, names_its_rings
S = PolynomialRing(QQ, 'x')
z = S.gen()
@lru_cache(None)
def independent(m,n):
"""Monic form of Buckingham (2020), equation (3), second recurrence."""
if n == 0 or m == 0:
return S.one()
if n == 1:
return sum((QQ((-1)**j*factorial(m))/QQ(4**j*factorial(j)*factorial(m-2*j)))*z**(m-2*j) for j in range(m//2+1))
p=independent(m,n-1)
numerator=p*p + (p.derivative()**2-p*p.derivative(2))*(QQ(1)/QQ(2*(n-1)))
q,r=numerator.quo_rem(independent(m,n-2))
assert r==0, ('independent recurrence division',m,n)
return q
def fourth_order_residual(p,m,n):
# Clarkson (2008), equation (5.9); invariant under constant normalization.
p1,p2,p3,p4=[p.derivative(j) for j in range(1,5)]
return p*p4-4*p1*p3+3*p2**2+4*z*p*p1-8*m*n*p*p-4*(z*z+2*n-2*m)*(p*p2-p1*p1)
def painleve_residual(p,q,m,n):
# w=(log(q/p))', alpha=2m+n+1, beta=-2*n^2.
# p=Hhat_{m,n}, q=Hhat_{m+1,n}.
a=q.derivative()*p-q*p.derivative()
b=p*q
c=a.derivative()*b-a*b.derivative()
d=c.derivative()*b-2*c*b.derivative()
alpha=2*m+n+1
beta=-2*n*n
return 2*a*d-c*c-3*a**4-8*z*a**3*b-4*(z*z-alpha)*a*a*b*b-2*beta*b**4
def controls():
assert independent(2,1)==z*z-QQ(1)/2
assert independent(1,2)==z*z+QQ(1)/2
assert independent(2,2)==z**4+QQ(3)/4
assert fourth_order_residual(z,1,1)==0
assert fourth_order_residual(z+1,1,1)!=0
assert painleve_residual(S.one(),z,0,1)==0 # w=1/x.
assert painleve_residual(S.one(),z+1,0,1)!=0
assert agrees_with({(2,2):z**4+QQ(3)/4},lambda key:independent(*key))==[]
assert agrees_with({(2,2):z**4+QQ(1)/4},lambda key:independent(*key))
def check_values(values):
controls()
assert not exactness(values)
assert not agrees_with(values,lambda key:independent(*key))
counts={k:0 for k in ['coefficient_comparisons','degree_monic_parity','transpose_symmetry','recurrence_m','recurrence_n','bilinear_ode','painleve_iv','hermite_specialization']}
for (m,n),p in values.items():
counts['coefficient_comparisons']+=1
assert p.degree()==m*n and p.leading_coefficient()==1
assert p(-z)==(-1)**(m*n)*p
counts['degree_monic_parity']+=1
transpose=values[(n,m)]
expected=S([coefficient*(-1)**((m*n-k)//2) if (m*n-k)%2==0 else 0 for k,coefficient in enumerate(p.list())])
assert transpose==expected
counts['transpose_symmetry']+=1
delta=p*p.derivative(2)-p.derivative()**2
assert independent(m+1,n)*independent(m-1,n)==p*p+delta*(QQ(1)/QQ(2*m))
counts['recurrence_m']+=1
assert independent(m,n+1)*independent(m,n-1)==p*p-delta*(QQ(1)/QQ(2*n))
counts['recurrence_n']+=1
assert fourth_order_residual(p,m,n)==0
counts['bilinear_ode']+=1
assert painleve_residual(p,independent(m+1,n),m,n)==0
counts['painleve_iv']+=1
if n==1:
assert p==independent(m,1)
counts['hermite_specialization']+=1
return counts
def stored_values():
document=numberdb.table('T557')
from numberdb._generate import _stored_entries
# The API may export flat, nested, or grouped records. Use the client parser.
return {tuple(int(v) for v in identity.split(',')): S(value)
for identity, value in _stored_entries(document).items()}
if __name__=='__main__':
start=time.monotonic()
from generate import GeneralizedHermite, authenticate
authenticate()
g=GeneralizedHermite()
params=list(g.enumerate())
expected_keys=[(p['m'],p['n']) for p in params]
# Independent complete set and independent ordering.
assert expected_keys==sorted([(m,n) for m in range(1,51) for n in range(1,51) if m*n<=50],key=lambda pair:(pair[0]*pair[1],*pair))
assert not names_its_rings(os.path.join(os.path.dirname(__file__),'generate.py'))
readback='--stored' in sys.argv or os.environ.get('NUMBERDB_CHECK_STORED')=='1'
values=stored_values() if readback else {(p['m'],p['n']):S(g.value(p,100)) for p in params}
assert list(values)==expected_keys
counts=check_values(values)
report={'table':'T557','mode':'stored' if readback else 'local','checks':counts,'controls':'known values and deliberately altered values passed','measurement':measure(values),'sage_version':SAGE_VERSION,'numberdb_version':numberdb.__version__,'elapsed_seconds':time.monotonic()-start}
print('CHECKS_JSON',json.dumps(report,default=str))
print('VALUES_JSON',json.dumps([{'params':{'m':m,'n':n},'number':str(p)} for (m,n),p in values.items()]))