radix.py

3.5 kB · python · 112 lines

1import itertools2from math import log3import numpy as np45N = 126SMALL = (2, 3, 5, 7, 11, 13)7SCHEDULES = [8    ("alternating base 2 {0,1} / base 3 {0,1}", ((2, (0, 1)), (3, (0, 1)))),9    ("alternating base 2 {0,1} / base 3 {0,2}", ((2, (0, 1)), (3, (0, 2)))),10    ("pure base 2 {0,1}", ((2, (0, 1)),)),11    ("pure base 3 {0,1}", ((3, (0, 1)),)),12    ("pure base 3 {0,2}", ((3, (0, 2)),)),13]1415def build(schedule, n):16    vals = [0]17    place = 118    for j in range(n):19        base, digits = schedule[j % len(schedule)]20        vals = [v + d * place for v in vals for d in digits]21        place *= base22    return sorted(vals)2324def moebius_table(n):25    mu = np.ones(n + 1, dtype=np.int64)26    prime = np.ones(n + 1, dtype=bool)27    prime[:2] = False28    for p in range(2, int(n ** 0.5) + 1):29        if prime[p]:30            prime[p * p::p] = False31    for p in np.nonzero(prime)[0]:32        mu[p::p] = -mu[p::p]33        mu[p * p::p * p] = 034    mu[0] = 035    return mu3637def present(vals, top):38    a = np.zeros(top + 1, dtype=np.int64)39    a[np.array(vals, dtype=np.int64)] = 140    a[0] = 041    return a4243def coprime_pairs(vals, mu, top):44    a = present(vals, top)45    ordered = 046    for m in range(1, top + 1):47        if mu[m]:48            c = int(a[m::m].sum())49            if c:50                ordered += int(mu[m]) * c * c51    unit = 1 if 1 in vals else 052    diagonal = unit53    with_zero = unit54    return (ordered - diagonal) // 2 + with_zero5556def divisible_fraction(vals, m):57    return sum(1 for v in vals if v % m == 0) / len(vals)5859def joint_small(vals):60    arr = np.array(vals, dtype=np.int64)61    n = len(vals)62    total = 063    for k in range(len(SMALL) + 1):64        for sub in itertools.combinations(SMALL, k):65            d = 166            for p in sub:67                d *= p68            c = int((arr % d == 0).sum())69            total += (-1 if k % 2 else 1) * c * (c - 1) // 270    return total / (n * (n - 1) // 2)7172top = max(max(build(s, N)) for _, s in SCHEDULES)73mu = moebius_table(top)7475print("DOMAIN %d digit positions, unordered distinct pairs including the zero point" % N)76print("points per schedule %d, pairs per schedule %d" % (1 << N, (1 << N) * ((1 << N) - 1) // 2))7778rows = {}79for name, sched in SCHEDULES:80    vals = build(sched, N)81    pairs = len(vals) * (len(vals) - 1) // 282    c = coprime_pairs(vals, mu, max(vals))83    rows[name] = (vals, c, c / pairs)84    print("%-40s coprime %7d  density %.6f" % (name, c, c / pairs))8586a, b = SCHEDULES[0][0], SCHEDULES[1][0]87print("alternating gap = %.6f" % (rows[b][2] - rows[a][2]))88print("pure base 2 against 1/zeta(2) = 0.607927, difference %+.6f" % (rows[SCHEDULES[2][0]][2] - 0.6079271018540267))8990vals = rows[a][0]91res = [sum(1 for v in vals if v % 6 == r) for r in range(6)]92print("residues mod 6 of the first alternating schedule: %s" % (", ".join(str(x) for x in res)))93for name in (a, b):94    vs = rows[name][0]95    print("%-40s even fraction %.6f  divisible by 3 fraction %.6f"96          % (name, divisible_fraction(vs, 2), divisible_fraction(vs, 3)))9798for name in (a, b):99    vs = rows[name][0]100    prod = 1.0101    for p in SMALL:102        prod *= 1 - divisible_fraction(vs, p) ** 2103    exact = joint_small(vs)104    print("%-40s Euler product through 13 = %.6f  exact joint = %.6f  product minus exact = %+.6f"105          % (name, prod, exact, prod - exact))106107for p in SMALL:108    fa = divisible_fraction(rows[a][0], p)109    fb = divisible_fraction(rows[b][0], p)110    ra = 1 - fa * fa111    rb = 1 - fb * fb112    print("prime %2d  factor %.6f -> %.6f  log advantage %+.6f" % (p, ra, rb, log(rb / ra)))