back to table · edit · history · where entries came from · files · download
3243 bytes, as of the version from 2026-10-30 12:25 (current). Recorded here, not run.
"""Volumes of real and complex Grassmann manifolds -- numberdb.org/T625.
Run with SageMath:
sage -pip install numberdb
sage -python generate.py # verify all stored entries
sage -python generate.py --fill # write entries to this draft
Filling requires NUMBERDB_API_KEY; it does not publish or offer the table.
The campaign wrapper may instead pipe the key and set NUMBERDB_KEY_FROM_STDIN=1
and NUMBERDB_PUBLISH=1. This file has no selection or numerical dependencies.
The metric is ds^2 = Re tr(dP^2)/2 on rank-k orthogonal projectors.
Both fields and 2 <= n <= 16, 1 <= k <= floor(n/2), give 128 entries.
See argument-selection.md for the discrete family and practical finite bound.
Integer and half-integer Gamma factors are reduced exactly before evaluating
one integer power of pi with Arb. A 64-bit guard is measured by check_values.py.
"""
import os
import sys
from math import factorial
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.real_arb import RealBallField
WORKING_GUARD = 64
MAX_N = 16
FIELDS = ('real', 'complex')
def gamma_factor(twice_argument):
"""Return exact (r, e) for Gamma(t/2) = r*pi^(e/2), t positive."""
t = int(twice_argument)
if t < 1:
raise ValueError('Gamma argument must be positive')
if t % 2 == 0:
return QQ(factorial(t//2-1)), 0
m = (t-1)//2
return QQ(factorial(2*m))/QQ(4**m*factorial(m)), 1
def exact_form(field, n, k):
"""Return (c, e) such that G = c*pi^e, with c rational and e integer."""
if field not in FIELDS or n < 2 or not 1 <= k < n:
raise ValueError('need real or complex, n >= 2, 1 <= k < n')
beta = 1 if field == 'real' else 2
coefficient = QQ(1)
twice_exponent = beta*k*(n-k)
for i in range(1, k+1):
a, ea = gamma_factor(beta*i)
b, eb = gamma_factor(beta*(n-k+i))
coefficient *= a/b
twice_exponent += ea-eb
assert twice_exponent % 2 == 0
return coefficient, twice_exponent//2
class GrassmannVolumes(numberdb.Generator):
table = 'T625'
parameters = ('field', 'n', 'k')
type = 'R'
digits = 100
rigour = 'proven'
def enumerate(self, max_n=MAX_N):
for field in FIELDS:
for n in range(2, max_n+1):
for k in range(1, n//2+1):
yield {'field':field, 'n':n, 'k':k}
def value(self, params, digits):
c, e = exact_form(params['field'], int(params['n']), int(params['k']))
if e == 0:
return c
R = RealBallField(numberdb.bits(digits, losing=WORKING_GUARD))
return R(c)*R.pi()**e
if __name__ == '__main__':
if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
key = sys.stdin.read().strip()
if key.startswith('NUMBERDB_'):
key = key.split('=', 1)[1].strip().strip('\"\'')
numberdb.configure(api_key=key)
generator = GrassmannVolumes()
if '--fill' in sys.argv or os.environ.get('NUMBERDB_PUBLISH') == '1':
print(generator.publish(message='Compute 128 Grassmann volumes with certified 100-digit enclosures'))
else:
report = generator.verify(sample=None)
print(report)
sys.exit(0 if report.ok else 1)