From aecbc5ed2898389bbc8a60067d04719f5bfb13a9 Mon Sep 17 00:00:00 2001 From: didericis Date: Thu, 11 Jun 2026 22:52:38 -0400 Subject: [PATCH] Add tile-overlap probe: per-tile interface subsets always glue Each tile realises only a subset of the parity-admissible alphabet on its rim, and tiles genuinely omit interfaces (n=12 m=8: max 273/274, min 43). But any two tiles always glue: interface subsets always overlap (n=9 m=3-6, n=12 m=3-8) -- usually via a global universal seam present on every inner+outer rim, and where none exists (n=12 m=7) the worst pair still shares 14 seams. The universal seams are the low-complexity ones (<=2 colours, single contiguous block). No local gluing obstruction; any obstruction must be global across a nested stack. Co-Authored-By: Claude Opus 4.8 --- .../experiments/kempe_tile_overlap_probe.py | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 papers/medial_tire_decompositions_of_plane_triangulations/experiments/kempe_tile_overlap_probe.py diff --git a/papers/medial_tire_decompositions_of_plane_triangulations/experiments/kempe_tile_overlap_probe.py b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/kempe_tile_overlap_probe.py new file mode 100644 index 0000000..06ffa30 --- /dev/null +++ b/papers/medial_tire_decompositions_of_plane_triangulations/experiments/kempe_tile_overlap_probe.py @@ -0,0 +1,131 @@ +"""Per-tile interface subsets and gluing overlap. + +The achievable interface alphabet for size m is the full parity-admissible set +(see kempe_interface_admissibility_probe.py). But each individual tile realizes +only a SUBSET of it on its rim. Gluing tile A inside tile B along an m-seam +needs A's outer-rim subset and B's inner-face subset to share a common sequence +(census sets are already orientation-closed, so plain set intersection is the +right test). + +For each n and interface size m this reports, separately for outer (up-tooth) +and inner (down-face) interfaces: + * subset-size distribution (how much of the alphabet each tile realizes); + * number of distinct subsets (= gluing "signatures"); + * the universal sequences (in EVERY tile's subset) for up, for down, and the + global universal (in every up AND every down subset -- a seam any inner tile + can use inside any outer tile); + * whether every (inner up-rim, outer down-face) pair overlaps -- i.e. can any + two tiles be glued at this seam size -- and the worst (smallest-overlap) pair. + +Summary numbers only. + +Run: python3 kempe_tile_overlap_probe.py --n 9 --m 3 4 5 6 +""" + +from __future__ import annotations + +import argparse +import statistics +import sys +import time +from collections import defaultdict + +from full_medial_tire_generator import generate, innermost_bite +from kempe_valid_colorings import classify_colorings +from kempe_interface_admissibility_probe import admissible_sequences +from kempe_up_tooth_sequences import dihedral_reading_sequences, seq_str + + +def collect(n: int, m: int): + """Per-tile up-subsets and down-subsets (census sequence sets) for size m.""" + up_subsets: list[frozenset] = [] + down_subsets: list[frozenset] = [] + for g in generate(n, min_up_teeth=3, dedup=True): + do_up = len(g.up_edges) == m + faces = defaultdict(list) + for e in g.singleton_down_edges: + faces[innermost_bite(e, g.bites)].append(e) + down_faces = [sorted(es) for es in faces.values() if len(es) == m] + if not do_up and not down_faces: + continue + valid = [c for c, v in classify_colorings(g, dedup_colors=True) if v.valid] + if do_up: + s: set = set() + for c in valid: + s |= dihedral_reading_sequences(n, c, g.up_edges, "u") + up_subsets.append(frozenset(s)) + for edges in down_faces: + s = set() + for c in valid: + s |= dihedral_reading_sequences(n, c, edges, "d") + down_subsets.append(frozenset(s)) + return up_subsets, down_subsets + + +def min_pairwise_overlap(ups, downs): + """Smallest |U ∩ D| over all (up, down) pairs, and a witnessing pair size.""" + worst = None + for u in ups: + for d in downs: + k = len(u & d) + if worst is None or k < worst: + worst = k + if worst == 0: + return 0 + return worst if worst is not None else None + + +def describe(label, subsets, adm): + sizes = sorted(len(s) for s in subsets) + universal = frozenset.intersection(*subsets) if subsets else frozenset() + n_full = sum(1 for s in subsets if len(s) == len(adm)) + sigs = len(set(subsets)) + return { + "n": len(subsets), + "min": sizes[0] if sizes else 0, + "med": int(statistics.median(sizes)) if sizes else 0, + "max": sizes[-1] if sizes else 0, + "sigs": sigs, + "universal": universal, + "n_full": n_full, + } + + +def run(args): + n = args.n + print(f"n={n}: per-tile interface subsets and gluing overlap\n") + for m in args.m: + t0 = time.time() + adm = admissible_sequences(m) + ups, downs = collect(n, m) + u = describe("up", ups, adm) + d = describe("down", downs, adm) + gu = (frozenset.intersection(*ups) if ups else frozenset()) & \ + (frozenset.intersection(*downs) if downs else frozenset()) + # can any inner tile glue inside any outer tile? + if gu: + glue = f"yes (global universal {sorted(seq_str(x) for x in gu)})" + else: + mo = min_pairwise_overlap(ups, downs) + glue = f"{'yes' if mo and mo > 0 else 'NO'} (min up×down overlap = {mo})" + dt = time.time() - t0 + print(f"m={m} |adm|={len(adm)}") + print(f" up : {u['n']:>4} tiles subset size {u['min']}..{u['med']}..{u['max']}" + f" ({u['n_full']} realise all) {u['sigs']} signatures" + f" universal={sorted(seq_str(x) for x in u['universal'])}") + print(f" down : {d['n']:>4} tiles subset size {d['min']}..{d['med']}..{d['max']}" + f" ({d['n_full']} realise all) {d['sigs']} signatures" + f" universal={sorted(seq_str(x) for x in d['universal'])}") + print(f" glue-any-pair: {glue} ({dt:.0f}s)\n") + sys.stdout.flush() + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--n", type=int, default=9) + parser.add_argument("--m", type=int, nargs="+", default=[3, 4, 5, 6]) + run(parser.parse_args()) + + +if __name__ == "__main__": + main()