"""Jacobi theta3 constants at singular nomes -- numberdb.org/T504.

Run with SageMath:
    sage -pip install numberdb
    sage -python generate.py              # verify all stored entries
    sage -python checks.py                # independent numerical checks

Set NUMBERDB_API_KEY to read this table while it remains a private draft.
The generator class also supports preview() and publish() through numberdb;
publish() fills entries and does not change a draft's publication status.

For each positive integer r, return theta_3(0 | i*sqrt(r)), with the positive
square root. The initial selection is precisely r=1,...,12. Every operation,
including the square root in the argument, uses Arb complex balls. Sage's
jacobi_theta multiplies its first argument by pi relative to DLMF; at zero
this convention difference has no effect. Index 2 in its four-tuple is theta3.

The 96-bit guard gives 429 working bits at 100 requested decimal digits.
checks.py measures the minimum retained accuracy and compares against
explicitly bounded series, elliptic integrals, and a Gamma special value.
Only the requested 100 significant digits are serialized.
"""
import sys

import numberdb.sage as numberdb
from sage.rings.complex_arb import ComplexBallField

WORKING_GUARD = 96


class ThetaThreeSingularNomes(numberdb.Generator):
    table = 'T504'
    parameters = ('r',)
    type = 'R'
    digits = 100
    rigour = 'proven'

    def enumerate(self, maximum=12):
        for r in range(1, maximum + 1):
            yield {'r': str(r)}

    def value(self, params, digits):
        r = int(params['r'])
        if r <= 0:
            raise ValueError('r must be a positive integer')
        C = ComplexBallField(numberdb.bits(digits, losing=WORKING_GUARD))
        tau = C.gen(0) * C(r).sqrt()
        z = C(0).jacobi_theta(tau)[2]
        if not z.real().is_finite() or not z.imag().is_finite() or not z.imag().contains_zero():
            raise ArithmeticError('theta3 did not enclose a finite real value')
        value = z.real()
        if not value > 1:
            raise ArithmeticError('theta3 at a positive nome must exceed one')
        return value


if __name__ == '__main__':
    result = ThetaThreeSingularNomes().verify(sample=None)
    print(result)
    sys.exit(0 if result.ok else 1)
