generate.py

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

2376 bytes, as of the version from 2026-10-26 08:43. Recorded here, not run.

"""Values of the Kelvin function kei_nu(x) -- numberdb.org/T509.

Run with SageMath (or a compatible passagemath installation):
    sage -pip install numberdb
    sage -python generate.py                  # verify every stored entry
    sage -python generate.py --fill           # fill an authorized draft

The fill command requires NUMBERDB_API_KEY. It writes entries and attaches
this source; it does not publish the draft or offer it for review.

DLMF 10.61.2 fixes the principal-branch definition:
kei_nu(x) = Im(exp(-nu*pi*i/2) K_nu(x exp(pi*i/4))).
The phase is exact at the integer orders stored here. Rational arguments and
the rotation are enclosed in complex balls. The 64-bit guard is measured by
checks.py, which also checks all values by independent certified quadrature.
The finite selection is the family #205 rectangle of low integer orders at
simple integer, half-, third-, and quarter-unit arguments through x=20.
"""
import os
import sys
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.complex_arb import ComplexBallField

WORKING_GUARD = 64


class KelvinKei(numberdb.Generator):
    table = "T509"
    parameters = ("nu", "x")
    type = "R"
    digits = 100
    rigour = "proven"

    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):
        nu = QQ(params["nu"])
        if nu.denominator() != 1:
            raise ValueError("This generator uses the exact integer-order phase.")
        C = ComplexBallField(numberdb.bits(digits, losing=WORKING_GUARD))
        z = C(QQ(params["x"])) * C(1, 1) / C(2).sqrt()
        return (C(0, -1)**int(nu) * z.bessel_K(C(nu))).imag()


if __name__ == "__main__":
    if os.environ.get("NUMBERDB_KEY_FROM_STDIN") == "1":
        os.environ["NUMBERDB_API_KEY"] = sys.stdin.read().strip()
    generator = KelvinKei()
    if "--fill" in sys.argv or os.environ.get("NUMBERDB_PUBLISH") == "1":
        outcome = generator.publish(message="Fill Kelvin kei values with certified 100-digit enclosures")
        print(outcome)
    else:
        report = generator.verify(sample=None)
        print(report)
        sys.exit(0 if report.ok else 1)