generate.py

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

3221 bytes, as of the version from 2026-10-27 19:33. Recorded here, not run.

"""Umemura polynomials for Painlevé III -- numberdb.org/T558.

Run with SageMath (install numberdb once with sage -pip install numberdb):
    sage -python generate.py              # verify the stored table
    sage -python generate.py --fill       # fill the existing draft
    sage -python checks.py                # independent exact checks
Authenticated draft reads and writes require NUMBERDB_API_KEY. The campaign
wrapper can supply the key on stdin with NUMBERDB_KEY_FROM_STDIN=1, and request
filling with NUMBERDB_PUBLISH=1. Filling entries does not publish the table.

Clarkson, Law and Lin, SIGMA 19 (2023), 080, equation (1.5), with
S_{-1}=S_0=1. Both x and mu are indeterminates; only n indexes the table.
Division is explicit monic polynomial long division over ZZ[x,mu].
See argument-selection.md for the measured finite extent.
"""
import os
import sys
import numberdb.sage as numberdb
from sage.rings.integer_ring import ZZ
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing

R = PolynomialRing(ZZ, names=('x', 'mu'), order='lex')
x, mu = R.gens()
MAX_N = 5
_POLYS = [R.one(), x + mu]


def monic_quotient(numerator, denominator):
    """Exact division in x; a nonzero remainder is a hard failure."""
    degree = denominator.degree(x)
    assert denominator.coefficient({x: degree}) == 1
    quotient = R.zero()
    remainder = numerator
    while remainder and remainder.degree(x) >= degree:
        top = remainder.degree(x)
        term = remainder.coefficient({x: top}) * x**(top - degree)
        quotient += term
        remainder -= term * denominator
    assert remainder == 0, 'Nonzero recurrence remainder'
    return quotient


def polynomial(n):
    n = int(n)
    if n < 0:
        raise ValueError('n must be nonnegative')
    while len(_POLYS) <= n:
        previous, current = _POLYS[-2:]
        derivative = current.derivative(x)
        numerator = ((x + mu)*current**2
                     - x*(current*derivative.derivative(x) - derivative**2)
                     - current*derivative)
        _POLYS.append(monic_quotient(numerator, previous))
    return _POLYS[n]


class Umemura(numberdb.Generator):
    table = 'T558'
    parameters = ('n',)
    type = 'Z[]'
    rigour = 'exact'
    digits = 100  # Exact polynomial coefficients are never rounded.
    files = ('generate.py', 'checks.py', 'check.py', 'argument-selection.md')

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

    def value(self, params, digits):
        return polynomial(params['n'])


if __name__ == '__main__':
    if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
        key = sys.stdin.read().strip()
        if '=' in key and key.split('=', 1)[0].replace('_', '').isupper():
            key = key.split('=', 1)[1].strip().strip('\"\'')
        os.environ['NUMBERDB_API_KEY'] = key
    generator = Umemura()
    if '--fill' in sys.argv or os.environ.get('NUMBERDB_PUBLISH') == '1':
        print(generator.publish(message='Fill exact monic Umemura polynomials after determinant and Bessel checks.'))
    else:
        report = generator.verify(sample=None)
        print(report)
        sys.exit(0 if report.ok else 1)