generate.py

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

3411 bytes, as of the version from 2026-10-29 10:07 (current). Recorded here, not run.

"""Sharp upper constants in the Khintchine inequality -- numberdb.org/T606.

Run with SageMath (or a compatible passagemath installation):
    sage -pip install numberdb
    sage -python generate.py              # verify every stored entry
    sage -python checks.py                # independent local checks
    sage -python dry_run.py generate.py   # compute without sending
    sage -python generate.py --fill       # fill the existing draft, key required

--fill calls Generator.publish, which sends entries and attachments only; it
neither offers this draft for review nor makes the table public. An unpublished
draft also needs NUMBERDB_API_KEY for verification. The campaign may supply the
key on stdin with NUMBERDB_KEY_FROM_STDIN=1 and use NUMBERDB_PUBLISH=1 to fill.

The exact comparison p <= 2 selects the unit branch. For p > 2, Arb evaluates
the positive Gaussian-moment formula with a measured 96-bit guard (429 bits for
100 digits). argument-selection.md explains all enumeration choices. checks.py
records actual radii, independently integrates the Gaussian moment, and tests
integer-moment identities and finite Rademacher sums. No rounded input or
fixed-precision output is promoted to a certified enclosure.
"""
import json
import os
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

WORKING_GUARD = 96


def selected_exponents():
    values = {QQ(1), QQ(2)}
    values.update(QQ(n) for n in range(3, 33))
    for b in range(2, 7):
        for a in range(2 * b + 1, 4 * b):
            p = QQ(a) / QQ(b)
            if p.denominator() == b:
                values.add(p)
    values.update(QQ(n) / QQ(2) for n in range(9, 20, 2))
    return sorted(values)


class UpperKhintchine(numberdb.Generator):
    table = 'T606'
    parameters = ('p',)
    type = 'R'
    digits = 100
    rigour = 'proven'
    files = ('generate.py', 'argument-selection.md', 'checks.py', 'check.py', 'dry_run.py',
             'skill-evidence.json', 'sources.md')

    def enumerate(self):
        for p in selected_exponents():
            yield {'p': str(p)}

    def value(self, params, digits):
        p = QQ(params['p'])
        if p <= 0:
            raise ValueError('p must be positive')
        if p <= 2:
            return ZZ(1)
        field = RealBallField(numberdb.bits(digits, losing=WORKING_GUARD))
        moment = field((p + 1) / QQ(2)).gamma() / field.pi().sqrt()
        value = field(2).sqrt() * (moment.log() / field(p)).exp()
        if not value.is_finite() or not value > 1:
            raise ArithmeticError('Gaussian branch was not certified positive and above 1')
        return value


if __name__ == '__main__':
    if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
        numberdb.configure(api_key=sys.stdin.read().strip())
    generator = UpperKhintchine()
    if '--fill' in sys.argv or os.environ.get('NUMBERDB_PUBLISH') == '1':
        result = generator.publish(message='Fill 60 sharp upper Khintchine constants with certified enclosures')
        print(result)
        print('Attached:', ', '.join(result.files))
        print(json.dumps({'table': result.table, 'run': result.run, 'files': result.files, 'applied': result.applied}))
    else:
        result = generator.verify(sample=None)
        print(result)
        sys.exit(0 if result.ok else 1)