back to table · edit · history · where entries came from · files · download
9179 bytes, as of the version from 2026-09-05 10:53. Recorded here, not run.
"""Hermite's constants gamma_n -- numberdb.org/T149
Hermite's constant gamma_n is the supremum, over all lattices L in R^n, of
the Hermite number
gamma(L) = mu(L) / (det L)^(1/n)
with mu(L) the squared length of a shortest nonzero vector of L and det L the
determinant of a Gram matrix of L: sqrt(gamma_n) is the greatest length a
shortest vector of a lattice of covolume 1 in R^n can have. It is known for
n <= 8 and n = 24, and in no other dimension:
gamma_n^n = 1, 4/3, 2, 4, 8, 64/3, 64, 256 for n = 1, ..., 8
gamma_24^24 = 4^24
attained by Z, A_2, A_3, D_4, D_5, E_6, E_7, E_8 and the Leech lattice. The
table has one parameter, `n`, and one entry per dimension in which gamma_n is
known.
Run it with SageMath:
$ sage -pip install numberdb # once
$ sage -python generate.py # check the table against this code
$ sage -python generate.py --publish # send it, with NUMBERDB_API_KEY set
**Where the values come from.** The datum for each entry is the rational
number gamma_n^n, which is a theorem in each dimension listed (Lagrange for
n = 2, Gauss for n = 3, Korkine and Zolotareff for n = 4 and 5, Blichfeldt
for n = 6, 7 and 8, Cohn and Kumar for n = 24), together with the lattice
attaining it. Before a value is returned, gamma_n^n is recomputed as
mu^n / det from the Gram matrix of that lattice for n <= 8 -- the identity
for Z and the Cartan matrix for the root lattices, with mu from PARI's
qfminim -- and a disagreement is an error rather than an entry. For n = 24
the Leech lattice is even and unimodular with minimal norm 4, so
gamma_24^24 = 4^24 / 1; that Gram matrix is not carried here, and the
outside checks recomputed it from the catalogue's block.
**Exact arithmetic up to the last step.** gamma_n is written exactly when
gamma_n^n is an n-th power of a rational (n = 1, 8, 24: the values 1, 2, 4)
and otherwise as the ball for the n-th root in arb. No division of Python
integers occurs anywhere in this file.
**These digits are proven.** With the guard below, the widest ball in the
table, relative to its value, has radius 1.4e-119 (measured at 100 digits
over every entry: gamma_7), so 100 digits are supported with room.
**What was checked outside this file** when the table was made, before any
entry was sent: gamma_n^n against OEIS A007361/A007362; the digits of
gamma_2 to gamma_7 against OEIS A020832 (1/sqrt 75, ten times gamma_2),
A002580, A002193, A011093, A246184 and A246722; the closed forms of the
Wikipedia and MathWorld pages; the stored Hermite numbers of the table of
the classical lattices, of which gamma_n is the maximum in each dimension
listed, and the stored centre densities of the table of the densest lattice
packings, from which gamma_n = 4 delta_n^(2/n); the Leech lattice's
determinant and minimal norm from the catalogue's Gram block; and Hermite's,
Minkowski's, Blichfeldt's and Mordell's inequalities on every entry.
"""
import sys
import numberdb.sage as numberdb
from sage.rings.integer_ring import ZZ
from sage.rings.rational_field import QQ
from sage.rings.real_arb import RealBallField
from sage.matrix.constructor import matrix
from sage.libs.pari.all import pari
#: Bits of working precision beyond what the written digits need. Measured
#: over the whole table at 100 digits: the widest ball, relative to its
#: value, is gamma_7 with relative radius 1.4e-119.
WORKING_GUARD = 64
#: gamma_n^n in every dimension where Hermite's constant is known, with the
#: lattice attaining it (family and dimension, as the table of the classical
#: lattices names them) and the reference key of the table document for the
#: theorem.
KNOWN = {
1: (QQ(1), 'Z', 1, None),
2: (QQ(4) / 3, 'A', 2, 'Lagrange'),
3: (QQ(2), 'A', 3, 'Gauss'),
4: (QQ(4), 'D', 4, 'KZ'),
5: (QQ(8), 'D', 5, 'KZ'),
6: (QQ(64) / 3, 'E', 6, 'Blichfeldt'),
7: (QQ(64), 'E', 7, 'Blichfeldt'),
8: (QQ(256), 'E', 8, 'Blichfeldt'),
24: (QQ(4) ** 24, 'Lambda', 24, 'CohnKumar'),
}
#: gamma_n in closed form, for the entry comment.
CLOSED_FORM = {
1: '1',
2: r'\frac{2}{\sqrt{3}}',
3: r'2^{1/3}',
4: r'\sqrt{2}',
5: r'2^{3/5}',
6: r'\frac{2}{3^{1/6}}',
7: r'2^{6/7}',
8: '2',
24: '4',
}
#: The attaining lattice, as a phrase for the entry comment.
LATTICE = {
1: r'$\mathbb{Z}$',
2: r'the hexagonal lattice $A_2$',
3: r'$A_3=D_3$, the face-centred cubic lattice',
4: r'$D_4$',
5: r'$D_5$',
6: r'$E_6$',
7: r'$E_7$',
8: r'$E_8$',
24: r'the Leech lattice $\Lambda_{24}$',
}
#: The row of the table of the classical lattices holding gamma(L) for the
#: attaining lattice L (address read off the stored document).
CLASSICAL = 'Packing_densities_and_Hermite_numbers_of_the_classical_lattices'
def cartan(kind, n):
"""The Cartan matrix of A_n, D_n or E_n as an integer matrix: 2 on the
diagonal, -1 between neighbours in the Dynkin diagram. E_n uses
Bourbaki's numbering, the chain 1-3-4-5-...-n with node 2 attached to
node 4."""
M = [[0] * n for _ in range(n)]
for i in range(n):
M[i][i] = 2
if kind == 'A':
for i in range(n - 1):
M[i][i + 1] = M[i + 1][i] = -1
elif kind == 'D':
if n < 4:
raise ValueError('D_n needs n >= 4, not %s' % n)
for i in range(n - 2):
M[i][i + 1] = M[i + 1][i] = -1
M[n - 3][n - 1] = M[n - 1][n - 3] = -1
elif kind == 'E':
if n not in (6, 7, 8):
raise ValueError('E_n needs n in 6, 7, 8, not %s' % n)
chain = [0, 2, 3, 4, 5, 6, 7][:n - 1]
for a, b in zip(chain, chain[1:]):
M[a][b] = M[b][a] = -1
M[1][3] = M[3][1] = -1
else:
raise ValueError('no Cartan matrix of kind %r' % kind)
return matrix(ZZ, M)
def gram(family, n):
"""An integral Gram matrix of the attaining lattice, for n <= 8."""
n = int(n)
if family == 'Z':
return matrix(ZZ, n, n, lambda i, j: 1 if i == j else 0)
if family in ('A', 'D', 'E'):
return cartan(family, n)
raise ValueError('no Gram matrix carried for %s_%d' % (family, n))
def hermite_power_from_lattice(family, n):
"""mu^n / det of the attaining lattice, an exact rational, from its
Gram matrix and PARI's qfminim."""
G = gram(family, n)
det = ZZ(G.det())
if det <= 0:
raise ArithmeticError('%s_%d: Gram matrix is not positive definite' % (family, n))
found = pari(G).qfminim(None, None, 0)
mu = ZZ(found[1])
return QQ(mu) ** ZZ(n) / QQ(det)
def compute(n, bits):
n = int(n)
if n not in KNOWN:
raise ValueError("Hermite's constant is not known in dimension %d" % n)
power, family, dim, _ = KNOWN[n]
if dim != n:
raise ValueError('n = %d is attained by a lattice of dimension %d' % (n, dim))
if n <= 8:
recomputed = hermite_power_from_lattice(family, n)
if recomputed != power:
raise ArithmeticError('n = %d: %s_%d gives gamma^n = %s, the table says %s'
% (n, family, n, recomputed, power))
if power.is_nth_power(n):
gamma = power.nth_root(n)
else:
RBF = RealBallField(bits)
gamma = RBF(power) ** (QQ(1) / n)
if not gamma.is_finite():
raise ArithmeticError('n = %d: the root is not a finite ball' % n)
return {'hermite': gamma, 'power': power}
def latex_rational(r):
r = QQ(r)
if r.denominator() == 1:
return str(r.numerator())
return r'\frac{%d}{%d}' % (r.numerator(), r.denominator())
def latex_power(n, power):
"""gamma_n^n as the comment writes it: the reduced fraction, or 4^{24}."""
if n == 24:
return '4^{24}'
return latex_rational(power)
def comment(n, values):
n = int(n)
power, _, _, who = KNOWN[n]
text = r'$\gamma_{%d}=%s$, $\gamma_{%d}^{\,%d}=%s$; attained by %s' % (
n, CLOSED_FORM[n], n, n, latex_power(n, power), LATTICE[n])
if who:
text += ' CITE{%s}' % who
return text
def equals_link(n):
_, family, dim, _ = KNOWN[int(n)]
return 'HREF{%s#%s,%d,hermite}' % (CLASSICAL, family, dim)
class HermiteConstants(numberdb.Generator):
table = 'T149'
parameters = ('n',)
type = 'R'
digits = 100
rigour = 'proven'
def enumerate(self):
for n in sorted(KNOWN):
yield {'n': n}
def value(self, params, digits):
n = int(params['n'])
bits = numberdb.bits(digits, losing=WORKING_GUARD)
values = compute(n, bits)
return {'number': values['hermite'],
'comment': comment(n, values),
'equals': equals_link(n)}
if __name__ == '__main__':
generator = HermiteConstants()
if '--publish' in sys.argv:
print(generator.publish(
message="Hermite's constant gamma_n in every dimension where it is known, "
"n <= 8 and n = 24: the n-th root of the exact rational gamma_n^n, "
"written exactly where that is an integer and as a ball otherwise"))
else:
report = generator.verify()
print(report)
sys.exit(0 if report.ok else 1)