back to table · edit · history · where entries came from · files · download
4784 bytes, as of the version from 2026-11-09 23:15 (current). Recorded here, not run.
"""Inverse binomial sums -- numberdb.org/T698.
Run with SageMath or passagemath-symbolics:
sage -pip install numberdb mpmath
sage -python generate.py # verify all stored entries
sage -python generate.py --submit # fill this draft, API key required
sage -python checks.py # independent checks; read-only
F_s(u) = sum_{j>=1} u^j/(j^s binomial(2*j,j)).
Default selection: s=2,...,10; u=1,-1,2,3,4, in that order for each s.
For |u|<4, Arb sums the defining series and encloses a geometric tail.
At u=4, the log-sine integral is integrated by a convergent power series
with a positive-coefficient majorant. certification.md derives both bounds.
The endpoint algorithm adapts the Euler-product method independently inspected
in T697's attached generate.py, SHA256
531d1e432c82defc5d84670740b0bc4c1b8cb5168fe647621ec7cb3e77c34391.
This file contains the complete numerical algorithm; it imports no companion
source and reads no precomputed values when producing an entry.
Instruction provenance: skill-manifest.json, archived at
agents/runs/20261109T224707Z-build-skills/manifest.json. Both archived skills:
886390324dd1971e381a43cf3b46b822ab0bc67d62f31d8481e29ec79556746b.
"""
import os
import sys
from functools import lru_cache
from math import comb, factorial
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.real_arb import RealBallField
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
MAX_ORDER = 10
ARGUMENTS = ('1', '-1', '2', '3', '4')
WORKING_GUARD_BITS = 192
TAIL_GUARD_DIGITS = 60
@lru_cache(maxsize=8)
def endpoint_workspace(digits):
R = RealBallField(numberdb.bits(digits, losing=WORKING_GUARD_BITS))
P = PolynomialRing(R, 'x')
N = numberdb.bits(digits + TAIL_GUARD_DIGITS, losing=0)
A = (R(2)/R.pi()).log()
h = P([R(0)] + [R(2*m).zeta()/(R(m)*R(4)**m) for m in range(1,N+1)])
powers = [P.one()]
for j in range(1,MAX_ORDER-1):
powers.append((powers[-1]*h).truncate(N+1))
J = [[R(1)/(2*m+2) for m in range(N+1)]]
for d in range(1,MAX_ORDER-1):
J.append([(A**d+d*J[-1][m])/(2*m+2) for m in range(N+1)])
return R,N,A,powers,J
def endpoint(s,digits):
R,N,A,powers,J = endpoint_workspace(digits)
p = s-2
total = sum((comb(p,j)*sum((c*J[p-j][m] for m,c in enumerate(powers[j].list())),R(0))
for j in range(p+1)),R(0))
C = 2*R(2).log()
error = R(0)
for j in range(1,p+1):
d = p-j
moment = sum((R(comb(d,l)*factorial(l))*abs(A)**(d-l)/R(2)**(l+1)
for l in range(d+1)),R(0))
error += comb(p,j)*C**j*R(2)**(-N-1)*moment
factor = R(2)**p*R.pi()**2/factorial(p)
return (factor*total).add_error((factor*error).upper())
def direct_series(s,u,digits):
R = RealBallField(numberdb.bits(digits, losing=WORKING_GUARD_BITS))
u = QQ(u)
if u == 0:
return QQ(0)
assert abs(u)<4
r = R(abs(u))/4
target = R(10)**(-digits-TAIL_GUARD_DIGITS)
b = R(u)/2
total = R(0)
j = 1
while True:
term = b/R(j)**s
total += term
tail = abs(term)*r/(1-r)
if tail < target:
return total.add_error(tail.upper())
b *= R(u)*(j+1)/(2*(2*j+1))
j += 1
def evaluate(s,u,digits=100):
s,u=int(s),QQ(u)
assert 2<=s<=MAX_ORDER and -4<u<=4
answer=endpoint(s,digits) if u==4 else direct_series(s,u,digits)
if u:
assert answer.is_finite()
assert answer.accuracy() >= numberdb.bits(digits+20,losing=0)
return answer
class InverseBinomial(numberdb.Generator):
table='T698'
parameters=('s','u')
type='R'
digits=100
rigour='proven'
files=('generate.py','checks.py','check.py','argument-selection.md','certification.md',
'skill-manifest.json','numerical-evidence.json')
def enumerate(self):
for s in range(2,MAX_ORDER+1):
for u in ARGUMENTS:
yield {'s':str(s),'u':u}
def value(self,params,digits):
value=evaluate(params['s'],params['u'],digits)
if params=={'s':'3','u':'-1'}:
return {'number':value,'comment':r'This is $-2\zeta(3)/5$, the negative of the usual positive Apéry sum CITE{BBK}.'}
return value
if __name__=='__main__':
if os.environ.get('NUMBERDB_KEY_FROM_STDIN')=='1':
os.environ['NUMBERDB_API_KEY']=sys.stdin.read().strip()
generator=InverseBinomial()
if '--submit' in sys.argv or os.environ.get('NUMBERDB_PUBLISH')=='1':
print(generator.publish(message='Certified inverse binomial sums with series tails and independent integral checks.'))
else:
report=generator.verify(sample=None)
print(report)
sys.exit(0 if report.ok else 1)