generate.py

back to table · edit · history · where entries came from · files · download

4088 bytes, as of the version from 2026-11-02 11:34 (current). Recorded here, not run.

"""Frobenius polynomials of hypergeometric Calabi–Yau motives -- numberdb.org/T674.

Run with SageMath:
    sage -pip install numberdb               # once
    sage -python generate.py                  # verify the stored draft/table
    sage -python generate.py --fill           # write entries with an API key
    sage -python checks.py                   # independent offline checks

This writes no publication/review state. The default enumeration is all fourteen
Calabi–Yau templates, z=1/2,-1,2, and every good prime <=31. See
argument-selection.md. Rational input is exact; there is no decimal precision
claim. Sage's Gross–Koblitz traces are recovered as centered integers with
p^N > 8*p^(3f/2). The Weil trace bound |trace| <=4*p^(3f/2) makes the integer
unique. Newton's identity and weight-three reciprocity give the polynomial.
The checks use PARI at the reciprocal coordinate and direct character sums.
"""
import os
import sys
from functools import lru_cache
import numberdb.sage as numberdb
from sage.rings.integer_ring import ZZ
from sage.rings.rational_field import QQ
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
from sage.symbolic.ring import SR  # initialize symbolic functions for HGM
from sage.modular.hypergeometric_motive import HypergeometricData

R = PolynomialRing(ZZ, 'T')
T = R.gen()
TEMPLATES = ('2.2.2.2','2.2.3','2.2.4','2.2.6','3.3','3.4','3.6',
             '4.4','4.6','6.6','5','8','10','12')
FIBRES = ('1/2','-1','2')
PRIME_BOUND = 31

@lru_cache(None)
def motive(template):
    if template not in TEMPLATES:
        raise ValueError('Unknown Calabi-Yau template')
    h = HypergeometricData(cyclotomic=([ZZ(x) for x in template.split('.')],
                                     [ZZ(1)]*4))
    assert h.degree() == 4 and h.weight() == 3
    assert list(h.hodge_numbers()) == [1,1,1,1]
    return h

def trace_precision(p, f):
    n = 1
    while p**(2*n) <= 64*p**(3*f):
        n += 1
    return n

@lru_cache(None)
def traces(template, z_string, p_int):
    h, z, p = motive(template), QQ(z_string), ZZ(p_int)
    if not p.is_prime(proof=True) or z in (0,1):
        raise ValueError('Require a good prime and a nonsingular rational fibre')
    if any(d % p == 0 for d in (z.numerator(),z.denominator(),
                                (z-1).numerator())):
        raise ValueError('Tame prime excluded')
    if any(a.denominator() % p == 0 for a in h.alpha_beta()[0]):
        raise ValueError('Wild prime excluded')
    out = []
    for f in (1,2):
        n = trace_precision(p,f)
        # cache_p=False keeps precision-dependent coefficients separate.
        a = ZZ(h.padic_H_value(p,f,z,prec=n,cache_p=False))
        assert a*a <= 16*p**(3*f)
        out.append(a)
    return tuple(out)

class CalabiYauFrobenius(numberdb.Generator):
    table = 'T674'
    parameters = ('template','z','p')
    type = 'Z[]'
    rigour = 'exact'
    files = ('generate.py','checks.py','argument-selection.md','numerical-evidence.md',
             'check.py','skill-evidence.json')

    def enumerate(self, prime_bound=PRIME_BOUND):
        for key in TEMPLATES:
            indices = tuple(int(x) for x in key.split('.'))
            for z in FIBRES:
                for p in range(3,int(prime_bound)+1):
                    if ZZ(p).is_prime(proof=True) and all(d % p for d in indices):
                        yield {'template':key,'z':z,'p':str(p)}

    def value(self, params, digits=100):
        a, c2 = traces(params['template'],str(params['z']),int(params['p']))
        p = ZZ(params['p'])
        assert (a*a-c2) % 2 == 0
        b = (a*a-c2)//2
        return R([1,-a,b,-p**3*a,p**6])

if __name__ == '__main__':
    if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
        os.environ['NUMBERDB_API_KEY'] = sys.stdin.read().strip()
    gen = CalabiYauFrobenius()
    if '--fill' in sys.argv:
        print(gen.publish(message='Fill exact Calabi-Yau local factors after independent checks'))
    else:
        report = gen.verify(sample=None)
        print(report)
        sys.exit(0 if report.ok else 1)