back to table · edit · history · where entries came from · files · download
4851 bytes, as of the version from 2026-10-27 13:49 (current). Recorded here, not run.
"""Orthogonal Weingarten functions -- numberdb.org/T550.
Run with SageMath (install numberdb with sage -pip install numberdb):
sage -python generate.py # verify every stored entry
sage -python generate.py --fill-draft # write entries to the existing draft
Writing needs NUMBERDB_API_KEY; this never offers or publishes the table.
The campaign can instead pipe the key with NUMBERDB_KEY_FROM_STDIN=1 and
set NUMBERDB_PUBLISH=1 to fill its draft through agents/sage.sh.
Values are exact Sage rationals. The zonal polynomial is Jack J at alpha=2.
Collins--Matsumoto, arXiv:0903.5143, equations (3.5)--(3.7), give its power-sum
coefficients as the spherical functions multiplied by pairing-orbit sizes.
Dimensions f^(2 lambda) use the hook-length formula. Every division is exact.
Default coverage: every N=1,...,12 and every partition of 1<=k<=min(6,N),
ordered by N, then k, then reverse lexicographic partition order.
See argument-selection.md for the coverage rationale and independent_checks.py
for pairing-Gram and sphere-moment checks, which do not use Jack polynomials.
"""
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.symbolic.ring import SR # Initializes symbolic conversions used by Sage.
import sage.rings.polynomial.laurent_polynomial_ring # Matrix ring dispatch.
from sage.combinat.partition import Partitions
from sage.combinat.sf.sf import SymmetricFunctions
from collections import Counter
from functools import lru_cache
from math import factorial, prod
import os
import sys
@lru_cache(None)
def zonal_expansions(k):
"""Return exact coefficients [p_mu] J_lambda^(2) for all lambda of k."""
sf = SymmetricFunctions(QQ)
p = sf.power()
jack = sf.jack(t=QQ(2)).J()
return {
tuple(lam): {tuple(mu): QQ(c) for mu, c in p(jack[lam])}
for lam in Partitions(k)
}
def character_dimension(lam):
"""Dimension of the symmetric-group representation with shape lam."""
hooks = [row - j + sum(next_row > j for next_row in lam[i + 1:])
for i, row in enumerate(lam) for j in range(row)]
numerator, denominator = factorial(sum(lam)), prod(hooks)
assert numerator % denominator == 0
return numerator // denominator
def pairing_orbit_size(mu):
k = sum(mu)
z = prod(part**count * factorial(count)
for part, count in Counter(mu).items())
numerator, denominator = 2**k * factorial(k), 2**len(mu) * z
assert numerator % denominator == 0
return numerator // denominator
def weingarten(N, mu):
"""The conventional coefficient, including singular positive dimensions."""
N, mu = int(N), tuple(int(x) for x in mu)
if N < 1 or not mu or any(x < 1 for x in mu) or mu != tuple(sorted(mu, reverse=True)):
raise ValueError('N must be positive and mu a nonempty decreasing partition')
k = sum(mu)
total = QQ(0)
for lam, coefficients in zonal_expansions(k).items():
if len(lam) > N:
continue
denominator = prod(N + 2*j - i for i, row in enumerate(lam) for j in range(row))
assert denominator > 0
dimension = character_dimension(tuple(2*x for x in lam))
total += QQ(dimension) * coefficients.get(mu, QQ(0)) / QQ(denominator)
return (QQ(2**k * factorial(k)) * total
/ QQ(factorial(2*k) * pairing_orbit_size(mu)))
class OrthogonalWeingarten(numberdb.Generator):
table = 'T550'
parameters = ('N', 'mu')
type = 'Q'
rigour = 'exact'
files = ('generate.py', 'independent_checks.py', 'argument-selection.md',
'check.py', 'auxiliary_checks.py', 'program.py',
'numerical-evidence.md', 'skill-evidence.json')
def enumerate(self, max_dimension=12, max_degree=6):
for N in range(1, max_dimension + 1):
for k in range(1, min(max_degree, N) + 1):
for mu in sorted((tuple(p) for p in Partitions(k)), reverse=True):
yield {'N': str(N), 'mu': ','.join(map(str, mu))}
def value(self, params, digits):
return weingarten(int(params['N']), tuple(map(int, params['mu'].split(','))))
def configure_key_from_stdin():
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('\'"')
numberdb.configure(api_key=key)
if __name__ == '__main__':
configure_key_from_stdin()
generator = OrthogonalWeingarten()
if '--fill-draft' in sys.argv or os.environ.get('NUMBERDB_PUBLISH') == '1':
print(generator.publish(message='Fill 242 exact orthogonal Weingarten coefficients with independent checks'))
else:
report = generator.verify(sample=None)
print(report)
sys.exit(0 if report.ok else 1)