back to table · edit · history · where entries came from · files · download
7183 bytes, as of the version from 2026-10-24 20:50 (current). Recorded here, not run.
"""Feynman periods of primitive log-divergent non-phi4 graphs -- numberdb.org/T466.
Run with SageMath after downloading the attached files into one directory:
sage -pip install numberdb
sage -python generate.py # verify every stored entry
sage -python checks.py # independent controls and graph checks
To fill this draft (this does not publish the table):
NUMBERDB_API_KEY=... sage -python generate.py --fill
The pinned Panzer--Schnetz v2 census is parsed without evaluating Maple code.
Only its 511 known periods are included, with every label retained. Rational
coefficients are Sage rationals; PARI zetamult uses the descending-index
convention directly (Sage Multizeta reverses it). Alternating terms use
polylogmult(s, [-1,1,...,1]). Values are recomputed at 150 and 200 decimal
working digits. Agreement is heuristic, never a certified graph integral.
The source's 100-digit values are independent numerical comparison targets.
"""
import numberdb.sage as numberdb
from sage.libs.pari import pari
from sage.rings.real_mpfr import RealField
from sage.rings.rational_field import QQ
import ast
import hashlib
import json
import os
import re
import sys
from functools import lru_cache
from pathlib import Path
from urllib.request import urlopen
from parse_census import parse, canonical
SOURCE_URL='https://arxiv.org/src/1603.04289v2/anc/PeriodsNonPhi4'
SOURCE_SHA256='f735c62370e0e1561e0cdffc28d86226d6d0fb0be138729abd44f74191d1966a'
WORKING_DIGITS=(150,200)
ROOT=Path(__file__).resolve().parent
@lru_cache(None)
def records():
local=ROOT/'PeriodsNonPhi4'
raw=local.read_bytes() if local.exists() else urlopen(SOURCE_URL,timeout=60).read()
assert hashlib.sha256(raw).hexdigest()==SOURCE_SHA256,'Source checksum changed'
return parse(raw.decode('utf-8'))
@lru_cache(None)
def field(digits):
return RealField(numberdb.bits(digits,losing=32))
@lru_cache(None)
def zeta(s, alternating, digits):
R=field(digits)
assert all(isinstance(n,int) and n>0 for n in s)
if alternating:
return R(pari.polylogmult(list(s),[-1]+[1]*(len(s)-1),precision=R.precision()))
assert s[0]>=2
return R(pari.zetamult(list(s),precision=R.precision()))
@lru_cache(None)
def expression_tree(expression):
return ast.parse(expression.replace('^','**'), mode='eval').body
def evaluate_node(node,digits):
if isinstance(node,ast.Constant) and type(node.value) is int:
return QQ(node.value)
if isinstance(node,ast.Name) and node.id=='Pi':
return field(digits).pi()
if isinstance(node,ast.UnaryOp) and isinstance(node.op,(ast.UAdd,ast.USub)):
a=evaluate_node(node.operand,digits)
return -a if isinstance(node.op,ast.USub) else a
if isinstance(node,ast.BinOp):
a,b=evaluate_node(node.left,digits),evaluate_node(node.right,digits)
if isinstance(node.op,ast.Add): return a+b
if isinstance(node.op,ast.Sub): return a-b
if isinstance(node.op,ast.Mult): return a*b
if isinstance(node.op,ast.Div): return a/b
if isinstance(node.op,ast.Pow):
assert b in QQ and b.denominator()==1
return a**int(b)
if isinstance(node,ast.Subscript) and isinstance(node.value,ast.Name) and node.value.id=='zeta':
args=ast.literal_eval(node.slice)
if not isinstance(args,tuple): args=(args,)
alternating=isinstance(args[0],list)
if alternating:
assert args[0][0]==-1 and len(args[0])==2
args=(args[0][1],)+args[1:]
return zeta(tuple(args),alternating,digits)
raise ValueError('Unexpected expression syntax: '+ast.dump(node))
@lru_cache(None)
def compute(expression,digits):
value=field(digits)(evaluate_node(expression_tree(expression),digits))
assert not value.is_NaN() and not value.is_infinity() and value>0
return value
@lru_cache(None)
def comparison(expression):
a,b=(compute(expression,d) for d in WORKING_DIGITS)
R=field(200)
relative=abs(R(a)-b)/abs(b)
agreed=999 if relative==0 else float(-relative.log10())
assert agreed>125,('insufficient agreement',agreed,expression)
return agreed
@lru_cache(None)
def aliases():
seen={}; out={}
for key,row in records().items():
ex=row['expression']
if ex=='FAIL': continue
ex=canonical(ex)
if ex in seen: out[key]=seen[ex]
else: seen[ex]=key
return out
@lru_cache(None)
def wheel_labels():
out={}
for key,row in records().items():
if row['expression']=='FAIL': continue
infinity=max(v for e in row['edges'] for v in e['vertices'])
es=[e['vertices'] for e in row['edges'] if infinity not in e['vertices']]
degree={v:sum(v in e for e in es) for v in range(infinity)}
n=row['loops']
hubs=[v for v,d in degree.items() if d==n]
if len(hubs)!=1 or any(d!=3 for v,d in degree.items() if v!=hubs[0]): continue
hub=hubs[0]; rim=[e for e in es if hub not in e]
visited={next(v for v in degree if v!=hub)}
while True:
new=visited|{v for e in rim if any(w in visited for w in e) for v in e}
if new==visited: break
visited=new
if len(visited)==n: out[key]=n
return out
class NonPhi4Periods(numberdb.Generator):
table='T466'
parameters=('loops','index')
type='R'
digits=100
rigour='heuristic (agreement-checked)'
files=('generate.py','parse_census.py','checks.py','check.py','PeriodsNonPhi4','cross-equalities.json','cross-equality-proofs.json','cross-source-values.json')
def enumerate(self):
for row in records().values():
if row['expression']!='FAIL':
yield {'loops':row['loops'],'index':row['index']}
def value(self,params,digits):
key=f"{params['loops']},{params['index']}"
row=records()[key]; ex=row['expression']
comparison(ex)
value=numberdb.agreeing(lambda d:compute(ex,d),at=WORKING_DIGITS)
result={'number':value}
if key in aliases(): result['equals']=f'HREF{{T466#{aliases()[key]}}}'
# Cross-table equalities are supported by exact source expressions.
cross_path=ROOT/'cross-equalities.json'
if cross_path.exists():
cross=json.loads(cross_path.read_text())
if key in cross: result['equals']=cross[key]
if key in wheel_labels():
n=wheel_labels()[key]
result['comment']=f'The wheel with {n} spokes has period $\\binom{{{2*n-2}}}{{{n-1}}}\\zeta({2*n-3})$.'
if key=='8,39':
result['comment']=r'This period contains alternating multiple polylogarithms CITE{PS}, equation (5.6).'
return result
if __name__=='__main__':
if os.environ.get('NUMBERDB_KEY_FROM_STDIN'):
numberdb.configure(api_key=sys.stdin.read().strip())
generator=NonPhi4Periods()
if '--fill' in sys.argv or os.environ.get('NUMBERDB_PUBLISH')=='1':
print(generator.publish(message='Recompute 511 non-phi4 census periods at two precisions'))
else:
report=generator.verify(sample=None)
print(report)
sys.exit(0 if report.ok else 1)