back to table · edit · history · where entries came from · files · download
5459 bytes, as of the version from 2026-10-28 07:03 (current). Recorded here, not run.
"""Independent exact checks of Trace moments -- numberdb.org/T574.
sage -python checks.py # compare generated entries
sage -python checks.py --stored # independently check the live draft
A private draft requires NUMBERDB_API_KEY (or NUMBERDB_KEY_FROM_STDIN=1).
This file has no dependency on a NumberDB website checkout.
"""
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from collections import Counter
from functools import lru_cache
from itertools import permutations
from math import factorial, prod
import json
import os
import sys
from generate import InducedTraceMoments, moment
def cycles(perm):
seen = set()
count = 0
for start in range(len(perm)):
if start in seen:
continue
count += 1
i = start
while i not in seen:
seen.add(i)
i = perm[i]
return count
@lru_cache(maxsize=None)
def wick_counts(q):
counts = Counter()
for sigma in permutations(range(q)):
gamma_sigma = tuple((sigma[i]+1) % q for i in range(q))
counts[(cycles(gamma_sigma), cycles(sigma))] += 1
assert sum(counts.values()) == factorial(q)
return counts
def wick(N, K, q):
if q == 0:
return QQ(N)
numerator = sum(count*N**i*K**j for (i,j), count in wick_counts(q).items())
return QQ(numerator)/QQ(prod(N*K+r for r in range(q)))
def beta_integer(a, b):
return QQ(factorial(a-1)*factorial(b-1))/QQ(factorial(a+b-1))
def qubit_integral(K, q):
# Integrate x^q against x^(K-2)(1-x)^(K-2)(2x-1)^2 on [0,1].
def raw(order):
return (4*beta_integer(K+order+1,K-1)
-4*beta_integer(K+order,K-1)
+beta_integer(K+order-1,K-1))
return 2*raw(q)/raw(0)
def qubit_hs(q):
return 6*(QQ(4)/QQ(q+3)-QQ(4)/QQ(q+2)+QQ(1)/QQ(q+1))
def run_checks(values):
# Nonzero known controls precede all data comparisons.
assert cycles((0,1,2)) == 3 and cycles((1,2,0)) == 1
assert wick_counts(2) == Counter({(1,2):1,(2,1):1})
assert beta_integer(1,1) == 1
assert qubit_integral(2,0) == 2 and qubit_integral(2,1) == 1
for q, expected in [(2,QQ(4)/QQ(5)),(3,QQ(7)/QQ(10)),(4,QQ(22)/QQ(35))]:
assert wick(2,2,q) == qubit_integral(2,q) == qubit_hs(q) == expected
expected_keys={(N,K,q) for N in range(2,9) for K in range(N,65)
if N*K <= 64 for q in range(2,9)}
assert set(values) == expected_keys and len(values) == 560
counts=Counter()
for (N,K,q), actual in values.items():
assert actual == wick(N,K,q), ('Wick',N,K,q,actual,wick(N,K,q))
counts['wick'] += 1
assert actual == wick(K,N,q)
counts['dimension_swap'] += 1
assert QQ(1)/QQ(N**(q-1)) < actual < 1
counts['density_bounds'] += 1
mprev=values[(N,K,q-1)] if q > 2 else QQ(1)
mprevprev=values[(N,K,q-2)] if q > 3 else (QQ(1) if q==3 else QQ(N))
assert actual < mprev
counts['order_monotonicity'] += 1
left=actual*(N*K+q-1)*(N*K+q-2)*(q+1)
right=(2*q-1)*(N+K)*(N*K+q-2)*mprev+(q-2)*((q-1)**2-(K-N)**2)*mprevprev
assert left == right
counts['recurrence'] += 1
if q == 2:
assert actual == QQ(N+K)/QQ(N*K+1)
counts['purity'] += 1
if q == 3:
assert actual == QQ(N*N+3*N*K+K*K+1)/QQ((N*K+1)*(N*K+2))
counts['third_moment'] += 1
if q == 4:
assert actual == QQ(N**3+6*N*N*K+6*N*K*K+K**3+5*(N+K))/QQ((N*K+1)*(N*K+2)*(N*K+3))
counts['fourth_moment'] += 1
if N == 2:
assert actual == qubit_integral(K,q)
counts['qubit_eigenvalue_integral'] += 1
if N == K == 2:
assert actual == qubit_hs(q)
counts['qubit_hs_formula'] += 1
for N,K in {(N,K) for N,K,q in values}:
assert wick(N,K,0) == N and wick(N,K,1) == 1
assert moment(N,K,0) == N and moment(N,K,1) == 1
counts['zeroth_and_first_controls'] += 1
return {'entries':len(values),'counts':dict(counts),'permutations_enumerated':sum(factorial(q) for q in range(2,9)),
'max_written_length':max(len(str(v)) for v in values.values()),'all_passed':True}
def generated_values():
generator=InducedTraceMoments()
return {tuple(p[n] for n in generator.parameters):generator.value(p) for p in generator.enumerate()}
def parse_exact(value):
text=str(value).strip()
if '/' in text:
numerator,denominator=text.split('/')
return QQ(int(numerator))/QQ(int(denominator))
return QQ(int(text))
def stored_values():
document=numberdb.table('T574')
assert tuple(document['Parameters']) == ('N','K','q')
records=document['Numbers']
if isinstance(records,list):
return {tuple(int(r['params'][n]) for n in ('N','K','q')):parse_exact(r['number']) for r in records}
# API reads may nest flat submissions by the declared parameter order.
assert isinstance(records,dict)
return {(int(N),int(K),int(q)):parse_exact(v['number'] if isinstance(v,dict) else v)
for N,by_K in records.items() for K,by_q in by_K.items()
for q,v in by_q.items()}
if __name__ == '__main__':
if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
os.environ['NUMBERDB_API_KEY']=sys.stdin.read().strip()
data=stored_values() if '--stored' in sys.argv else generated_values()
print(json.dumps(run_checks(data),indent=2))