"""Values of the Struve function H_nu(x) -- numberdb.org/T492.

Run with SageMath (or a compatible passagemath environment):
    sage -pip install numberdb
    sage -python generate.py

The default command verifies every stored entry. Reading an unpublished draft
requires NUMBERDB_API_KEY. This file never creates, offers, or publishes a table.
An authorized maintainer may use StruveH().publish() to send numerical entries;
that client method does not change a draft's publication state.

Normalization: DLMF 11.2.1, real principal powers at positive rational x.
The defining series is evaluated through Arb's generalized hypergeometric
function. Precision is numberdb.bits(digits, losing=64); checks.py measures
all errors and checks an independent integral, including its elementary
half-integer cases. Parameters are ordered nu, x and enumerated increasingly.
"""
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
ORDERS = tuple(QQ(n) / 2 for n in range(5))


def arguments():
    return sorted({QQ(a) / b for b in range(1, 5)
                   for a in range(1, 20 * b + 1)})


def struve_h(nu, x, digits=100):
    C = ComplexBallField(numberdb.bits(digits, losing=WORKING_GUARD))
    n, z = C(nu), C(x)
    half = QQ(1) / 2
    w = ((z / 2) ** (n + 1)
         * (-(z * z) / 4).hypergeometric([1], [3 * half, n + 3 * half])
         / (C(3 * half).gamma() * (n + 3 * half).gamma()))
    assert w.real().is_finite() and w.imag().is_finite() and w.imag().contains_zero()
    return w.real()


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

    def enumerate(self):
        for nu in ORDERS:
            for x in arguments():
                yield {'nu': str(nu), 'x': str(x)}

    def value(self, params, digits):
        return struve_h(QQ(params['nu']), QQ(params['x']), digits)


if __name__ == '__main__':
    if os.environ.get('NUMBERDB_KEY_FROM_STDIN'):
        os.environ['NUMBERDB_API_KEY'] = sys.stdin.read().strip()
    report = StruveH().verify(sample=None)
    print(report)
    sys.exit(0 if report.ok else 1)
