generate.py

back to table · edit · history · where entries came from · files · download

2895 bytes, as of the version from 2026-10-25 18:59 (current). Recorded here, not run.

"""Lebesgue constants of the Fourier partial sums -- numberdb.org/T499.

Run with SageMath (or passagemath with the numberdb package):

    sage -pip install numberdb
    sage -python generate.py               # verify all stored entries
    sage -python checks.py                 # independent, offline checks

This generator computes the Fourier Lebesgue constants for 0 <= n <= 100.
It uses the finite sum
    L_n = 1/(2*n+1) + (2/pi)*sum(tan(pi*k/(2*n+1))/k, k=1..n),
with real ball arithmetic. L_0 = 1 is returned exactly because D_0(t)=1.
The parameter n is the maximum Fourier frequency, not the number 2*n+1
of complex Fourier modes. The integral convention is
    L_n = (1/pi)*integral_0^pi |1+2*sum(cos(k*t), k=1..n)| dt.

The 96 guard bits supplement the bits needed for 100 significant digits.
checks.py records the worst retained precision, recomputes with 160 extra
bits, and evaluates the signed integral using a separate sine antiderivative.
The supported digits are enforced again by NumberDB's serializer.
The range is the consecutive first 101 degrees, including the mean projection
and the classical small-degree examples. It makes no claim of completeness.

No command in this file writes to the website. A contributor can explicitly
call LebesgueFourier().publish() to fill the draft after reviewing the checks;
that client method sends entries and does not publish the website draft.
An API key is needed to read the table while it remains a private draft.
"""
import sys
import numberdb.sage as numberdb
from sage.rings.integer_ring import ZZ
from sage.rings.real_arb import RealBallField

MAX_DEGREE = 100
WORKING_GUARD = 96


def lebesgue_fourier(n, digits=100, extra_bits=0):
    """Return a rigorous ball, or the exact integer L_0."""
    n = ZZ(n)
    if n < 0:
        raise ValueError('Fourier degree must be nonnegative')
    if n == 0:
        return ZZ(1)
    field = RealBallField(numberdb.bits(digits, losing=WORKING_GUARD + extra_bits))
    pi = field.pi()
    m = 2*n+1
    total = field(0)
    for k in range(1, int(n)+1):
        total += (pi*k/m).tan()/k
    return field(1)/m + 2*total/pi


class LebesgueFourier(numberdb.Generator):
    table = 'T499'
    files = ('generate.py', 'checks.py', 'check.py', 'b226654.txt',
             'b226655.txt', 'b226656.txt', 'validation.json', 'evidence.md')
    parameters = ('n',)
    type = 'R'
    digits = 100
    rigour = 'proven'

    def enumerate(self, maximum=MAX_DEGREE):
        for n in range(maximum + 1):
            yield {'n': n}

    def value(self, params, digits):
        n = ZZ(params['n'])
        value = lebesgue_fourier(n, digits)
        if n == 0:
            return {'number': value, 'comment': '$D_0(t)=1$, so $L_0=1$ exactly.'}
        return value


if __name__ == '__main__':
    report = LebesgueFourier().verify(sample=None)
    print(report)
    sys.exit(0 if report.ok else 1)