generate.py

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

4001 bytes, as of the version from 2026-11-11 08:15 (current). Recorded here, not run.

"""T714: Log-sinh-cosh integrals, 100 significant digits.

sage -pip install numberdb
sage -python generate.py              # verify every stored entry, no write
sage -python generate.py --publish    # fill the authorized draft, no offer

Requires SageMath or passagemath with Arb real balls and polynomials.
Parameters (m,n,x) have positive integer orders and exact positive real
endpoints x=logphi or 2logphi. The default 44-row selection follows CGLXZ
arXiv:2210.14704v1 (2.5); see argument-selection.md. No rounded endpoint or
stored sibling value is used. DLMF 4.36.1-2 gives the two kernel expansions.
The polynomial/log-moment integral is accompanied by a uniform integrated
tail bound; computation.md proves it. Working precision bits(digits+80),
series cutoff digits+60; 100 digits use 614 bits and 160 terms. Credentials
and upload provenance belong to the caller. checks.py provides independent
quadrature and binomial-series corroboration, not this generator's proof.
"""
import math
from functools import lru_cache
import numberdb.sage as numberdb
from sage.rings.real_arb import RealBallField
from sage.rings.rational_field import QQ
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing


def endpoint(R, key):
    a = ((R(1) + R(5).sqrt()) / 2).log()
    if key == 'logphi':
        return a
    if key == '2logphi':
        return 2*a
    raise ValueError('Unknown exact endpoint')


@lru_cache(maxsize=None)
def prepare(key, digits):
    R = RealBallField(numberdb.bits(digits+80))
    x = endpoint(R, key)
    qb, qc = (x/(2*R.pi()))**2, (x/R.pi())**2
    assert 0 < qb < qc < QQ(1)/10
    assert 2*qb/(1-qb) < 1
    assert R(2).log()+2*qc/(1-qc) < 1
    N = digits+60
    bc, cc = [x.log()], [R(2).log()]
    qj = R(1)
    for j in range(1, N+1):
        qj *= qb
        coeff = (-1)**(j+1)*R(2*j).zeta()*qj/j
        bc.append(coeff)
        cc.append((4**j-1)*coeff)
    ring = PolynomialRing(R, 'y2')
    eb = 2*qb**(N+1)/((N+1)*(1-qb))
    ec = 2*qc**(N+1)/((N+1)*(1-qc))
    return R, x, ring(bc), ring(cc), eb, ec


@lru_cache(maxsize=None)
def product_coefficients(key, digits, r, s):
    R, x, P, Q, eb, ec = prepare(key, digits)
    return (P**r*Q**s).list()


class LogSinhCosh(numberdb.Generator):
    table = 'T714'
    parameters = ('m', 'n', 'x')
    type = 'R'
    digits = 100
    rigour = 'proven'

    def enumerate(self):
        for m in range(1, 9):
            for n in range(2, 11-m):
                yield {'m': m, 'n': n, 'x': 'logphi'}
                if n == 2:
                    yield {'m': m, 'n': n, 'x': '2logphi'}

    @lru_cache(maxsize=None)
    def compute(self, m, n, key, digits):
        m, n, digits = int(m), int(n), int(digits)
        if m < 1 or n < 1:
            raise ValueError('Require m,n>=1')
        r, s = m-1, n-1
        R, x, P, Q, eb, ec = prepare(key, digits)
        total = R(0)
        for h in range(r+1):
            coeffs = product_coefficients(key, digits, r-h, s)
            moment = sum((c/R(2*j+1)**(h+1)
                          for j,c in enumerate(coeffs)), R(0))
            total += math.comb(r,h)*(-1)**h*math.factorial(h)*moment
        c = abs(x.log())+1
        def J(v):
            return sum((R(math.comb(v,h)*math.factorial(h))*c**(v-h)
                        for h in range(v+1)), R(0))
        error = x*((r*eb*J(r-1) if r else R(0))+s*ec*J(r))
        answer = (-x*total).add_error(error)
        assert type(answer).__name__ == 'RealBall'
        assert answer.is_finite()
        assert answer.accuracy() > numberdb.bits(digits+10)
        return answer

    def value(self, params, digits):
        return self.compute(int(params['m']), int(params['n']), str(params['x']), int(digits))


if __name__ == '__main__':
    import os, sys
    if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
        numberdb.configure(api_key=sys.stdin.read().strip())
    g = LogSinhCosh()
    print(g.publish(removing=False) if '--publish' in sys.argv else g.verify(sample=None))