"""Dirichlet spectral determinants of homogeneous oscillators -- numberdb.org/T539.

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          # write entries with an authorized key

Set NUMBERDB_API_KEY for authenticated access to the unpublished draft. The
campaign wrapper also accepts NUMBERDB_KEY_FROM_STDIN=1 and NUMBERDB_PUBLISH=1.
Filling entries does not publish or offer the draft.

For H = -d^2/dx^2 + x^N on x >= 0 with y(0)=0, compute exp[-Z_N^-'(0)]
from Voros, Exercises in exact quantization, Appendix A.1, equation (136):
Gamma(nu) * nu**(1/2-nu) / sqrt(pi), nu = 1/(N+2).
All arguments are exact rationals; powers, Gamma and pi use Arb throughout.
The 96 guard bits protect the requested 100 significant digits. checks.py
measures the retained relative accuracy and independently reconstructs the
zero-energy boundary value from a Bessel solution and a Frobenius series.
The finite prefix N=1,...,12 is justified in argument-selection.md.
"""
import os
import sys

import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.real_arb import RealBallField

WORKING_GUARD = 96
MAX_DEGREE = 12


class DirichletDeterminants(numberdb.Generator):
    table = 'T539'
    parameters = ('N',)
    type = 'R'
    digits = 100
    rigour = 'proven'

    def enumerate(self, max_degree=MAX_DEGREE):
        for degree in range(1, max_degree + 1):
            yield {'N': degree}

    def value(self, params, digits):
        degree = int(params['N'])
        if degree < 1:
            raise ValueError('The degree must be a positive integer.')
        field = RealBallField(numberdb.bits(digits, losing=WORKING_GUARD))
        nu = QQ(1) / QQ(degree + 2)
        return field(nu).gamma() * field(nu)**(QQ(1)/2-nu) / field.pi().sqrt()


def authenticate_from_stdin():
    if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
        key = sys.stdin.read().strip()
        if '=' in key and key.split('=', 1)[0].isidentifier():
            key = key.split('=', 1)[1].strip().strip('\"\'')
        numberdb.configure(api_key=key)


if __name__ == '__main__':
    authenticate_from_stdin()
    generator = DirichletDeterminants()
    if '--fill' in sys.argv or os.environ.get('NUMBERDB_PUBLISH') == '1':
        print(generator.publish(message='Fill twelve Dirichlet determinants certified by Arb'))
    else:
        result = generator.verify(sample=None)
        print(result)
        sys.exit(0 if result.ok else 1)
