generate.py

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

2488 bytes, as of the version from 2026-10-25 14:36. Recorded here, not run.

"""Values of the Kelvin function ber_nu(x) -- numberdb.org/T490.

Run with SageMath or a modular passagemath installation:
    sage -pip install numberdb
    sage -python generate.py             # verify the stored draft/table
    sage -python generate.py --fill      # write entries, with NUMBERDB_API_KEY

A private draft needs its owner's API key even for verification. The --fill
option writes entries and sources to this existing table; it cannot publish
or offer the draft for review.

Convention: DLMF 10.61.1, ber_nu(x) = Re J_nu(x exp(3*pi*i/4)), using the
principal branch of J. The rotation is (-1+i)/sqrt(2), evaluated entirely in
complex balls. Orders 0, 1, 2 and all positive reduced rationals a/b with
b <= 4 and x <= 20 follow the shared Kelvin family conventions.

The 64-bit guard is measured by checks.py over every entry. Independent
verification uses an exact-rational power-series sum with an explicit tail
bound, mpmath's Kelvin implementation, a Schlaefli integral, and the rotated
modified-Bessel identity. No floating-point value is wrapped as a proof.
"""
import os
import sys
import numberdb.sage as numberdb
from sage.rings.complex_arb import ComplexBallField
from sage.rings.rational_field import QQ

WORKING_GUARD = 64


class KelvinBer(numberdb.Generator):
    table = 'T490'
    parameters = ('nu', 'x')
    type = 'R'
    digits = 100
    rigour = 'proven'
    files = ('generate.py', 'checks.py', 'check.py')

    def enumerate(self):
        arguments = sorted({QQ(a)/QQ(b)
                            for b in range(1, 5)
                            for a in range(1, 20*b+1)})
        for nu in range(3):
            for x in arguments:
                yield {'nu': str(nu), 'x': str(x)}

    def value(self, params, digits):
        C = ComplexBallField(numberdb.bits(digits, losing=WORKING_GUARD))
        z = C(QQ(params['x'])) * C(-1, 1) / C(2).sqrt()
        result = z.bessel_J(C(QQ(params['nu']))).real()
        if not result.is_finite():
            raise ArithmeticError('nonfinite Kelvin value')
        return result


if __name__ == '__main__':
    if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
        os.environ['NUMBERDB_API_KEY'] = sys.stdin.read().strip()
    generator = KelvinBer()
    if '--fill' in sys.argv:
        print(generator.publish(message='Compute Kelvin ber in certified ball arithmetic.'))
    else:
        report = generator.verify(sample=None)
        print(report)
        sys.exit(0 if report.ok else 1)