generate.py

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

3981 bytes, as of the version from 2026-10-30 04:30 (current). Recorded here, not run.

"""Central pressure constants of Lane–Emden polytropes -- numberdb.org/T617.

Run with SageMath (install numberdb once with sage -pip install numberdb):
    sage -python generate.py           # recompute and verify every stored row
    sage -python generate.py --fill    # fill this existing draft
Download the attached solver.py and files named in `files` beside this script.
Draft access and writes use NUMBERDB_API_KEY. The campaign wrapper also
supports NUMBERDB_KEY_FROM_STDIN=1 and NUMBERDB_PUBLISH=1. Filling entries
neither offers the draft nor reviews or makes it public.

W_n=P_c R^4/(G M^2)=xi_1^4/(4*pi*(n+1)*mu_n^2).
The analytic cases are 3/(8*pi) and pi/8, evaluated with Arb balls.
Every other value freshly integrates the normalized positive Lane–Emden
solution. The attached solver was obtained from the website's T614 attachment.
Central-series initialization and Taylor continuation in t=sqrt(theta) avoid
fractional powers at the surface. Runs at 150/210 decimal digits use orders
160/210, step caps 1/12 and 1/18, and starting radii 1/2 and 2/3.
ODE truncation, propagation and endpoint errors are not rigorously bounded;
confidence is heuristic (agreement-checked), not proven. See numerical-evidence
for measured agreement and independent checks. No stored numerical input file
is used by value(). The solver supports the selected half-integer family;
it does not implement arbitrary rational indices from the mathematical domain.
"""
import os
import sys
from functools import lru_cache
import numberdb.sage as numberdb
from sage.rings.real_arb import RealBallField
from sage.rings.rational_field import QQ
from solver import radius

INDICES=('0','1/2','1','3/2','2','5/2','3','7/2','4','9/2')
CONFIG={150:(160,12,'1/2'),210:(210,18,'2/3')}

@lru_cache(maxsize=24)
def background(n,working):
    order,divisor,start=CONFIG[working]
    return radius(n,working,order,divisor,start,trace=True)

def pressure(n,working):
    x,q,meta=background(n,working)
    F=x.parent()
    return x**4/(4*F.pi()*(F(QQ(n))+1)*q**2)

class LaneEmdenPressure(numberdb.Generator):
    table='T617'
    parameters=('n',)
    type='R'
    digits=100
    rigour='heuristic (agreement-checked)'
    files=('generate.py','solver.py','compute.py','independent_checks.py',
           'radial_check.py','readback_checks.py','argument-selection.md',
           'numerical-evidence.json','independent-evidence.json',
           'skill-manifest.json','source-manifest.json')

    def enumerate(self):
        for n in INDICES:
            yield {'n':n}

    def value(self,params,digits):
        n=str(QQ(params['n']))
        if n not in INDICES:
            raise ValueError('Use a selected integer or half-integer in [0,9/2].')
        if digits>100:
            raise ValueError('This precision policy was validated for at most 100 digits.')
        B=RealBallField(numberdb.bits(digits,losing=80))
        if n=='0':
            return {'number':B(3)/(8*B.pi()),'comment':r'The incompressible profile $\theta_0(\xi)=1-\xi^2/6$ gives $W_0=3/(8\pi)$.'}
        if n=='1':
            return {'number':B.pi()/8,'comment':r'The linear profile $\theta_1(\xi)=\sin(\xi)/\xi$ gives $W_1=$ HREF{Rational_multiples_of_pi#1/8}[$\pi/8$].'}
        return numberdb.agreeing(lambda working:str(pressure(n,working)),at=(150,210))

if __name__=='__main__':
    if os.environ.get('NUMBERDB_KEY_FROM_STDIN')=='1':
        token=sys.stdin.read().strip()
        if '=' in token and token.split('=',1)[0].replace('_','').isalnum():
            token=token.split('=',1)[1].strip().strip('\"\'')
        os.environ['NUMBERDB_API_KEY']=token
    g=LaneEmdenPressure()
    if '--fill' in sys.argv or os.environ.get('NUMBERDB_PUBLISH')=='1':
        for params in g.enumerate():g.value(params,g.digits)
        print(g.publish(message='Add ten checked central pressure constants and reproducible sources.'))
    else:
        report=g.verify(sample=None);print(report);sys.exit(0 if report.ok else 1)