"""Hankel derivative asymptotic coefficient polynomials -- numberdb.org/T570.

Run with SageMath (install numberdb once with sage -pip install numberdb):
    sage -python generate.py             # verify every stored entry, read only
    sage -python checks.py              # independent exact checks, offline

The generator retains every correction order 0 <= k <= 20 in increasing order.
It computes the DLMF 10.17.8 product over QQ, with no floating-point arithmetic.
The polynomial variable v denotes the Bessel order nu, matching the companion
T569; the NumberDB polynomial grammar accepts single-letter variable names.
The overall minus sign in the K derivative expansion is external to b_k.
No decimal precision or asymptotic remainder bound is claimed for exact data.
The rationale and measured extent are in argument-selection.md.

This file has no writing entry point. The NumberDB Generator API can fill an
existing draft using its author's authenticated client; this never publishes
that draft or offers it for review.
"""
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing

R = PolynomialRing(QQ, 'v')
nu = R.gen()
MAX_K = 20


def coefficient(k):
    """Return b_k(nu), exactly, with all denominator divisions in QQ."""
    k = int(k)
    if k < 0:
        raise ValueError('the correction order must be nonnegative')
    if k == 0:
        return R.one()
    product = R.one()
    for j in range(1, k):
        product *= (4*nu**2 - (2*j-1)**2) * (QQ(1)/QQ(8*j))
    return product * (4*nu**2 + 4*k**2 - 1) * (QQ(1)/QQ(8*k))


class HankelDerivative(numberdb.Generator):
    table = 'T570'
    parameters = ('k',)
    type = 'Q[]'
    rigour = 'exact'
    files = ('generate.py', 'checks.py', 'check.py', 'argument-selection.md',
             'numerical-evidence.md', 'skill-evidence.json', 'sources.json')

    def enumerate(self, max_k=MAX_K):
        for k in range(max_k + 1):
            yield {'k': str(k)}

    def value(self, params, digits):
        return coefficient(int(params['k']))


if __name__ == '__main__':
    report = HankelDerivative().verify(sample=None)
    print(report)
    raise SystemExit(0 if report.ok else 1)
