"""Expected convex-hull vertex counts -- numberdb.org/T471.

Run with SageMath (or passagemath with Arb):
    sage -pip install numberdb
    sage -python generate_t471_repaired.py

The default action verifies every stored entry and writes nothing. A private
NumberDB draft requires its author's API key through the normal numberdb
configuration. NUMBERDB_KEY_FROM_STDIN=1 also reads that key from stdin.

This is the repaired table's displayed computation for triangles,
parallelograms and filled ellipses, with an exact one-point case. The stored
selection is every integer n from 4 through 20; these are the first
nontrivial planar hulls in a common finite-sample range. Polygon values
are exact rationals. Ellipse values use certified Arb integration at 100
significant digits with 80 guard bits, with finite narrow balls required.
The repair does not change or add stored numerical values.
"""
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 = 80


def triangle_vertices(n):
    if n == 1:
        return QQ(1)
    return 2 * sum(QQ(1) / k for k in range(1, n))


def parallelogram_vertices(n):
    if n == 1:
        return QQ(1)
    s = sum((1 - QQ(1) / 2**k) / k for k in range(1, n + 1))
    return QQ(8) / 3 * (s - QQ(1) / (n * 2**n))


def ellipse_vertices(n, digits=100):
    if n == 1:
        return QQ(1)
    C = ComplexBallField(numberdb.bits(digits, losing=WORKING_GUARD))
    pi = C.pi()

    def integrand(u, analytic):
        t = pi * u
        return t.sin()**4 * (u - t.sin() * t.cos() / pi)**(n - 2)

    result = (C(8*n*(n-1)) / 3 * C.integral(integrand, 0, 1)).real()
    assert result.is_finite()
    R = result.parent()
    assert R(result.rad()) < R(10)**(-digits-10)
    return result


class HullVertices(numberdb.Generator):
    table = 'T471'
    parameters = ('region', 'n')
    type = 'R'
    digits = 100
    rigour = 'proven'

    def enumerate(self):
        for region in ('equilateral-triangle', 'unit-square', 'unit-disk'):
            for n in range(4, 21):
                yield {'region': region, 'n': str(n)}

    def value(self, params, digits):
        n = int(params['n'])
        region = params['region']
        if region == 'equilateral-triangle':
            return triangle_vertices(n)
        if region == 'unit-square':
            return parallelogram_vertices(n)
        if region == 'unit-disk':
            return ellipse_vertices(n, digits)
        raise ValueError('Unknown affine class: ' + region)


if __name__ == '__main__':
    if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
        numberdb.configure(api_key=sys.stdin.read().strip())
    report = HullVertices().verify(sample=None)
    print(report)
    sys.exit(0 if report.ok else 1)
