erring_widths.py
Checks: SIZE: Growing widths observation; pattern.
Cited on: SIZE.
To run it: save erring_widths.py, with erring_label.py beside it; standard library only.
"""
erring_widths.py -- does a width profile growing with position err
locally below rounding's quarter?
QUESTION. Fill [0, c) with m intervals below the overflow label
(N = 2c - 1), the error as in erring_label.py. Rounding (equal widths,
one wide top [uc, c)) errs on a quarter of its fine pairs and tends to
1/10. Does a profile w(t) = g c (t/c)^p, widths at least 1, err less at
the same m, and how does the least error per c^2 fall with m?
THE ARGUMENT (written before this script). A cell of widths a, b sums
over an interval of width a + b at x + y, where the label has width
W(x + y); it errs nowhere unless a cut lies inside. At a phase spread
over the cells it straddles with chance about (a + b)/W, then errs on
between 1/6 (a = b) and 1/4 (a << b) of its pairs. Rounding has
a = b = W, a block twice its label, aligned at the best phase: 1/4.
Under t^p, (a + b)/W averages 2/(p + 1) over the triangle, so the local
error falls like 1/p; the uniform phase is a transplant the run decides.
PREDICTIONS AND KILLS (written before the run).
W1 at c = 4000, m near 34, 66, 162: some profile with p >= 2 prints
e/c^2 below rounding's best (u over 0.70..0.90) at the same m.
W2 p = 2 at m near 160 prints below 0.095; p = 3 below p = 2 at large
enough m.
W3 at fixed m the best profile's e/c^2 moves under 2% from c = 2000
to c = 4000.
K-floor: the lean "1/10 is the limit" dies if a profile prints
e/c^2 < 0.095 at c = 4000 and within 2% at c = 2000.
K-power: the heuristic dies if no profile at p = 2, 3, 4 prints below
rounding's best at the same m for any m in 34..400 at c = 4000.
W4 (written after W1..W3's prints) at m = 1000, c = 10000, the best
profile over p = 1, 2, 3 and top None, 0.8, 0.9 prints below 0.0785
(m = 400's best), holding within 2% scaled x2, and its p is >= 2.
Dies (the fall stalls) if the best is above 0.0785.
FINDINGS (from the printed run; both controls passed first).
K-floor fired: m = 400, p = 1, top 0.8 prints 0.0852 at c = 4000, and
the same cut set scaled x2 to x16 prints 0.0854 to 0.0857 against
rounding's 0.1012 to 0.1009. 1/10 is rounding's limit, not a floor:
at m = 162 the p = 1, top 0.8 cut set prints 0.0905 at every scale
x1 to x16 (rounding 0.1027 to 0.1029). On the reading it froze, the
re-tuned c = 2000 prints 0.0837, within 2% of 0.0852.
K-power survived: at m = 400, p = 2 (top 0.8) prints 0.0785 and p = 3
(top 0.8) 0.1005 against rounding's 0.1022. At p = 1 a profile beats
rounding's best from m = 66 (top 0.8: 0.1034 against 0.1068), not at
m = 34 (best 0.1362 against 0.1120, the widest label 800 of 4000).
W1 failed: no p >= 2 profile beats rounding at m <= 162; p = 1
(geometric widths) does from m = 66.
W2 failed: p = 2 at m = 162 prints 0.1183 at best; p = 3 is above
p = 2 at every m run (m = 400: 0.1005 against 0.0785). The profile
spends its labels on singletons near 0 (p = 3, m = 400: 299), so
larger p needs larger m.
W3 failed on the re-tuned reading it froze: re-tuned at c/2 the
profiles print 1.8 to 9.6% lower (m = 400, p = 2: 0.0710 against
0.0785). The reading kappa_m needs is
the same cut set scaled.
W4 held on the row run: m = 1000, c = 10000, p = 2, top 0.9 prints
0.0723, scaled x2 0.0731 (1.1%), x4 0.0734; rounding 0.1017, 0.1007,
0.1004. (Its comparison over p = 1, 2, 3 and three tops, and so its
clause that the best p is >= 2, is not run here.)
The scaled readings rise with the scale, the increments shrinking:
0.0785, 0.0793, 0.0796, 0.0798, 0.0799 at m = 400, p = 2, x1 to x16.
Each cut set's limit as it is scaled is its continuum error, an upper
bound on kappa_m; the run prints the approach, not the limit. The hand
estimate for p = 1, top 0.8: the local error at uniform phase, v =
x/(x + y) uniform, prints phi_1 = 0.1989 (section_phi; 1/4 at a flat
block, 1/6 at a triangle), so 0.64 x 0.1989/2 + 0.02 = 0.0836, against
0.0857 at m = 400, x16. The uniform phase is a transplant here; the
widths are a companding quantizer's (steps 1/G'(t), p = 1 the
logarithmic compressor of mu-law), and only the constants are the
run's.
CONTROLS. The fast error equals erring_label.error on every cut set at
N = 12, s = 2..5, and on rounding at c = 2000, w = 100; rounding at
c = 2000 reprints 0.1301 at w = 100.
"""
from bisect import bisect_right
from erring_label import below, error, cutsets, rounding
CHECKS = []
def check(name, ok, detail=""):
CHECKS.append(bool(ok))
tail = f" ({detail})" if detail else ""
print(f" {'PASS' if ok else 'FAIL'} {name}{tail}")
def fast_error(cuts, N):
"""error(cuts, N), reading only the labels each cell's sums meet."""
s = len(cuts) - 1
E = 0
for a in range(s):
u1, n1 = cuts[a], cuts[a + 1] - cuts[a]
for b in range(s):
u2, n2 = cuts[b], cuts[b + 1] - cuts[b]
base = u1 + u2
if base >= N:
continue
tot = below(n1, n2, N - base)
top = min(base + n1 + n2 - 2, N - 1)
lo = bisect_right(cuts, base) - 1
hi = bisect_right(cuts, top) - 1
if lo == hi:
continue
best = 0
for L in range(lo, hi + 1):
k = (below(n1, n2, min(cuts[L + 1], N) - base)
- below(n1, n2, cuts[L] - base))
best = max(best, k)
E += tot - best
return E
def profile(c, p, g, u=None):
"""Cuts of the profile t -> t + max(1, round(g c (t/c)^p)) on [0, U),
U = c or the top cut u c, then [U, c) as one top label."""
U = c if u is None else round(u * c)
cuts = [0]
t = 0
while True:
t = t + max(1, round(g * c * (t / c) ** p))
if t >= U:
break
cuts.append(t)
cuts.append(U)
if U < c:
cuts.append(c)
return tuple(cuts)
def profile_at(c, p, m, u=None):
"""A profile with m intervals, g found by bisection (None if missed)."""
lo, hi = 1e-9, 1e3
for _ in range(200):
g = (lo * hi) ** 0.5
k = len(profile(c, p, g, u)) - 1
if k == m:
return profile(c, p, g, u)
if k > m:
lo = g
else:
hi = g
return None
def round_at(c, m, u):
"""Rounding with m intervals: m - 2 cuts below the top u c."""
w = u * c / (m - 2)
cuts = rounding(c, w, u)
return cuts if len(cuts) - 1 == m else None
def ratio(cuts, c):
return fast_error(cuts + (2 * c - 1,), 2 * c - 1) / c / c
def section_controls():
print("controls")
bad = n = 0
for s in range(2, 6):
for cu in cutsets(12, s):
n += 1
bad += fast_error(cu, 12) != error(cu, 12)
check("control: fast error equals error() at N = 12", bad == 0,
f"{n} cut sets, {bad} faults")
cu = rounding(2000, 100, 0.8) + (3999,)
e1, e2 = fast_error(cu, 3999), error(cu, 3999)
check("control: fast error equals error() on rounding, c = 2000, w = 100",
e1 == e2 and f"{e1 / 4e6:.4f}" == "0.1301", f"{e1}, {e2}")
US = (0.70, 0.74, 0.78, 0.80, 0.82, 0.86, 0.90)
def best_round(c, m):
out = []
for u in US:
cu = round_at(c, m, u)
if cu:
out.append((ratio(cu, c), u))
return min(out) if out else (None, None)
def section_profiles(c, ms, ps, tops):
print(f"profiles against rounding, c = {c}")
rows = {}
for m in ms:
r, ru = best_round(c, m)
print(f" m = {m:3d} rounding best {r:.4f} (u = {ru})")
for p in ps:
for u in tops:
cu = profile_at(c, p, m, u)
if cu is None:
print(f" p = {p} top {u}: no g gives m = {m}")
continue
e = ratio(cu, c)
rows[(m, p, u)] = e
ones = sum(1 for i in range(len(cu) - 1)
if cu[i + 1] - cu[i] == 1)
print(f" p = {p:3} top {str(u):4} e/c^2 = {e:.4f}"
f"{' < rounding' if e < r else ''}"
f" singletons {ones}, widest {max(cu[i + 1] - cu[i] for i in range(len(cu) - 1))}")
rows[(m, "round")] = r
return rows
def section_scale(cases, c=4000, ks=(1, 2, 4)):
"""W3: the same shape at fixed m, scaled; and as frozen, re-tuned at
c/2."""
print(f"fixed m: the c = {c} cut set scaled, and re-tuned at {c // 2}")
for m, p, u in cases:
cu = profile_at(c, p, m, u)
row = [ratio(tuple(k * x for x in cu), c * k) for k in ks]
re = profile_at(c // 2, p, m, u)
r2 = ratio(re, c // 2) if re else float("nan")
rr = [best_round(c * k, m)[0] for k in ks]
print(f" m = {m} p = {p} top {u}: scaled "
+ ", ".join(f"x{k}" for k in ks) + " "
+ ", ".join(f"{x:.4f}" for x in row)
+ f"; re-tuned c = {c // 2} {r2:.4f}; rounding "
+ ", ".join(f"{x:.4f}" for x in rr))
def section_phi(n=600):
"""The p = 1 local error at uniform phase: U[0, a] + U[0, 1 - a]
against a cut at a uniform offset of [0, 1), a = min(v, 1 - v), the
mean of min(F, 1 - F) over the offset and v, both by midpoints."""
def cdf(t, a, b):
if a == 0:
return t / b
if t <= a:
return t * t / (2 * a * b)
if t <= b:
return (t - a / 2) / b
s = a + b - t
return 1 - s * s / (2 * a * b)
tot = 0.0
for i in range(n):
v = (i + 0.5) / n
a, b = min(v, 1 - v), max(v, 1 - v)
tot += sum(min(x, 1 - x) for x in
(cdf((j + 0.5) / n, a, b) for j in range(n))) / n
phi = tot / n
print(f"phi_1 = {phi:.4f} (flat block 1/4, triangle 1/6); at u = 0.8 "
f"the estimate 0.64 phi/2 + 0.02 = {0.64 * phi / 2 + 0.02:.4f}")
def main():
section_controls()
if not all(CHECKS):
print("\nCONTROL FAILED: nothing below is read.")
raise SystemExit(1)
section_profiles(4000, (34, 66, 162, 400), (1, 2, 3), (None, 0.8, 0.9))
section_scale([(162, 1, 0.8), (400, 1, 0.8), (400, 2, 0.8)],
ks=(1, 2, 4, 8, 16))
section_scale([(1000, 2, 0.9)], c=10000, ks=(1, 2, 4))
section_phi()
print(f"{sum(CHECKS)}/{len(CHECKS)} checks passed")
raise SystemExit(0 if all(CHECKS) else 1)
if __name__ == "__main__":
main()