back to table · edit · history · where entries came from · files · download
4939 bytes, as of the version from 2026-11-09 11:44. Recorded here, not run.
"""Genus-zero Gopakumar–Vafa invariants of projective complete intersections -- numberdb.org/T689.
Run with SageMath:
sage -pip install numberdb # once
sage -python generate.py # verify all stored entries
sage -python generate.py --fill # fill this draft, with NUMBERDB_API_KEY
sage -python checks.py # independent checks; no network
All arithmetic is exact in QQ; final invariants are returned in ZZ. The
standalone generator uses the geometric Yukawa coupling, formal inverse of
q=x exp(G/F), and triangular Lambert-series extraction. No live table is an
input. Default coverage is all five ordinary-projective Calabi–Yau threefold
complete-intersection types and degrees 1 through 20. See argument-selection.md.
The extra four series orders are checked against eight extra orders in checks.py.
Filling entries neither offers nor publishes a draft.
"""
import os
import sys
from functools import lru_cache
from math import factorial, prod
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.integer_ring import ZZ
TARGETS = ((5,), (2, 4), (3, 3), (2, 2, 3), (2, 2, 2, 2))
MAX_DEGREE = 20
EXTRA_ORDERS = 4
def multiply(a, b):
n = len(a) - 1
return [sum((a[j] * b[i-j] for j in range(i+1)), QQ(0))
for i in range(n+1)]
def reciprocal(a):
n = len(a) - 1
b = [QQ(1) / a[0]]
for i in range(1, n+1):
b.append(-sum((a[j] * b[i-j] for j in range(1, i+1)), QQ(0)) / a[0])
return b
def exponential(a):
assert a[0] == 0
b = [QQ(1)]
for i in range(1, len(a)):
b.append(sum((QQ(j) * a[j] * b[i-j] for j in range(1, i+1)), QQ(0)) / QQ(i))
return b
def compose(a, b):
assert b[0] == 0
out = [QQ(0)] * len(a)
for coefficient in reversed(a):
out = multiply(out, b)
out[0] += coefficient
return out
def periods(target, order):
r = len(target)
harmonics = [QQ(0)]
for j in range(1, max(target)*order+1):
harmonics.append(harmonics[-1] + QQ(1)/QQ(j))
f, g = [], []
for m in range(order+1):
a = QQ(prod(factorial(l*m) for l in target)) / QQ(factorial(m)**(r+4))
f.append(a)
g.append(a * (sum(l*harmonics[l*m] for l in target) - (r+4)*harmonics[m]))
return f, g
@lru_cache(maxsize=None)
def coefficients(target, order):
"""Return geometric Yukawa, GW and GV coefficients through order inclusive."""
assert target in TARGETS
f, g = periods(target, order)
h = multiply(g, reciprocal(f))
jacobian = [QQ(1)] + [QQ(i)*h[i] for i in range(1, order+1)]
inv_jacobian = reciprocal(jacobian)
inv_f = reciprocal(f)
c = prod(l**l for l in target)
kappa = prod(target)
coupling = [QQ(kappa) * QQ(c)**i for i in range(order+1)]
for factor in (inv_f, inv_f, inv_jacobian, inv_jacobian, inv_jacobian):
coupling = multiply(coupling, factor)
# Fixed-point inversion x(q)=q exp(-h(x(q))). Each iteration fixes
# at least one additional coefficient, since h(0)=0.
x = [QQ(0), QQ(1)] + [QQ(0)]*(order-1)
for _ in range(order):
e = exponential([-v for v in compose(h, x)])
x = [QQ(0)] + e[:-1]
q = [QQ(0)] + exponential(h)[:-1]
assert compose(q, x) == [QQ(0), QQ(1)] + [QQ(0)]*(order-1)
k = compose(coupling, x)
gw = [QQ(0)] + [k[d]/QQ(d**3) for d in range(1, order+1)]
gv = [ZZ(0)]
for d in range(1, order+1):
proper = sum((QQ(e**3)*gv[e] for e in range(1, d) if d % e == 0), QQ(0))
value = (k[d] - proper) / QQ(d**3)
assert value.denominator() == 1, (target, d, value)
gv.append(ZZ(value))
return k, gw, gv
class GenusZeroGV(numberdb.Generator):
table = 'T689'
parameters = ('multidegree', 'd')
type = 'Z'
rigour = 'exact'
digits = 100
def enumerate(self, maximum_degree=MAX_DEGREE):
for target in TARGETS:
for d in range(1, maximum_degree+1):
yield {'multidegree': ','.join(map(str, target)), 'd': str(d)}
def value(self, params, digits):
target = tuple(int(v) for v in params['multidegree'].split(','))
d = int(params['d'])
assert d >= 1
return coefficients(target, max(MAX_DEGREE, d)+EXTRA_ORDERS)[2][d]
if __name__ == '__main__':
if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
token = sys.stdin.read().strip()
if '=' in token and token.split('=', 1)[0].replace('_', '').isalnum():
token = token.split('=', 1)[1].strip().strip('\"\'')
numberdb.configure(api_key=token)
generator = GenusZeroGV()
if '--fill' in sys.argv or os.environ.get('NUMBERDB_PUBLISH') == '1':
print(generator.publish(message='Fill exact genus-zero GV invariants after independent checks'))
else:
report = generator.verify(sample=None)
print(report)
sys.exit(0 if report.ok else 1)