back to table · edit · history · where entries came from · files · download
8744 bytes, as of the version from 2026-11-09 23:15 (current). Recorded here, not run.
"""Independent checks for inverse binomial sums -- numberdb.org/T698.
Run: sage -python checks.py
Set NUMBERDB_API_KEY to read the private draft and companion T697.
This script writes nothing to the website. It emits EVIDENCE_JSON for archiving.
The generator certifies values; the independent elementary-integral quadrature
at 150 and 200 digits is only a check. Companion decimal intervals and closed
forms are checked both before filling and on the values read from T698.
Instruction provenance: skill-manifest.json, archived at
agents/runs/20261109T224707Z-build-skills/manifest.json.
"""
import os,sys,json,hashlib,time,platform
from pathlib import Path
from math import factorial
from decimal import Decimal
import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.real_arb import RealBallField
from sage.rings.real_mpfi import RealIntervalField
from sage.rings.complex_arb import ComplexBallField
from sage.env import SAGE_VERSION
import mpmath as mp
from generate import InverseBinomial,evaluate,WORKING_GUARD_BITS,endpoint_workspace
from check import exactness,measure,names_its_rings
from numberdb._write import to_text
R=RealBallField(800)
I=RealIntervalField(800)
def decimal_rational(text):
d=Decimal(text)
e=int(d.as_tuple().exponent)
center=QQ(int(''.join(str(x) for x in d.as_tuple().digits))) * QQ(10)**e
if d.is_signed(): center=-center
return center,QQ(10)**e
def decimal_interval(text):
center,ulp=decimal_rational(text)
return I(center-ulp,center+ulp)
def rows(document):
# API documents here use ordered nested Numbers or the flat record schema.
block=document.get('Numbers',[])
names=list(document.get('Parameters',{}))
if isinstance(block,list):
return {tuple(str(e['params'][n]) for n in names):e['number'] for e in block}
out={}
def walk(node,keys):
if isinstance(node,dict) and 'number' in node:
out[tuple(keys)]=node['number']; return
if len(keys)==len(names) and isinstance(node,(str,int)):
out[tuple(keys)]=str(node); return
for k,v in node.items(): walk(v,keys+[str(k)])
if block: walk(block,[])
return out
def f2(u):
if u>=0: return 2*mp.asin(mp.sqrt(u)/2)**2
return -2*mp.asinh(mp.sqrt(-u)/2)**2
def integral(s,u,dps):
with mp.workdps(dps):
if s==2: return mp.nstr(f2(mp.mpf(u)),dps)
def f(y):
return 2*y**(2*s-5)*f2(mp.mpf(u)*mp.exp(-y*y))/mp.factorial(s-3)
return mp.nstr(mp.quad(f,[0,1,2,4,8,16,mp.inf]),dps)
def assert_overlap(a,b,label):
a,b=I(a),I(b)
assert not a.is_NaN() and not b.is_NaN(),label
assert I(a.absolute_diameter())<I('1e-88') and I(b.absolute_diameter())<I('1e-88'),label
assert a.overlaps(b),label
def closed_forms(values):
B=RealBallField(700); pi=B.pi()
for u in ['1','2','3','4']:
expected=2*(B(QQ(u)).sqrt()/2).arcsin()**2
assert_overlap(values[('2',u)],expected,('F2',u))
assert_overlap(values[('2','-1')],-2*(B(1)/2).arcsinh()**2,'F2(-1)')
assert_overlap(values[('3','-1')],-B(2)*B(3).zeta()/5,'Apery')
assert_overlap(values[('4','1')],B(17)*B(4).zeta()/36,'F4(1)')
C=ComplexBallField(700)
z=(C.gen(0)*C.pi()/3).exp()
assert_overlap(values[('3','1')],2*pi*z.polylog(2).imag()/3-B(4)*B(3).zeta()/3,'F3(1) Clausen')
assert_overlap(values[('5','1')],2*pi*z.polylog(4).imag()-B(19)*B(5).zeta()/3+B(2)*B(3).zeta()*B(2).zeta()/3,'F5(1) Clausen')
assert_overlap(values[('3','4')],pi**2*B(2).log()-B(7)*B(3).zeta()/2,'F3(4)')
return 10
def companion_checks(values,documents):
ls=rows(documents['T697']); zeta=rows(documents['T14']); cl=rows(documents['T175'])
angle={'1':'1/3','2':'1/2','3':'2/3','4':'1'}
count=0
for s in range(2,11):
for u,t in angle.items():
theta=I(R.pi()*R(QQ(t)))
logu=I(R(int(u)).log())
expected=I(0)
for i in range(s-1):
lsvalue=-theta**2/2 if i==0 else decimal_interval(ls[(str(i+2),'1',t)])
expected-=I((-2)**i)*logu**(s-2-i)*lsvalue/(factorial(i)*factorial(s-2-i))
assert_overlap(values[(str(s),u)],expected,('T697 triangular identity',s,u))
count+=1
assert_overlap(values[('3','-1')],-I(2)*decimal_interval(zeta[('3',)])/5,'stored zeta3')
assert_overlap(values[('4','1')],I(17)*decimal_interval(zeta[('4',)])/36,'stored zeta4')
assert_overlap(values[('3','1')],2*I(R.pi())*decimal_interval(cl[('2','1/3')])/3-I(4)*decimal_interval(zeta[('3',)])/3,'stored Clausen2')
assert_overlap(values[('5','1')],2*I(R.pi())*decimal_interval(cl[('4','1/3')])-I(19)*decimal_interval(zeta[('5',)])/3+I(2)*decimal_interval(zeta[('3',)])*decimal_interval(zeta[('2',)])/3,'stored Clausen4')
return count+4
def main():
if os.environ.get('NUMBERDB_KEY_FROM_STDIN')=='1':
os.environ['NUMBERDB_API_KEY']=sys.stdin.read().strip()
started=time.time()
# Nonzero known-answer and deliberately false controls precede numerical use.
with mp.workdps(150):
for s in [3,10]:
control=mp.quad(lambda y:2*y**(2*s-5)*mp.exp(-y*y)/mp.factorial(s-3),[0,1,2,4,8,16,mp.inf])
assert abs(control-1)<mp.mpf('1e-140')
assert abs(control-mp.mpf('1.01'))>mp.mpf('0.009')
print('Known-answer quadrature and wrong-answer controls passed.',flush=True)
generator=InverseBinomial(); params=list(generator.enumerate())
assert params==[{'s':str(s),'u':str(u)} for s in range(2,11) for u in [1,-1,2,3,4]]
assert not names_its_rings(Path(__file__).with_name('generate.py'))
values={}; records=[]; min_accuracy=10000
for p in params:
key=(p['s'],p['u'])
v=evaluate(*key,100); higher=evaluate(*key,140)
assert v.overlaps(higher)
min_accuracy=min(min_accuracy,int(v.accuracy()))
text=to_text(v,100)
interval=decimal_interval(text)
assert I(higher) in interval
if not records:
ulp=interval.absolute_diameter()/2
assert not interval.overlaps(I(higher)+10*I(ulp))
a=integral(int(p['s']),p['u'],150)
b=integral(int(p['s']),p['u'],200)
with mp.workdps(210):
discrepancy=abs(mp.mpf(a)-mp.mpf(b))
assert discrepancy < mp.mpf('1e-135')*max(1,abs(mp.mpf(b))),key
assert I(decimal_rational(b)[0]) in interval,key
values[key]=I(v)
records.append({'params':p,'number':text,'accuracy_bits':int(v.accuracy()),'integral_150':a,'integral_200':b,'integral_difference':str(discrepancy)})
print('ENTRY_JSON '+json.dumps(records[-1]),flush=True)
print('Checked',p,'accuracy',int(v.accuracy()),'elapsed',round(time.time()-started,1),flush=True)
assert not exactness({k:evaluate(*k) for k in values})
forms=closed_forms(values)
docs={tid:numberdb.table(tid) for tid in ['T697','T14','T175']}
companions=companion_checks(values,docs)
document=numberdb.table('T698'); stored=rows(document)
readback=0
if stored:
assert list(stored)==list(values)
read_values={key:decimal_interval(text) for key,text in stored.items()}
for record in records:
key=tuple(record['params'][n] for n in ['s','u'])
assert I(evaluate(*key,140)) in read_values[key],key
assert I(decimal_rational(record['integral_200'])[0]) in read_values[key],key
readback+=1
closed_forms(read_values)
companion_checks(read_values,docs)
report=generator.verify(sample=None)
assert report.ok,str(report)
print(report,flush=True)
manifest=json.loads(Path(__file__).with_name('skill-manifest.json').read_text())
evidence={'table':'T698','skill_manifest_path':'agents/runs/20261109T224707Z-build-skills/manifest.json','skill_manifest':manifest,
'versions':{'python':platform.python_version(),'sage':SAGE_VERSION,'numberdb':numberdb.__version__,'mpmath':mp.__version__},
'generator_sha256':hashlib.sha256(Path(__file__).with_name('generate.py').read_bytes()).hexdigest(),
'selection_count':len(records),'working_bits':numberdb.bits(100,losing=WORKING_GUARD_BITS),'endpoint_degree':endpoint_workspace(100)[1],
'minimum_accuracy_bits':min_accuracy,'size':measure({str(k):to_text(evaluate(*k),100) for k in values}),
'known_answer_controls':2,'wrong_answer_control':True,'ten_ulp_perturbation_rejected':True,
'closed_form_checks':forms,'companion_checks':companions,'stored_entries_checked':readback,'entries':records,'elapsed_seconds':time.time()-started}
print('EVIDENCE_JSON '+json.dumps(evidence,default=str),flush=True)
if __name__=='__main__': main()