controls.py
3.5 kB · python · 113 lines
1import itertools2import math3from fractions import Fraction45CODES = range(1, 16)67def tile(code):8 return {(j & 1, (j >> 1) & 1) for j in range(4) if code & (1 << j)}910def kron(a, b, side_b):11 return {(ra * side_b + rb, ca * side_b + cb)12 for ra, ca in a for rb, cb in b}1314def word_array(word):15 cells, side = tile(word[0]), 216 for code in word[1:]:17 cells = kron(cells, tile(code), 2)18 side *= 219 return cells, side2021def profile(cells, side):22 p = [0] * (2 * side - 1)23 for r, c in cells:24 p[r + c] += 125 return p2627def convolve(p, q):28 out = [0] * (len(p) + len(q) - 1)29 for i, x in enumerate(p):30 if x:31 for j, y in enumerate(q):32 out[i + j] += x * y33 return out3435def dilate(p, k):36 out = [0] * ((len(p) - 1) * k + 1)37 for i, x in enumerate(p):38 out[i * k] = x39 return out4041def report_profile_identity():42 bad = 043 for length in (2, 3):44 for word in itertools.product(CODES, repeat=length):45 head, side = word_array(word[:-1])46 tail = tile(word[-1])47 lhs = profile(kron(head, tail, 2), side * 2)48 rhs = convolve(dilate(profile(head, side), 2), profile(tail, 2))49 bad += lhs != rhs50 print(f"profile identity mismatches over words of length 2 and 3: {bad}")5152def digit_polynomial(D):53 p = [0] * (2 * D + 1)54 for v in itertools.product(range(3), repeat=D):55 if sum(1 for x in v if x == 1) <= 1:56 p[sum(v)] += 157 return p5859def central_slice(D, level):60 p = digit_polynomial(D)61 acc = [1]62 for j in range(level):63 acc = convolve(acc, dilate(p, 3 ** j))64 return acc[(len(acc) - 1) // 2]6566def cross_section_vertices(D):67 if D % 2 == 0:68 return math.comb(D, D // 2)69 return math.comb(D, (D - 1) // 2) * ((D + 1) // 2)7071def report_vertex_identity(top):72 row, bad = [], 073 for D in range(2, top + 1):74 lhs, rhs = central_slice(D, 1), cross_section_vertices(D)75 bad += lhs != rhs76 row.append(lhs)77 print(f"level-1 slice against cross-section vertices, D = 2..{top}: "78 f"{bad} mismatches")79 print(f"level-1 slice counts D = 2..{top}: {row}")8081def fit_order_two(seq):82 s0, s1, s2, s3 = (Fraction(x) for x in seq[:4])83 det = s1 * s1 - s0 * s284 return (s1 * s2 - s0 * s3) / det, (s1 * s3 - s2 * s2) / det8586def report_rung(D, levels):87 seq = [central_slice(D, level) for level in range(1, levels + 1)]88 c1, c2 = fit_order_two(seq)89 holds = all(seq[n] == c1 * seq[n - 1] + c2 * seq[n - 2]90 for n in range(2, len(seq)))91 root = (float(c1) + math.sqrt(float(c1 * c1 + 4 * c2))) / 292 print(f"D = {D} census, levels 1..{levels}: {seq}")93 print(f"D = {D} recurrence a(n) = {c1}a(n-1) + {c2}a(n-2), "94 f"fitted on four terms, holds on every term: {holds}")95 print(f"D = {D} dominant root {root:.9f}, "96 f"slice dimension {math.log(root) / math.log(3):.9f}")9798def report_staircase(bases, top):99 for n in range(1, top + 1):100 num = sum((n - j) * math.log(q * q - ((q - 1) // 2) ** 2)101 for j, q in enumerate(bases[:n]))102 den = sum((n - j) * math.log(q) for j, q in enumerate(bases[:n]))103 print(f"staircase n = {n}, bases {bases[:n]}, "104 f"dimension {num / den:.9f}")105106def main():107 print("fill assumed for base q is q^2 - ((q-1)/2)^2")108 report_profile_identity()109 report_vertex_identity(14)110 report_rung(4, 6)111 report_staircase([3, 5, 7, 9, 11], 5)112113main()