generate.py

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

4916 bytes, as of the version from 2026-10-29 01:41 (current). Recorded here, not run.

"""Resistance of the infinite square lattice -- numberdb.org/T596.

Run with SageMath (or passagemath with the named rings installed):
    sage -pip install numberdb
    sage -python generate.py                 # verify every stored entry
    sage -python generate.py --fill-draft    # write entries; API key required
    sage -python checks.py                  # independent checks, no API needed

The --fill-draft action writes numbers and attachments; it does not publish
or offer the draft. A private draft also requires a key for verification.

Cserti, arXiv:cond-mat/9909120v4, equation (32), determines exact rational
coefficients a,b in r(m,n)=a+b/pi. The zero value at the origin is a seed,
not an entry. The enumeration is the complete graph-distance ball m+n<=20
modulo sign changes and coordinate interchange. See argument-selection.md.

The guard starts at 128 bits beyond the requested digits. Cancellation is
measured from the resulting Arb ball; precision doubles if fewer than
ceil(log2(10)*digits)+16 relative accuracy bits survive. No floating point
computation enters the coefficients or the certified value.
"""
import os
import sys
from functools import lru_cache

import numberdb.sage as numberdb
from sage.rings.rational_field import QQ
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
from sage.rings.real_arb import RealBallField
from sage.rings.real_mpfi import RealIntervalField

MAX_DISTANCE = 20
WORKING_GUARD = 128
COEFFICIENT_RING = PolynomialRing(QQ, 't')
t = COEFFICIENT_RING.gen()


@lru_cache(maxsize=None)
def coefficient_table(limit):
    """Exact a+b*t for 0 <= n <= m <= limit, with t representing 1/pi."""
    result = {(0, 0): COEFFICIENT_RING.zero()}
    if limit == 0:
        return result
    result[1, 0] = COEFFICIENT_RING(QQ(1) / QQ(2))
    result[1, 1] = 2 * t
    for m in range(1, limit):
        result[m + 1, m + 1] = (
            QQ(4*m) / QQ(2*m+1) * result[m, m]
            - QQ(2*m-1) / QQ(2*m+1) * result[m-1, m-1])
        result[m+1, m] = 2*result[m, m] - result[m, m-1]
        result[m+1, 0] = 4*result[m, 0] - result[m-1, 0] - 2*result[m, 1]
        for n in range(1, m):
            result[m+1, n] = (4*result[m, n] - result[m-1, n]
                              - result[m, n+1] - result[m, n-1])
    assert all(p.degree() <= 1 for p in result.values())
    return result


def coefficients(m, n):
    if not (m >= n >= 0 and m > 0):
        raise ValueError('Require m >= n >= 0 and m > 0')
    p = coefficient_table(max(MAX_DISTANCE, m))[m, n]
    return p[0], p[1]


def certified_value(m, n, digits=100):
    a, b = coefficients(m, n)
    if b == 0:
        return a
    precision = numberdb.bits(digits, losing=WORKING_GUARD)
    required = numberdb.bits(digits, losing=16)
    while True:
        field = RealBallField(precision)
        value = field(a) + field(b) / field.pi()
        if value.is_finite():
            interval = RealIntervalField(precision)(value)
            low, high = (endpoint.exact_rational() for endpoint in interval.endpoints())
            if low > 0 and high-low <= low * QQ(2)**(-required):
                return value
        precision *= 2
        if precision > 1000000:
            raise ArithmeticError('Certification did not reach requested precision')


class SquareLatticeResistance(numberdb.Generator):
    table = 'T596'
    parameters = ('m', 'n')
    type = 'R'
    digits = 100
    rigour = 'proven'
    files = ('generate.py', 'checks.py', 'check.py', 'argument-selection.md',
             'numerical-evidence.json', 'skill-evidence.json')

    def enumerate(self, max_distance=MAX_DISTANCE):
        for distance in range(1, max_distance+1):
            for n in range(distance//2+1):
                yield {'m': str(distance-n), 'n': str(n)}

    def value(self, params, digits):
        m, n = int(params['m']), int(params['n'])
        value = certified_value(m, n, digits)
        if (m, n) == (1, 0):
            return {'number': value, 'comment': 'Adjacent vertices have resistance $R_0/2$.'}
        if (m, n) == (1, 1):
            return {'number': value, 'comment': r'Opposite corners of a unit square have resistance $2R_0/\pi$.'}
        return value


if __name__ == '__main__':
    if os.environ.get('NUMBERDB_KEY_FROM_STDIN') == '1':
        key = sys.stdin.read().strip()
        if '=' in key and key.split('=', 1)[0].isidentifier():
            key = key.split('=', 1)[1].strip().strip('\"\'')
        numberdb.configure(api_key=key)
    generator = SquareLatticeResistance()
    if '--fill-draft' in sys.argv or os.environ.get('NUMBERDB_PUBLISH') == '1':
        print(generator.publish(message='Fill 120 square lattice resistances with certified 100-digit enclosures',
                                assisted_by='codex-cli'))
    else:
        report = generator.verify(sample=None)
        print(report)
        sys.exit(0 if report.ok else 1)