back to table · edit · history · where entries came from · files · download
3903 bytes, as of the version from 2026-11-02 13:17 (current). Recorded here, not run.
"""Values of the Brjuno function -- numberdb.org/T677.
Run with SageMath (install the numberdb Python package once):
sage -pip install numberdb
sage -python generate.py
The default command verifies every stored entry. Reading a private draft needs
NUMBERDB_API_KEY. This script neither creates nor offers nor publishes a table.
An authorized writer can use BrjunoValues().publish() to fill its existing draft.
The ordinary Gauss-map sum is evaluated by summing one exact quadratic cycle
and dividing by 1 minus its product. All logarithms and roots use Arb balls.
The 96 extra working bits are checked by checks.py against written last-place
intervals; they are not themselves an accuracy claim. See argument-selection.md
for the discriminant cutoff and checks.py for the independent convergent sum.
"""
import numberdb.sage as numberdb
from sage.rings.real_arb import RealBallField
from math import gcd, isqrt
DISCRIMINANT_BOUND = 100
WORKING_GUARD = 96
def triples(bound=DISCRIMINANT_BOUND):
"""Primitive A*t^2+B*t-K, with 0<x<1 and conjugate x'<-1."""
out = []
for A in range(1, isqrt(bound) + 1):
for B in range(1, isqrt(bound) + 1):
for K in range(1, bound // 4 + 1):
D = B*B + 4*A*K
if D > bound or isqrt(D)**2 == D:
continue
if gcd(gcd(A, B), K) != 1:
continue
if A+B-K > 0 and A-B-K < 0:
out.append((A, B, K))
return sorted(out, key=lambda t: (t[1]**2+4*t[0]*t[2], t))
def identity(t):
return 'quad_%d_%d_m%d' % t
def parse_identity(key):
import re
match = re.fullmatch(r'quad_(\d+)_(\d+)_m(\d+)', key)
if not match:
raise ValueError('Expected a primitive quadratic root identity')
return tuple(map(int, match.groups()))
def step(t):
A, B, K = t
D = B*B + 4*A*K
m = (B + isqrt(D)) // (2*K)
return (K, 2*m*K-B, A+B*m-K*m*m), m
def cycle(t):
orbit, digits, seen = [], [], set()
cur = t
while cur not in seen:
seen.add(cur)
orbit.append(cur)
cur, m = step(cur)
digits.append(m)
if cur != t:
raise ValueError('Argument has a preperiod; not part of this selection')
return orbit, digits
def root(t, field):
A, B, K = t
return field(2*K) / (field(B) + field(B*B+4*A*K).sqrt())
def brjuno(t, digits=100):
field = RealBallField(numberdb.bits(digits, losing=WORKING_GUARD))
product, total = field(1), field(0)
orbit, _ = cycle(t)
for cur in orbit:
x = root(cur, field)
total += product * (-x.log())
product *= x
result = total / (1-product)
if not result.is_finite() or not result > 0:
raise ArithmeticError('Brjuno enclosure is not finite and positive')
return result
class BrjunoValues(numberdb.Generator):
table = 'T677'
parameters = ('x',)
type = 'R'
digits = 100
rigour = 'proven'
def enumerate(self, discriminant_bound=DISCRIMINANT_BOUND):
for t in triples(discriminant_bound):
yield {'x': identity(t)}
def value(self, params, digits):
t = parse_identity(params['x'])
A, B, K = t
D = B*B+4*A*K
result = {'number': brjuno(t, digits),
'param-latex': r'$\frac{- %d+\sqrt{%d}}{%d}$' % (B,D,2*A)}
if t == (1,1,1):
result['comment'] = 'The argument is HREF{Golden_ratio#phi_inv}[the reciprocal of the golden ratio], with continued fraction $[0;\\overline{1}]$.'
elif t == (1,2,1):
result['comment'] = 'The argument is the reciprocal of HREF{Markov_quadratic_irrationals#1,1,2}[$1+\\sqrt2$], with continued fraction $[0;\\overline{2}]$.'
return result
if __name__ == '__main__':
import sys
report = BrjunoValues().verify(sample=None)
print(report)
sys.exit(0 if report.ok else 1)