"""Logarithmic capacity of regular polygons -- numberdb.org/T553.

Run with SageMath (or passagemath) and the numberdb package:
    sage -pip install numberdb
    sage -python generate.py                 # verify every stored entry
    sage -python generate.py --write-entries # send entries to this draft

Writing needs NUMBERDB_API_KEY. Reading an unpublished draft needs its author's
key too. --write-entries changes entries; it does not offer or publish a table.
Run the independent tests with: sage -python checks.py

The closed polygon has vertices exp(2*pi*i*j/n), hence circumradius one.
Solynin--Zalgaller (2004), Theorem 1, gives the capacity/area formula.
Gamma recurrence, reflection and duplication reduce it to
Gamma(1+1/n)/(Gamma(1-1/n)*Gamma(1+2/n)). All arguments start as exact rationals;
Arb carries their uncertainty through Gamma and division.

The default side counts 3,...,30 form a contiguous discrete geometric family;
30 is an editorial cutoff, justified in argument-selection.md. No Gamma
argument is sampled independently. The 128 guard bits are validated over every
entry in checks.py; the resulting certified bit accuracy is recorded in the
numerical evidence. Serialization is independently checked for containment.
"""

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

WORKING_GUARD = 128


class PolygonCapacity(numberdb.Generator):
    table = 'T553'
    parameters = ('n',)
    type = 'R'
    digits = 100
    rigour = 'proven'
    files = ('generate.py', 'checks.py', 'check.py', 'argument-selection.md')

    def enumerate(self, maximum=30):
        for n in range(3, maximum + 1):
            yield {'n': n}

    def value(self, params, digits):
        n = int(params['n'])
        if n < 3:
            raise ValueError('A polygon has at least three sides.')
        a = QQ(1) / QQ(n)
        field = RealBallField(numberdb.bits(digits, losing=WORKING_GUARD))
        v = field(1+a).gamma() / (field(1-a).gamma()*field(1+2*a).gamma())
        if not v.is_finite() or QQ(v.rad()) >= QQ(1) / QQ(10)**(digits+10):
            raise ArithmeticError('The capacity ball does not support the requested digits.')
        return v


if __name__ == '__main__':
    generator = PolygonCapacity()
    if '--write-entries' in sys.argv:
        print(generator.publish(message='Add certified circumradius-one polygon capacities.'))
    else:
        report = generator.verify(sample=None)
        print(report)
        sys.exit(0 if report.ok else 1)
