barnes.py

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

7245 bytes, as of the version from 2026-10-26 16:08 (current). Recorded here, not run.

"""Reproduce T93 at 200 digits without endorsing its inherited argument range.

    python -m pip install numberdb python-flint==0.6.0 mpmath==1.3.0
    python generate.py
    python checks.py --live

The rational enumeration is preserved for a numerical correction only. The
relevance of its numerator, denominator and shift bounds remains unresolved.
"""

import argparse
import copy
import json
import math
from contextlib import contextmanager
from decimal import Decimal
from fractions import Fraction

import mpmath as mp
import numberdb
from flint import acb, ctx
from numberdb._write import to_text


@contextmanager
def precision(digits):
    previous = ctx.prec
    ctx.prec = numberdb.bits(digits, losing=160)
    try:
        yield
    finally:
        ctx.prec = previous


def endpoint(value):
    mantissa, exponent = value.man_exp()
    return Fraction(int(mantissa)) * Fraction(2) ** int(exponent)


def evaluate(identity):
    argument = Fraction(identity)
    if argument.denominator == 1 and argument > 0:
        return math.prod(math.factorial(index) for index in range(argument.numerator - 1))
    value = acb(str(argument)).barnes_g()
    if not value.is_finite() or not value.imag.contains(0):
        raise ArithmeticError("nonfinite or non-real Barnes G")
    return value.real


def bounds(text):
    midpoint = Fraction(text)
    if "." not in text and "e" not in text.lower():
        return midpoint, midpoint, Fraction(0)
    unit = Fraction(10) ** Decimal(text).as_tuple().exponent
    return midpoint - unit, midpoint + unit, unit


class BarnesValues(numberdb.Generator):
    table = "T93"
    parameters = ("s",)
    type = "R"
    digits = 200
    rigour = "proven"
    files = ("generate.py", "barnes.py", "checks.py", "checks-evidence.json", "selection.md")

    def enumerate(self):
        for denominator in range(1, 31):
            for numerator in range(-30, 31):
                if math.gcd(numerator, denominator) != 1 or (denominator == 1 and numerator <= 0):
                    continue
                yield {"s": str(Fraction(numerator, denominator))}

    def value(self, params, digits):
        with precision(digits):
            value = evaluate(params["s"])
            if isinstance(value, int):
                return value
            if value.rel_accuracy_bits() < numberdb.bits(digits + 10, losing=0):
                raise ArithmeticError("insufficient certified accuracy")
            return numberdb.RealInterval(endpoint(value.lower()), endpoint(value.upper()))


def verify_document(document, correct=False, independent=True):
    proposed = copy.deepcopy(document)
    if set(document["Numbers"]) != {params["s"] for params in BarnesValues().enumerate()}:
        raise AssertionError("inherited enumeration differs")
    evidence = []
    corrections = []
    minimum_bits = 10 ** 6
    for identity, entry in document["Numbers"].items():
        text = str(entry["number"] if isinstance(entry, dict) else entry)
        lower, upper, unit = bounds(text)
        row = {"s": identity, "number": text}
        with precision(200):
            value = evaluate(identity)
            if isinstance(value, int):
                if unit or lower != value or upper != value:
                    raise AssertionError("exact integer differs")
                row["exact"] = True
            else:
                if not value.is_finite() or value.rel_accuracy_bits() < 700:
                    raise AssertionError("uninformative enclosure")
                minimum_bits = min(minimum_bits, value.rel_accuracy_bits())
                low, high = endpoint(value.lower()), endpoint(value.upper())
                if not lower < low <= high < upper:
                    difference = ((low + high) / 2 - (lower + unit)) / unit
                    with mp.workdps(60):
                        discrepancy = mp.nstr(mp.mpf(difference.numerator) / difference.denominator, 30)
                    if not correct:
                        raise AssertionError("outside interval at %s: %s ulps" % (identity, discrepancy))
                    replacement = to_text(numberdb.RealInterval(low, high), 200)
                    corrections.append({"s": identity, "old_number": text, "new_number": replacement,
                                        "old_error_in_last_place_units": discrepancy})
                    text = replacement
                    row["number"] = replacement
                    if isinstance(entry, dict):
                        proposed["Numbers"][identity]["number"] = replacement
                    else:
                        proposed["Numbers"][identity] = replacement
                    lower, upper, unit = bounds(text)
                if not lower < low <= high < upper:
                    raise AssertionError("replacement fails containment")
                if lower + 10 * unit < low <= high < upper + 10 * unit:
                    raise AssertionError("negative control passed")
                row["certified_accuracy_bits"] = value.rel_accuracy_bits()
        if unit:
            with precision(250):
                higher = evaluate(identity)
                if not higher.is_finite() or not lower < endpoint(higher.lower()) <= endpoint(higher.upper()) < upper:
                    raise AssertionError("higher-precision Arb disagrees")
        for working in ((250, 300) if independent else ()):
            with mp.workdps(working):
                argument = Fraction(identity)
                independent = mp.barnesg(mp.mpf(argument.numerator) / argument.denominator)
                if not mp.isfinite(independent):
                    raise AssertionError("nonfinite independent result")
                independent_lower = mp.mpf(lower.numerator) / lower.denominator
                independent_upper = mp.mpf(upper.numerator) / upper.denominator
                if unit:
                    if not independent_lower < independent < independent_upper:
                        raise AssertionError("mpmath disagrees at " + identity)
                elif abs(independent - independent_lower) > mp.mpf(10) ** -220 * max(1, abs(independent)):
                    raise AssertionError("exact mpmath disagreement")
        row["mpmath_250_300_pass"] = True if independent else "checked before submission; identical numeric strings"
        evidence.append(row)
    return proposed, {"tid": "T93", "entries": len(evidence), "written_digits": 200,
                      "selection_review_complete": False, "range_changed": False,
                      "independent_mpmath_recomputed": independent,
                      "minimum_certified_accuracy_bits": minimum_bits,
                      "corrections": corrections, "records": evidence}


def run():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--fill", action="store_true")
    arguments = parser.parse_args()
    generator = BarnesValues()
    if arguments.fill:
        print(generator.publish(message="Verify inherited Barnes G range at 200 certified digits"))
    else:
        report = generator.verify(sample=None)
        print(report)
        verify_document(numberdb.table("T93"), independent=False)
        raise SystemExit(0 if report.ok else 1)