diff --git a/papers/heawood_restrictions_on_nested_tire_graph_duals/experiments/branch_invariant.py b/papers/heawood_restrictions_on_nested_tire_graph_duals/experiments/branch_invariant.py new file mode 100644 index 0000000..049565e --- /dev/null +++ b/papers/heawood_restrictions_on_nested_tire_graph_duals/experiments/branch_invariant.py @@ -0,0 +1,182 @@ +""" +Does the richness invariant survive BRANCHING? + +For a separating cycle C bounding a disk G_C (away from the source), the achievable +outer-interface set is + + Phi(C) = { (lambda*(v))_{v in C} : lambda in {+1,-1}^{F(G_C)}, + sum_{f ∋ w} lambda(f) ≡ 0 for every + truly-interior vertex w of G_C }. + +This is the exact value the recursive transfer operator produces at C (interior +consistency = all the descendant gluings already performed; seam/boundary vertices +are deferred, exactly as in the recursion). We compute Phi(C) by constrained +enumeration over real triangulations and test the candidate self-similar invariant + + non-empty & closed under sign flip & full single-position marginals + +separately at BRANCH nodes (region encloses >=2 disjoint deeper sub-tires) and at +LINEAR nodes (one child), to see whether branching breaks it. +""" + +import sys +from collections import defaultdict, deque +from itertools import product + +import numpy as np +from scipy.spatial import Delaunay + + +def delaunay(n, rng): + pts = rng.random((n, 2)) + tri = Delaunay(pts) + faces = [tuple(int(x) for x in s) for s in tri.simplices] + hull = set(int(v) for e in tri.convex_hull for v in e) + return faces, hull + + +def build(faces): + adj = defaultdict(set) + efaces = defaultdict(list) + vfaces = defaultdict(list) + for fi, (a, b, c) in enumerate(faces): + adj[a] |= {b, c}; adj[b] |= {a, c}; adj[c] |= {a, b} + for e in ((a, b), (b, c), (a, c)): + efaces[frozenset(e)].append(fi) + for v in (a, b, c): + vfaces[v].append(fi) + fadj = [set() for _ in faces] + for fl in efaces.values(): + for i in fl: + for j in fl: + if i != j: + fadj[i].add(j) + return adj, fadj, vfaces + + +def bfs(adj, src): + lev = {src: 0}; q = deque([src]) + while q: + u = q.popleft() + for w in adj[u]: + if w not in lev: + lev[w] = lev[u] + 1; q.append(w) + return lev + + +def components(face_ids, fadj): + idset = set(face_ids) + seen = set(); comps = [] + for s in face_ids: + if s in seen: + continue + comp = []; stack = [s]; seen.add(s) + while stack: + u = stack.pop(); comp.append(u) + for w in fadj[u]: + if w in idset and w not in seen: + seen.add(w); stack.append(w) + comps.append(comp) + return comps + + +def sign_closed(S): + return all(tuple((3 - x) % 3 for x in s) in S for s in S) + + +def marginals_full(S, k): + return all({s[i] for s in S} == {0, 1, 2} for i in range(k)) + + +def phi_of_region(comp_faces, faces, vfaces, lev, d, cap): + """Constrained-enumeration Phi on the outer (level-d) cycle of a region.""" + Gc = comp_faces + if not (1 <= len(Gc) <= cap): + return None + Gcset = set(Gc) + verts = sorted(set(v for fi in Gc for v in faces[fi])) + # truly-interior: every global incident face is inside G_C (=> level > d) + interior = [v for v in verts if all(f in Gcset for f in vfaces[v])] + boundary_C = [v for v in verts if lev[v] == d and v not in interior] + if not boundary_C: + return None + F = len(Gc) + fidx = {fi: j for j, fi in enumerate(Gc)} + # incidence rows + Bint = np.zeros((len(interior), F), dtype=np.int64) + for r, w in enumerate(interior): + for fi in vfaces[w]: + if fi in Gcset: + Bint[r, fidx[fi]] = 1 + Cinc = np.zeros((len(boundary_C), F), dtype=np.int64) + for r, v in enumerate(boundary_C): + for fi in vfaces[v]: + if fi in Gcset: + Cinc[r, fidx[fi]] = 1 + labs = np.array(list(product((1, 2), repeat=F)), dtype=np.int64) + if len(interior): + ok = np.all((labs @ Bint.T) % 3 == 0, axis=1) + labs = labs[ok] + if labs.shape[0] == 0: + return set(), len(boundary_C) + outer = (labs @ Cinc.T) % 3 + return set(map(tuple, np.unique(outer, axis=0))), len(boundary_C) + + +def main(): + seed = int(sys.argv[1]) if len(sys.argv) > 1 else 0 + nprng = np.random.default_rng(seed) + CAP = 18 + + stats = {True: [0, 0, 0, 0], False: [0, 0, 0, 0]} # branch: [n, nonempty, sign, marg] + examples_fail = [] + + for _ in range(300): + faces, hull = delaunay(int(nprng.integers(14, 34)), nprng) + adj, fadj, vfaces = build(faces) + lev = bfs(adj, min(hull)) + if len(lev) != len(adj): + continue + depth = [min(lev[v] for v in faces[fi]) for fi in range(len(faces))] + maxd = max(depth) + for d in range(1, maxd + 1): + fge = [fi for fi in range(len(faces)) if depth[fi] >= d] + for comp in components(fge, fadj): + if not (1 <= len(comp) <= CAP): + continue + deeper = [fi for fi in comp if depth[fi] >= d + 1] + n_children = len(components(deeper, fadj)) + is_branch = n_children >= 2 + res = phi_of_region(comp, faces, vfaces, lev, d, CAP) + if res is None: + continue + S, k = res + rec = stats[is_branch] + rec[0] += 1 + rec[1] += bool(S) + rec[2] += (bool(S) and sign_closed(S)) + rec[3] += (bool(S) and marginals_full(S, k)) + if S and not marginals_full(S, k) and len(examples_fail) < 6: + examples_fail.append((is_branch, n_children, len(comp), k, + len(S))) + + for branch in (False, True): + n, ne, sg, mg = stats[branch] + tag = "BRANCH (>=2 children)" if branch else "LINEAR (1 child)" + if n: + print(f"{tag}: {n} regions") + print(f" non-empty : {ne}/{n} ({100*ne/n:.1f}%)") + print(f" sign-closed : {sg}/{n} ({100*sg/n:.1f}%)") + print(f" marginals-full : {mg}/{n} ({100*mg/n:.1f}%)") + else: + print(f"{tag}: 0 regions") + if examples_fail: + print("\n marginals-NOT-full examples (branch?,n_children,|G_C|,|C|,|Phi|):") + for e in examples_fail: + print(f" {e}") + else: + print("\n richness (incl. full marginals) held on every region tested.") + + +if __name__ == "__main__": + main() diff --git a/papers/heawood_restrictions_on_nested_tire_graph_duals/experiments/maximally_constrain.py b/papers/heawood_restrictions_on_nested_tire_graph_duals/experiments/maximally_constrain.py new file mode 100644 index 0000000..b8577bf --- /dev/null +++ b/papers/heawood_restrictions_on_nested_tire_graph_duals/experiments/maximally_constrain.py @@ -0,0 +1,167 @@ +""" +Construct the triangulated disk (= nested tire substructure) that MAXIMALLY +constrains its outer cycle. + +For a triangulated disk D with boundary cycle C = (0..n-1), the achievable outer +Heawood set is + + Phi(D) = { (lambda*(v))_{v in C} : lambda in {+1,-1}^{faces}, + sum_{f ∋ w} lambda(f) ≡ 0 for every interior vertex w } . + +Phi depends only on the disk triangulation (no BFS/tree needed). We want the disk +minimising |Phi| -- the worst case for the pigeonhole. Note Phi is always +sign-closed and non-empty, so |Phi| >= 1, and |Phi| = 1 forces Phi = { all-zeros }. + +Key local fact: a degree-3 interior vertex (one Apollonian stack) has incident +faces f1,f2,f3 with lambda(f1)+lambda(f2)+lambda(f3) ≡ 0 mod 3 over +/-1 values, +which forces f1=f2=f3. So stacking chains equalities and collapses Phi. + +We (a) randomly search disks built by Apollonian stacking, and (b) try a +deterministic deep-stack construction, reporting the smallest Phi found. +""" + +import random +import sys +from itertools import product + +import numpy as np + + +def fan_triangulation(n): + """n-gon (0..n-1) triangulated as a fan from vertex 0. No interior vertex.""" + return [(0, i, i + 1) for i in range(1, n - 1)] + + +def stack(faces, idx, v): + a, b, c = faces[idx] + faces[idx] = (a, b, v) + faces.append((b, c, v)) + faces.append((a, c, v)) + + +def phi(faces, n, cap): + """Phi on boundary 0..n-1; interior = vertices >= n.""" + verts = set(v for f in faces for v in f) + interior = sorted(v for v in verts if v >= n) + F = len(faces) + if F > cap: + return None + # incidence + Bint = np.zeros((len(interior), F), dtype=np.int64) + iindex = {w: r for r, w in enumerate(interior)} + Cinc = np.zeros((n, F), dtype=np.int64) + for j, (a, b, c) in enumerate(faces): + for v in (a, b, c): + if v >= n: + Bint[iindex[v], j] = 1 + else: + Cinc[v, j] = 1 + labs = np.array(list(product((1, 2), repeat=F)), dtype=np.int64) + if len(interior): + keep = np.all((labs @ Bint.T) % 3 == 0, axis=1) + labs = labs[keep] + if labs.shape[0] == 0: + return set() + outer = (labs @ Cinc.T) % 3 + return set(map(tuple, np.unique(outer, axis=0))) + + +def disp(s): + return tuple(-1 if int(x) == 2 else int(x) for x in s) + + +def gf3_rank(rows): + M = [[int(x) % 3 for x in r] for r in rows] + if not M: + return 0 + nc = len(M[0]); r = 0 + for c in range(nc): + piv = next((i for i in range(r, len(M)) if M[i][c] % 3), None) + if piv is None: + continue + M[r], M[piv] = M[piv], M[r] + inv = M[r][c] % 3 + M[r] = [(x * inv) % 3 for x in M[r]] + for i in range(len(M)): + if i != r and M[i][c] % 3: + fct = M[i][c] % 3 + M[i] = [(M[i][k] - fct * M[r][k]) % 3 for k in range(nc)] + r += 1 + if r == len(M): + break + return r + + +def describe(P): + P = list(P) + sign_closed = all(tuple((3 - x) % 3 for x in s) in set(P) for s in P) + s0 = P[0] + D = [tuple((np.array(s) - np.array(s0)) % 3) for s in P] + rank = gf3_rank(D) + affine = (len(P) == 3 ** rank) + pow2 = (len(P) & (len(P) - 1)) == 0 + return (f"sign-closed={sign_closed} affine-GF3={affine} " + f"|Phi|={len(P)} (power-of-2={pow2}) hull-dim={rank}") + + +def random_disk(n, n_stacks, rng): + faces = fan_triangulation(n) + nxt = n + for _ in range(n_stacks): + stack(faces, rng.randrange(len(faces)), nxt) + nxt += 1 + return faces + + +def deep_stack_disk(n, n_stacks): + """Always stack into the most-recently created face -> deep equality chain.""" + faces = fan_triangulation(n) + nxt = n + for _ in range(n_stacks): + stack(faces, len(faces) - 1, nxt) + nxt += 1 + return faces + + +def search(n, cap=18, trials=400, seed=0): + rng = random.Random(seed) + best = (10 ** 9, None, None) + max_stacks = (cap - (n - 2)) // 2 + # random search + for _ in range(trials): + k = rng.randint(0, max_stacks) + faces = random_disk(n, k, rng) + P = phi(faces, n, cap) + if P is None: + continue + if len(P) < best[0]: + best = (len(P), k, P) + # deterministic deep stack at max depth + for k in range(max_stacks + 1): + faces = deep_stack_disk(n, k) + P = phi(faces, n, cap) + if P is not None and len(P) < best[0]: + best = (len(P), k, P) + size, k, P = best + print(f"n={n}: min |Phi| = {size} (= 2^(n-2) = {2**(n-2)}?) " + f"interior vertices = {k}, max stacks at cap {cap} = {max_stacks}") + print(f" {describe(P)}") + for s in sorted(P)[:6]: + print(f" {disp(s)}") + if len(P) > 6: + print(f" ... (+{len(P)-6} more)") + return size + + +def main(): + ns = [int(x) for x in sys.argv[1:]] or [4, 5, 6, 7] + print("Searching for maximally-constraining disks (min |Phi|)\n") + for n in ns: + # bigger cap for small n + cap = 18 if n <= 6 else 16 + search(n, cap=cap) + print() + + +if __name__ == "__main__": + main() diff --git a/papers/heawood_restrictions_on_nested_tire_graph_duals/experiments/search_universal_sequence.py b/papers/heawood_restrictions_on_nested_tire_graph_duals/experiments/search_universal_sequence.py new file mode 100644 index 0000000..e50e830 --- /dev/null +++ b/papers/heawood_restrictions_on_nested_tire_graph_duals/experiments/search_universal_sequence.py @@ -0,0 +1,129 @@ +""" +Search for a UNIVERSAL Heawood boundary sequence for a tire graph. + +Fix an outer boundary cycle B_out of length n (the interface at which a tire +glues to its parent). Each way of filling the annulus -- an inner boundary of +size m together with a spoke triangulation ("inner graph") -- gives a tire whose +annular faces induce a set of realisable outer Heawood sequences + + R_out(tire) = { (lambda*(v0), ..., lambda*(v_{n-1})) : lambda in {+1,-1}^F } + ⊆ {0,1,-1}^n . + +A *universal sequence* for B_out is one realisable for EVERY inner graph, i.e. a +member of the intersection ∩_tire R_out(tire). If a universal sequence existed, +a parent could always present its negation and glue to any child regardless of +the child's interior. + +Note: chords of the inner outerplanar graph O lie inside B_in and bound no +annular face, so they do not change R_out -- only (n, m, spoke-path) do. And +intersecting over a SUBFAMILY of inner graphs can only OVERestimate the true +intersection, so finding the intersection empty over simple-cycle inner fills is +already conclusive that NO universal sequence exists. +""" + +import sys +from itertools import combinations, product + +import numpy as np + + +def lattice_paths(n_outer, m_inner): + """All spoke triangulations: strings with n_outer 'O' moves, m_inner 'I'.""" + N = n_outer + m_inner + for opos in combinations(range(N), n_outer): + opos = set(opos) + yield "".join("O" if i in opos else "I" for i in range(N)) + + +def annular_faces(n, m, path): + """Faces (triangles) of the annulus between outer n-cycle (0..n-1) and inner + m-cycle (n..n+m-1) under the spoke path. Starts at spoke (outer0, inner0).""" + faces = [] + i = j = 0 + for mv in path: + if mv == "O": + faces.append((i % n, (i + 1) % n, n + (j % m))) + i += 1 + else: + faces.append((i % n, n + (j % m), n + ((j + 1) % m))) + j += 1 + return faces + + +def fan_faces(n): + """m = 1 degenerate inner boundary: a wheel/fan, center = vertex n.""" + return [(i, (i + 1) % n, n) for i in range(n)] + + +def realisable_outer(n, faces): + """Set of outer Heawood sequences over all +/-1 face labellings.""" + F = len(faces) + A = np.zeros((n, F), dtype=np.int64) # outer-vertex x face incidence + for f, tri in enumerate(faces): + for v in tri: + if v < n: + A[v, f] = 1 + labs = np.array(list(product((1, 2), repeat=F)), dtype=np.int64) + vals = (labs @ A.T) % 3 + # display residues in {0, 1, -1}: 2 -> -1 + vals = np.where(vals == 2, -1, vals) + return set(tuple(int(x) for x in row) for row in np.unique(vals, axis=0)) + + +def tires_for(n, m_max, fcap): + """Yield (label, faces) for inner fills of an n-outer tire.""" + yield (f"m=1 fan", fan_faces(n)) + for m in range(2, m_max + 1): + if n + m > fcap: + continue + for path in lattice_paths(n, m): + yield (f"m={m} {path}", annular_faces(n, m, path)) + + +def run(n, m_max=7, fcap=13): + inter = None + n_tires = 0 + min_set = (10**9, None) + shrink_trace = [] + for label, faces in tires_for(n, m_max, fcap): + R = realisable_outer(n, faces) + n_tires += 1 + if len(R) < min_set[0]: + min_set = (len(R), label) + if inter is None: + inter = set(R) + else: + before = len(inter) + inter &= R + if len(inter) < before: + shrink_trace.append((n_tires, label, len(inter))) + if not inter: + break + print(f"n={n}: {n_tires} tires tried, " + f"smallest single R_out = {min_set[0]} ({min_set[1]})") + if inter: + print(f" UNIVERSAL sequences found: {len(inter)}") + for s in sorted(inter)[:12]: + print(f" {s}") + else: + print(f" NO universal sequence: intersection emptied after " + f"{n_tires} tires") + print(" intersection size as tires were added (last few shrinks):") + for t in shrink_trace[-6:]: + print(f" after tire {t[0]:4d} ({t[1]}): |∩| = {t[2]}") + return bool(inter) + + +def main(): + if len(sys.argv) > 1: + ns = [int(sys.argv[1])] + else: + ns = [3, 4, 5, 6] + print("Searching for universal Heawood boundary sequences\n") + for n in ns: + run(n) + print() + + +if __name__ == "__main__": + main() diff --git a/papers/heawood_restrictions_on_nested_tire_graph_duals/experiments/transfer_operator.py b/papers/heawood_restrictions_on_nested_tire_graph_duals/experiments/transfer_operator.py new file mode 100644 index 0000000..dc220f8 --- /dev/null +++ b/papers/heawood_restrictions_on_nested_tire_graph_duals/experiments/transfer_operator.py @@ -0,0 +1,172 @@ +""" +Transfer operator for the Heawood program, in the cleanest self-similar setting: +a chain of annular tires with n_out = n_in = n. Each tire's labelling map sends ++/-1 face labels to (outer sequence, inner sequence). Gluing a child below means +the parent's inner sequence must negate (mod 3) the child's achievable outer +sequence. So the achievable outer-interface set propagates UP the chain by + + Phi(parent) = { outer(lambda) : lambda in {+-1}^F, + inner(lambda) in -Phi(child) }. + +This is a monotone set-operator on subsets of (Z/3)^n. Iterating it models a +deepening nested chain; we look for a FIXED POINT (absorbing set) and test which +candidate self-similar invariants the limit satisfies: + * non-empty + * closed under the global sign flip s -> -s + * local marginals: does every position attain all of {0,1,-1}? + * is it an affine GF(3) subspace? (we expect NO -- R_T is a zonotope) + * does a linear/parity constraint cut it out? +Sequences are stored mod 3 in {0,1,2}; printed in {0,1,-1} (2 -> -1). +""" + +import sys +from itertools import product + +import numpy as np + + +def annular_tire(n_out, n_in, path): + """Faces between outer cycle 0..n_out-1 and inner cycle n_out..n_out+n_in-1.""" + faces = [] + i = j = 0 + for mv in path: + if mv == "O": + faces.append((i % n_out, (i + 1) % n_out, n_out + (j % n_in))) + i += 1 + else: + faces.append((i % n_out, n_out + (j % n_in), n_out + ((j + 1) % n_in))) + j += 1 + return faces + + +def labelling_pairs(n_out, n_in, faces): + """All (outer_seq, inner_seq) over lambda in {+1,-1}^F, as Z/3 tuples.""" + F = len(faces) + Ao = np.zeros((n_out, F), dtype=np.int64) + Ai = np.zeros((n_in, F), dtype=np.int64) + for f, (a, b, c) in enumerate(faces): + for v in (a, b, c): + if v < n_out: + Ao[v, f] = 1 + else: + Ai[v - n_out, f] = 1 + labs = np.array(list(product((1, 2), repeat=F)), dtype=np.int64) + outer = (labs @ Ao.T) % 3 + inner = (labs @ Ai.T) % 3 + return [(tuple(o), tuple(i)) for o, i in zip(outer.tolist(), inner.tolist())] + + +def make_operator(pairs): + def op(phi_child): + neg = {tuple((3 - x) % 3 for x in s) for s in phi_child} + return {o for (o, inn) in pairs if inn in neg} + return op + + +def iterate_to_fixed(op, start, max_iter=50): + phi = frozenset(start) + seen = [phi] + for _ in range(max_iter): + nxt = frozenset(op(phi)) + if nxt == phi: + return phi, "fixed", len(seen) + if nxt in seen: + return nxt, "cycle", len(seen) + phi = nxt + seen.append(phi) + return phi, "no-converge", len(seen) + + +# ----------------- invariant tests ------------------------------------------- +def disp(s): + return tuple(-1 if x == 2 else x for x in s) + + +def gf3_rank(rows): + M = [[x % 3 for x in r] for r in rows] + if not M: + return 0 + nc = len(M[0]); r = 0 + for c in range(nc): + piv = next((i for i in range(r, len(M)) if M[i][c] % 3), None) + if piv is None: + continue + M[r], M[piv] = M[piv], M[r] + inv = M[r][c] % 3 # 1->1, 2->2 are self-inverse mod 3 + M[r] = [(x * inv) % 3 for x in M[r]] + for i in range(len(M)): + if i != r and M[i][c] % 3: + f = M[i][c] % 3 + M[i] = [(M[i][k] - f * M[r][k]) % 3 for k in range(nc)] + r += 1 + if r == len(M): + break + return r + + +def is_affine(S): + S = list(S) + if len(S) <= 1: + return True + s0 = S[0] + D = [tuple((np.array(s) - np.array(s0)) % 3) for s in S] + return len(S) == 3 ** gf3_rank(D) + + +def marginals_full(S, n): + return all({s[i] for s in S} == {0, 1, 2} for i in range(n)) + + +def sign_closed(S): + return all(tuple((3 - x) % 3 for x in s) in S for s in S) + + +def linear_constraints(S, n): + """Dimension of the space of linear forms vanishing on S-s0 (codim of hull).""" + S = list(S) + if len(S) <= 1: + return n + s0 = S[0] + D = [tuple((np.array(s) - np.array(s0)) % 3) for s in S] + return n - gf3_rank(D) + + +def analyse(tag, S, n): + print(f" [{tag}] |Phi|={len(S)} of 3^{n}={3**n} " + f"sign-closed={sign_closed(S)} marginals-full={marginals_full(S,n)} " + f"affine={is_affine(S)} hull-codim={linear_constraints(S,n)}") + + +def run(n, paths=None): + if paths is None: + # a few distinct same-n annular triangulations + paths = ["OI" * n, "O" * n + "I" * n, ("OOI" * n)[:2 * n]] + paths = [p for p in paths if p.count("O") == n and p.count("I") == n] + print(f"=== n={n} ===") + full = set(product((0, 1, 2), repeat=n)) + for path in paths: + faces = annular_tire(n, n, path) + pairs = labelling_pairs(n, n, faces) + op = make_operator(pairs) + single = set(o for (o, _) in pairs) # leaf: full single-tire outer set + fixed, how, steps = iterate_to_fixed(op, single) + # also iterate from the universal start (all sequences allowed below) + fixed2, how2, _ = iterate_to_fixed(op, full) + print(f" path={path}: single-tire |outer|={len(single)}; " + f"iterate->{how} in {steps} steps; " + f"same-limit-from-full={fixed==fixed2}") + analyse("limit", fixed, n) + sample = sorted(disp(s) for s in fixed)[:8] + print(f" sample of limit set: {sample}") + print() + + +def main(): + ns = [int(x) for x in sys.argv[1:]] or [4, 5, 6] + print("Transfer-operator fixed points on same-n annular tire chains\n") + for n in ns: + run(n) + + +if __name__ == "__main__": + main() diff --git a/papers/heawood_restrictions_on_nested_tire_graph_duals/notes/boundary_restriction_structure.aux b/papers/heawood_restrictions_on_nested_tire_graph_duals/notes/boundary_restriction_structure.aux new file mode 100644 index 0000000..d490c35 --- /dev/null +++ b/papers/heawood_restrictions_on_nested_tire_graph_duals/notes/boundary_restriction_structure.aux @@ -0,0 +1,2 @@ +\relax +\gdef \@abspage@last{2} diff --git a/papers/heawood_restrictions_on_nested_tire_graph_duals/notes/boundary_restriction_structure.log b/papers/heawood_restrictions_on_nested_tire_graph_duals/notes/boundary_restriction_structure.log new file mode 100644 index 0000000..d218c6a --- /dev/null +++ b/papers/heawood_restrictions_on_nested_tire_graph_duals/notes/boundary_restriction_structure.log @@ -0,0 +1,296 @@ +This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022) (preloaded format=pdflatex 2022.10.5) 17 JUN 2026 02:12 +entering extended mode + restricted \write18 enabled. + %&-line parsing enabled. +**boundary_restriction_structure.tex +(./boundary_restriction_structure.tex +LaTeX2e <2021-11-15> patch level 1 +L3 programming layer <2022-02-24> +(/usr/local/texlive/2022/texmf-dist/tex/latex/base/article.cls +Document Class: article 2021/10/04 v1.4n Standard LaTeX document class +(/usr/local/texlive/2022/texmf-dist/tex/latex/base/size11.clo +File: size11.clo 2021/10/04 v1.4n Standard LaTeX file (size option) +) +\c@part=\count185 +\c@section=\count186 +\c@subsection=\count187 +\c@subsubsection=\count188 +\c@paragraph=\count189 +\c@subparagraph=\count190 +\c@figure=\count191 +\c@table=\count192 +\abovecaptionskip=\skip47 +\belowcaptionskip=\skip48 +\bibindent=\dimen138 +) +(/usr/local/texlive/2022/texmf-dist/tex/latex/amsmath/amsmath.sty +Package: amsmath 2021/10/15 v2.17l AMS math features +\@mathmargin=\skip49 + +For additional information on amsmath, use the `?' option. +(/usr/local/texlive/2022/texmf-dist/tex/latex/amsmath/amstext.sty +Package: amstext 2021/08/26 v2.01 AMS text + +(/usr/local/texlive/2022/texmf-dist/tex/latex/amsmath/amsgen.sty +File: amsgen.sty 1999/11/30 v2.0 generic functions +\@emptytoks=\toks16 +\ex@=\dimen139 +)) +(/usr/local/texlive/2022/texmf-dist/tex/latex/amsmath/amsbsy.sty +Package: amsbsy 1999/11/29 v1.2d Bold Symbols +\pmbraise@=\dimen140 +) +(/usr/local/texlive/2022/texmf-dist/tex/latex/amsmath/amsopn.sty +Package: amsopn 2021/08/26 v2.02 operator names +) +\inf@bad=\count193 +LaTeX Info: Redefining \frac on input line 234. +\uproot@=\count194 +\leftroot@=\count195 +LaTeX Info: Redefining \overline on input line 399. +\classnum@=\count196 +\DOTSCASE@=\count197 +LaTeX Info: Redefining \ldots on input line 496. +LaTeX Info: Redefining \dots on input line 499. +LaTeX Info: Redefining \cdots on input line 620. +\Mathstrutbox@=\box50 +\strutbox@=\box51 +\big@size=\dimen141 +LaTeX Font Info: Redeclaring font encoding OML on input line 743. +LaTeX Font Info: Redeclaring font encoding OMS on input line 744. +\macc@depth=\count198 +\c@MaxMatrixCols=\count199 +\dotsspace@=\muskip16 +\c@parentequation=\count266 +\dspbrk@lvl=\count267 +\tag@help=\toks17 +\row@=\count268 +\column@=\count269 +\maxfields@=\count270 +\andhelp@=\toks18 +\eqnshift@=\dimen142 +\alignsep@=\dimen143 +\tagshift@=\dimen144 +\tagwidth@=\dimen145 +\totwidth@=\dimen146 +\lineht@=\dimen147 +\@envbody=\toks19 +\multlinegap=\skip50 +\multlinetaggap=\skip51 +\mathdisplay@stack=\toks20 +LaTeX Info: Redefining \[ on input line 2938. +LaTeX Info: Redefining \] on input line 2939. +) +(/usr/local/texlive/2022/texmf-dist/tex/latex/amsfonts/amssymb.sty +Package: amssymb 2013/01/14 v3.01 AMS font symbols + +(/usr/local/texlive/2022/texmf-dist/tex/latex/amsfonts/amsfonts.sty +Package: amsfonts 2013/01/14 v3.01 Basic AMSFonts support +\symAMSa=\mathgroup4 +\symAMSb=\mathgroup5 +LaTeX Font Info: Redeclaring math symbol \hbar on input line 98. +LaTeX Font Info: Overwriting math alphabet `\mathfrak' in version `bold' +(Font) U/euf/m/n --> U/euf/b/n on input line 106. +)) +(/usr/local/texlive/2022/texmf-dist/tex/latex/amscls/amsthm.sty +Package: amsthm 2020/05/29 v2.20.6 +\thm@style=\toks21 +\thm@bodyfont=\toks22 +\thm@headfont=\toks23 +\thm@notefont=\toks24 +\thm@headpunct=\toks25 +\thm@preskip=\skip52 +\thm@postskip=\skip53 +\thm@headsep=\skip54 +\dth@everypar=\toks26 +) +(/usr/local/texlive/2022/texmf-dist/tex/latex/graphics/graphicx.sty +Package: graphicx 2021/09/16 v1.2d Enhanced LaTeX Graphics (DPC,SPQR) + +(/usr/local/texlive/2022/texmf-dist/tex/latex/graphics/keyval.sty +Package: keyval 2014/10/28 v1.15 key=value parser (DPC) +\KV@toks@=\toks27 +) +(/usr/local/texlive/2022/texmf-dist/tex/latex/graphics/graphics.sty +Package: graphics 2021/03/04 v1.4d Standard LaTeX Graphics (DPC,SPQR) + +(/usr/local/texlive/2022/texmf-dist/tex/latex/graphics/trig.sty +Package: trig 2021/08/11 v1.11 sin cos tan (DPC) +) +(/usr/local/texlive/2022/texmf-dist/tex/latex/graphics-cfg/graphics.cfg +File: graphics.cfg 2016/06/04 v1.11 sample graphics configuration +) +Package graphics Info: Driver file: pdftex.def on input line 107. + +(/usr/local/texlive/2022/texmf-dist/tex/latex/graphics-def/pdftex.def +File: pdftex.def 2020/10/05 v1.2a Graphics/color driver for pdftex +)) +\Gin@req@height=\dimen148 +\Gin@req@width=\dimen149 +) +(/usr/local/texlive/2022/texmf-dist/tex/latex/geometry/geometry.sty +Package: geometry 2020/01/02 v5.9 Page Geometry + +(/usr/local/texlive/2022/texmf-dist/tex/generic/iftex/ifvtex.sty +Package: ifvtex 2019/10/25 v1.7 ifvtex legacy package. Use iftex instead. + +(/usr/local/texlive/2022/texmf-dist/tex/generic/iftex/iftex.sty +Package: iftex 2022/02/03 v1.0f TeX engine tests +)) +\Gm@cnth=\count271 +\Gm@cntv=\count272 +\c@Gm@tempcnt=\count273 +\Gm@bindingoffset=\dimen150 +\Gm@wd@mp=\dimen151 +\Gm@odd@mp=\dimen152 +\Gm@even@mp=\dimen153 +\Gm@layoutwidth=\dimen154 +\Gm@layoutheight=\dimen155 +\Gm@layouthoffset=\dimen156 +\Gm@layoutvoffset=\dimen157 +\Gm@dimlist=\toks28 +) +(/usr/local/texlive/2022/texmf-dist/tex/latex/booktabs/booktabs.sty +Package: booktabs 2020/01/12 v1.61803398 Publication quality tables +\heavyrulewidth=\dimen158 +\lightrulewidth=\dimen159 +\cmidrulewidth=\dimen160 +\belowrulesep=\dimen161 +\belowbottomsep=\dimen162 +\aboverulesep=\dimen163 +\abovetopsep=\dimen164 +\cmidrulesep=\dimen165 +\cmidrulekern=\dimen166 +\defaultaddspace=\dimen167 +\@cmidla=\count274 +\@cmidlb=\count275 +\@aboverulesep=\dimen168 +\@belowrulesep=\dimen169 +\@thisruleclass=\count276 +\@lastruleclass=\count277 +\@thisrulewidth=\dimen170 +) +(/usr/local/texlive/2022/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def +File: l3backend-pdftex.def 2022-02-07 L3 backend support: PDF output (pdfTeX) +\l__color_backend_stack_int=\count278 +\l__pdf_internal_box=\box52 +) +No file boundary_restriction_structure.aux. +\openout1 = `boundary_restriction_structure.aux'. + +LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 18. +LaTeX Font Info: ... okay on input line 18. +LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 18. +LaTeX Font Info: ... okay on input line 18. +LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 18. +LaTeX Font Info: ... okay on input line 18. +LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 18. +LaTeX Font Info: ... okay on input line 18. +LaTeX Font Info: Checking defaults for TS1/cmr/m/n on input line 18. +LaTeX Font Info: ... okay on input line 18. +LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 18. +LaTeX Font Info: ... okay on input line 18. +LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 18. +LaTeX Font Info: ... okay on input line 18. +(/usr/local/texlive/2022/texmf-dist/tex/context/base/mkii/supp-pdf.mkii +[Loading MPS to PDF converter (version 2006.09.02).] +\scratchcounter=\count279 +\scratchdimen=\dimen171 +\scratchbox=\box53 +\nofMPsegments=\count280 +\nofMParguments=\count281 +\everyMPshowfont=\toks29 +\MPscratchCnt=\count282 +\MPscratchDim=\dimen172 +\MPnumerator=\count283 +\makeMPintoPDFobject=\count284 +\everyMPtoPDFconversion=\toks30 +) (/usr/local/texlive/2022/texmf-dist/tex/latex/epstopdf-pkg/epstopdf-base.sty +Package: epstopdf-base 2020-01-24 v2.11 Base part for package epstopdf +Package epstopdf-base Info: Redefining graphics rule for `.eps' on input line 4 +85. + +(/usr/local/texlive/2022/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg +File: epstopdf-sys.cfg 2010/07/13 v1.3 Configuration of (r)epstopdf for TeX Liv +e +)) +*geometry* driver: auto-detecting +*geometry* detected driver: pdftex +*geometry* verbose mode - [ preamble ] result: +* driver: pdftex +* paper: +* layout: +* layoutoffset:(h,v)=(0.0pt,0.0pt) +* modes: +* h-part:(L,W,R)=(72.26999pt, 469.75502pt, 72.26999pt) +* v-part:(T,H,B)=(72.26999pt, 650.43001pt, 72.26999pt) +* \paperwidth=614.295pt +* \paperheight=794.96999pt +* \textwidth=469.75502pt +* \textheight=650.43001pt +* \oddsidemargin=0.0pt +* \evensidemargin=0.0pt +* \topmargin=-37.0pt +* \headheight=12.0pt +* \headsep=25.0pt +* \topskip=11.0pt +* \footskip=30.0pt +* \marginparwidth=59.0pt +* \marginparsep=10.0pt +* \columnsep=10.0pt +* \skip\footins=10.0pt plus 4.0pt minus 2.0pt +* \hoffset=0.0pt +* \voffset=0.0pt +* \mag=1000 +* \@twocolumnfalse +* \@twosidefalse +* \@mparswitchfalse +* \@reversemarginfalse +* (1in=72.27pt=25.4mm, 1cm=28.453pt) + +LaTeX Font Info: Trying to load font information for U+msa on input line 19. + +(/usr/local/texlive/2022/texmf-dist/tex/latex/amsfonts/umsa.fd +File: umsa.fd 2013/01/14 v3.01 AMS symbols A +) +LaTeX Font Info: Trying to load font information for U+msb on input line 19. + + +(/usr/local/texlive/2022/texmf-dist/tex/latex/amsfonts/umsb.fd +File: umsb.fd 2013/01/14 v3.01 AMS symbols B +) [1 + +{/usr/local/texlive/2022/texmf-var/fonts/map/pdftex/updmap/pdftex.map}] [2] +(./boundary_restriction_structure.aux) ) +Here is how much of TeX's memory you used: + 3254 strings out of 478268 + 48506 string characters out of 5846347 + 347668 words of memory out of 5000000 + 21442 multiletter control sequences out of 15000+600000 + 480359 words of font info for 70 fonts, out of 8000000 for 9000 + 1141 hyphenation exceptions out of 8191 + 55i,8n,62p,247b,208s stack positions out of 10000i,1000n,20000p,200000b,200000s + +Output written on boundary_restriction_structure.pdf (2 pages, 184212 bytes). +PDF statistics: + 91 PDF objects out of 1000 (max. 8388607) + 54 compressed objects within 1 object stream + 0 named destinations out of 1000 (max. 500000) + 1 words of extra memory for PDF output out of 10000 (max. 10000000) + diff --git a/papers/heawood_restrictions_on_nested_tire_graph_duals/notes/boundary_restriction_structure.pdf b/papers/heawood_restrictions_on_nested_tire_graph_duals/notes/boundary_restriction_structure.pdf new file mode 100644 index 0000000..4e4fd3f Binary files /dev/null and b/papers/heawood_restrictions_on_nested_tire_graph_duals/notes/boundary_restriction_structure.pdf differ diff --git a/papers/heawood_restrictions_on_nested_tire_graph_duals/notes/boundary_restriction_structure.tex b/papers/heawood_restrictions_on_nested_tire_graph_duals/notes/boundary_restriction_structure.tex new file mode 100644 index 0000000..4e13a20 --- /dev/null +++ b/papers/heawood_restrictions_on_nested_tire_graph_duals/notes/boundary_restriction_structure.tex @@ -0,0 +1,139 @@ +\documentclass[11pt]{article} +\usepackage{amsmath,amssymb,amsthm} +\usepackage{graphicx} +\usepackage{geometry} +\usepackage{booktabs} +\geometry{margin=1in} + +\title{Heawood boundary restriction sets:\\ +zonotope structure and the $2^{n-2}$ constraint floor} +\author{} +\date{} + +\newtheorem*{obs}{Observation} +\newtheorem*{prop}{Proposition} +\newtheorem*{conj}{Conjecture} +\newtheorem*{lem}{Lemma} + +\begin{document} +\maketitle + +This note records the empirical structure of the Heawood boundary +restriction sets studied in \texttt{paper.tex}, and a clean +\emph{maximal-constraint} result. All claims below are backed by the +experiments in \texttt{experiments/} (filenames given inline). Sequences +live in $(\mathbb{Z}/3)^{\,\cdot}$, displayed in $\{0,1,-1\}$. + +\section*{Setup} + +Fix a triangulated disk $D$ with boundary cycle $C = (v_0,\dots,v_{n-1})$. +A Heawood face-labelling is $\lambda : \{\text{faces of }D\} \to \{+1,-1\}$, +with induced vertex value $\lambda^{*}(v) = \sum_{f \ni v}\lambda(f) \bmod 3$. +The achievable outer set is +\[ + \Phi(D) \;=\; \bigl\{\, (\lambda^{*}(v_0),\dots,\lambda^{*}(v_{n-1})) + \;:\; \lambda \in \{+1,-1\}^{F(D)},\; + \lambda^{*}(w) \equiv 0 \ \forall\ \text{interior } w \,\bigr\}. +\] +This is exactly the value the recursive transfer operator produces at +$C$ (interior consistency $=$ all descendant gluings performed; boundary +deferred). Crucially $\Phi(D)$ depends \emph{only} on the disk +triangulation, not on any BFS/tire-tree labelling. + +\section*{1. The restriction sets are zonotopes, not subspaces} + +(\texttt{probe\_RK\_structure.py}.) Writing $\lambda = \mathbf{1}+b$ with +$b \in \{0,1\}^F$, the labelling map is $\lambda \mapsto M\mathbf{1}+Mb +\pmod 3$, a linear image of the Boolean cube ($M$ the face/vertex +incidence matrix). Over $3655$ cluster restriction sets $R_{\mathsf K}$: +none was an affine $\mathrm{GF}(3)$ subspace; the map is usually +injective, so $|R_{\mathsf K}| = 2^{|F|}$ (a power of $2$ inside the +column space of size $3^{\operatorname{rank} M}$); the nowhere-zero +constraint $\lambda \neq 0$ shrank the set below the full linear image in +\emph{every} case. The only surviving linear structure is +$R_{\mathsf K} \subseteq \operatorname{col}(M)$ (cokernel relations such +as $\sum_v \lambda^{*}(v) \equiv 0$). So $\Phi$ is a $\mathbb{Z}/3$ +zonotope: a projected cube, sign-closed but not closed under addition. + +\section*{2. ``Richness'' is not a self-similar invariant} + +(\texttt{transfer\_operator.py}, \texttt{branch\_invariant.py}.) In a +homogeneous same-$n$ spoke-only chain the operator saturates: $\Phi$ has +full single-position marginals (every interface vertex independently +attains all of $\{0,1,-1\}$), and the alternating tire reaches the +\emph{entire} space $3^n$. This is an artifact of non-shrinking annuli +with no interior constraints. On genuine triangulations the marginal +fullness holds for only ${\sim}8\%$ of regions: depth (not branching) +shrinks $\Phi$, e.g.\ a region with $|C|=10$ realised only $|\Phi|=400$ +of $3^{10}\approx 59000$. Only non-emptiness and sign-closure survive, +both of which are automatic / equivalent to $4$CT. Hence no abundance +(counting) pigeonhole: a working invariant must tolerate \emph{small} +$\Phi$. + +\section*{3. The maximal-constraint floor} + +(\texttt{maximally\_constrain.py}.) Minimising $|\Phi(D)|$ over disks with +a fixed boundary $n$-cycle: + +\begin{center} +\begin{tabular}{ccccc} +\toprule +$n$ & $4$ & $5$ & $6$ & $7$\\ +\midrule +$\min |\Phi|$ (search) & $4$ & $8$ & $16$ & $32$\\ +fan, $0$ interior vertices & $4$ & $8$ & $16$ & $32$\\ +$2^{\,n-2}$ & $4$ & $8$ & $16$ & $32$\\ +\bottomrule +\end{tabular} +\end{center} + +A search over random and deep-stacked disks (up to $8$ interior vertices) +never beat $2^{n-2}$, and the interior-free triangulation already +attains it. Thus: + +\begin{obs} +The outer $n$-cycle cannot be constrained below $2^{n-2}$ achievable +sequences, and no nested structure is needed to reach the floor: a single +trivial tire is already maximal. Deep nesting only approaches the floor +from above. +\end{obs} + +The achievability is transparent: in a fan from $v_0$, +\[ + \sigma_1 = \lambda_1,\quad + \sigma_i = \lambda_{i-1}+\lambda_i \ (1