back to table · edit · history · where entries came from · files · download
4403 bytes, as of the version from 2026-10-30 02:01 (current). Recorded here, not run.
"""Mass constants of Lane–Emden polytropes -- numberdb.org/T614.
Run with SageMath (install numberdb once with sage -pip install numberdb):
sage -python generate.py # recompute and verify all stored rows
sage -python generate.py --fill # fill this existing draft
Download solver.py and the other files listed in `files` beside this script.
Use NUMBERDB_API_KEY for draft reads and entry writes. The campaign wrapper
supports NUMBERDB_KEY_FROM_STDIN=1 and NUMBERDB_PUBLISH=1 instead of --fill.
These commands neither offer the draft nor review or publish it.
mu_n = integral_0^xi_1 xi^2 theta_n^n dxi = -xi_1^2 theta_n'(xi_1).
At n=5 the upper limit is infinity. Its mass sqrt(3), the incompressible
mass 2 sqrt(6), and the linear mass pi are evaluated with Arb balls.
Other rows use central-series initialization and Taylor continuation in
sqrt(theta) using the attached solver originally obtained from T613.
We recompute the mass component, with 150 and 210 working decimal digits,
orders 160/210, step caps 1/12 and 1/18, and starting radii 1/2 and 2/3.
Truncation, propagation and endpoint errors are not rigorously bounded;
the table's level is heuristic (agreement-checked), not proven.
The numerical evidence records independent radial-coordinate integration,
a virial integral check, analytic controls and software versions.
The default eleven indices and their three distinct roles are justified in
argument-selection.md. This solver supports integer/half-integer models,
not arbitrary rational n, even though the mathematical quantity is defined
for those indices too. There is no file of precomputed values used by value().
"""
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','5')
CONFIG = {150:(160,12,'1/2'), 210:(210,18,'2/3')}
@lru_cache(maxsize=32)
def compute(n, working):
order, divisor, start = CONFIG[working]
return str(radius(n,working,order,divisor,start,trace=True)[1])
class LaneEmdenMass(numberdb.Generator):
table = 'T614'
parameters = ('n',)
type = 'R'
digits = 100
rigour = 'heuristic (agreement-checked)'
files = ('generate.py','solver.py','compute.py','argument-selection.md',
'numerical-evidence.json','independent_checks.py','independent-evidence.json',
'readback_checks.py','skills-evidence.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 index in [0,5].')
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':2*B(6).sqrt(), 'comment':r'The incompressible profile $\theta_0(\xi)=1-\xi^2/6$ gives $\mu_0=2\sqrt6$.'}
if n == '1':
return {'number':B.pi(), 'comment':r'The linear profile $\theta_1(\xi)=\sin(\xi)/\xi$ gives $\mu_1=$ HREF{Pi}[$\pi$].'}
if n == '5':
return {'number':B(3).sqrt(), 'comment':r'The profile $\theta_5(\xi)=(1+\xi^2/3)^{-1/2}$ has infinite radius and finite mass $\mu_5=\sqrt3$.'}
return numberdb.agreeing(lambda working:compute(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
generator = LaneEmdenMass()
if '--fill' in sys.argv or os.environ.get('NUMBERDB_PUBLISH') == '1':
# Compute everything before opening the writer, so the entries arrive together.
for params in generator.enumerate():
generator.value(params,generator.digits)
print(generator.publish(message='Add eleven checked Lane-Emden mass constants and reproducible sources.'))
else:
report = generator.verify(sample=None)
print(report)
sys.exit(0 if report.ok else 1)