generate.py

back to table · edit · history · where entries came from · files · download

3038 bytes, as of the version from 2026-10-27 17:40 (current). Recorded here, not run.

"""Interior conformal radius of regular Euclidean and ideal hyperbolic polygons -- numberdb.org/T554.

Run with SageMath and the numberdb client:
    sage -pip install numberdb
    sage -python generate.py                 # verify every stored entry
    sage -python generate.py --fill          # fill the existing draft

--fill requires NUMBERDB_API_KEY and writes entries, not publication status.
The campaign wrapper may supply the key on stdin with NUMBERDB_KEY_FROM_STDIN=1
and select filling with NUMBERDB_PUBLISH=1. Publication and review are separate.

The unit circle contains the vertices exp(2*pi*i*j/n). Euclidean sides are
chords; ideal-hyperbolic sides are orthogonal circular arcs. All radii are
f'(0)>0 for the disk-to-domain conformal bijection fixing zero.

The 128-bit guard gives 461 working bits at 100 digits. Its measured retained
accuracy and serialization checks are recorded in numerical-evidence.json.
Exact rational arguments are converted to Arb balls before Gamma evaluation.
The ordered selection and its justification are 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 = 128
GEOMETRIES = ('euclidean', 'ideal-hyperbolic')
MAX_SIDES = 30

class InteriorConformalRadius(numberdb.Generator):
    table = 'T554'
    parameters = ('geometry', 'n')
    type = 'R'
    digits = 100
    rigour = 'proven'

    def enumerate(self, max_sides=MAX_SIDES):
        for geometry in GEOMETRIES:
            for n in range(3, max_sides + 1):
                yield {'geometry': geometry, 'n': n}

    def value(self, params, digits):
        n = int(params['n'])
        geometry = params['geometry']
        if n < 3 or geometry not in GEOMETRIES:
            raise ValueError('Expected a supported geometry and n >= 3')
        R = RealBallField(numberdb.bits(digits, losing=WORKING_GUARD))
        a = QQ(1) / n
        if geometry == 'euclidean':
            value = R(1-a).gamma() / (R(1+a).gamma() * R(1-2*a).gamma())
        else:
            half = QQ(1) / 2
            value = (R(1-a).gamma() * R(half+a).gamma()
                     / (R(1+a).gamma() * R(half-a).gamma()))
        if not value.is_finite() or value <= 0 or value >= 1:
            raise ArithmeticError('Radius is not a finite ball strictly between 0 and 1')
        return value

if __name__ == '__main__':
    if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
        key = sys.stdin.read().strip()
        if '=' in key:
            key = key.split('=', 1)[1].strip().strip('\"\'')
        numberdb.configure(api_key=key)
    generator = InteriorConformalRadius()
    if '--fill' in sys.argv or os.environ.get('NUMBERDB_PUBLISH') == '1':
        outcome = generator.publish(message='Fill both regular-polygon radius families with certified 100-digit values')
        print(outcome)
    else:
        report = generator.verify(sample=None)
        print(report)
        sys.exit(0 if report.ok else 1)