"""Dedekind eta values at rectangular CM points -- numberdb.org/T506.

Run with SageMath (or passagemath with the required ball fields):
    sage -pip install numberdb
    sage -python generate.py                 # compare every stored entry
    sage -python checks.py                   # independent checks, no writes
    sage -python generate.py --fill-draft    # fill T506, API key required

The fill command writes entries and attached sources, never publishes or offers
this draft for review. Supply NUMBERDB_API_KEY in the environment, or pipe a
key on stdin with NUMBERDB_KEY_FROM_STDIN=1. The campaign wrapper also accepts
NUMBERDB_PUBLISH=1 for the entry-writing operation.

The parameter is every positive integer r, with initial range 1 through 12.
It specifies tau=i*sqrt(r), with the positive square root, without removing
square factors. Arb's modular_eta returns Dedekind's full eta value. Its real
part is positive by the infinite product at this purely imaginary argument.

A 96-bit guard gives 429 working bits at 100 requested digits. checks.py
measures retained accuracy and proves that each resulting ball is contained
in the exact interval denoted by its serialized 100-significant-digit decimal.
The independent product and theta series use explicit omitted-tail bounds.
"""
import os
import sys
import numberdb.sage as numberdb
from sage.rings.complex_arb import ComplexBallField
from sage.rings.real_arb import RealBallField

WORKING_GUARD = 96


class DedekindEtaCM(numberdb.Generator):
    table = 'T506'
    parameters = ('r',)
    type = 'R'
    digits = 100
    rigour = 'proven'
    files = ('generate.py', 'checks.py', 'check.py')

    def enumerate(self):
        for r in range(1, 13):
            yield {'r': r}

    def value(self, params, digits):
        r = int(params['r'])
        if r < 1:
            raise ValueError('r must be a positive integer')
        bits = numberdb.bits(digits, losing=WORKING_GUARD)
        R = RealBallField(bits)
        C = ComplexBallField(bits)
        eta = C(0, R(r).sqrt()).modular_eta()
        assert eta.real().is_finite() and eta.imag().is_finite() and eta.imag().contains_zero()
        value = eta.real()
        assert value > 0 and value.accuracy() >= numberdb.bits(digits, losing=0)
        if r == 1:
            return {'number': value,
                    'comment': 'The square lattice point $\\tau_1=i$. Its Gamma expression is CITE{formula-square}.'}
        return value


def configure_from_stdin():
    if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
        numberdb.configure(api_key=sys.stdin.read().strip())


if __name__ == '__main__':
    configure_from_stdin()
    generator = DedekindEtaCM()
    if '--fill-draft' in sys.argv or os.environ.get('NUMBERDB_PUBLISH') == '1':
        print(generator.publish(message='Fill twelve CM eta values with certified 100-digit enclosures'))
    else:
        report = generator.verify(sample=None)
        print(report)
        sys.exit(0 if report.ok else 1)
