Plot the n=12 size-7 universal breaker tile
Add plot_breaker_tile.py and figure for word=UUUDUDUDUDUD bite=(3,11): structure (7 up teeth = size-7 outer rim, bite (3,11), singleton downs d5,d7,d9) plus a Kempe-balanced colouring. Reconfirms the outer rim realises 9/10 admissible size-7 necklaces, never 0001112 -- the lone tile that empties the size-7 universal at n=12. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
BIN
Binary file not shown.
BIN
Binary file not shown.
|
After Width: | Height: | Size: 160 KiB |
+138
@@ -0,0 +1,138 @@
|
||||
"""Plot the n=12 size-7 universal breaker tile: word=UUUDUDUDUDUD, bite=(3,11).
|
||||
|
||||
Left panel: structure (7 up teeth = the size-7 outer rim, ringed; the bite (3,11);
|
||||
the singleton down teeth). Right panel: a Kempe-balanced colouring, with the outer
|
||||
rim necklace it presents. This tile's outer rim realises 9 of the 10 admissible
|
||||
size-7 necklaces but never 0001112, which is why it alone empties the size-7
|
||||
universal at n=12.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
import os
|
||||
|
||||
from full_medial_tire_generator import FullMedialTireGraph
|
||||
from kempe_valid_colorings import classify_colorings
|
||||
from kempe_up_tooth_sequences import PALETTE, _positions, canonical_sequence, seq_str
|
||||
from kempe_transfer_relation_probe import necklace
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
WORD = "UUUDUDUDUDUD"
|
||||
BITE = frozenset({(3, 11)})
|
||||
N = 12
|
||||
TYPE_COLOR = {"a": "#999999", "u": "#e6550d", "d": "#31a354", "p": "#756bb1"}
|
||||
|
||||
|
||||
def vtype(v):
|
||||
return v[0]
|
||||
|
||||
|
||||
def draw_structure(ax, g):
|
||||
pos = _positions(g)
|
||||
for u, v in g.edges():
|
||||
ax.plot([pos[u][0], pos[v][0]], [pos[u][1], pos[v][1]],
|
||||
color="#cccccc", lw=0.6, zorder=1)
|
||||
for k in range(g.n):
|
||||
a, b = f"a{k}", f"a{(k + 1) % g.n}"
|
||||
ax.plot([pos[a][0], pos[b][0]], [pos[a][1], pos[b][1]],
|
||||
color="#555555", lw=1.2, zorder=2)
|
||||
# highlight the bite spokes
|
||||
for i, j in g.bites:
|
||||
apex = f"p{i}_{j}"
|
||||
for e in (i, j):
|
||||
for av in (f"a{e}", f"a{(e + 1) % g.n}"):
|
||||
ax.plot([pos[apex][0], pos[av][0]], [pos[apex][1], pos[av][1]],
|
||||
color="#756bb1", lw=1.6, zorder=2.5)
|
||||
for v, (x, y) in pos.items():
|
||||
t = vtype(v)
|
||||
s = 90 if t in ("u", "p") else 60
|
||||
ax.scatter([x], [y], s=s, color=TYPE_COLOR[t], edgecolors="black",
|
||||
linewidths=0.6, zorder=3)
|
||||
# ring the up-tooth apexes (the size-7 outer rim / boundary)
|
||||
ux = [pos[f"u{i}"][0] for i in g.up_edges]
|
||||
uy = [pos[f"u{i}"][1] for i in g.up_edges]
|
||||
ax.scatter(ux, uy, s=240, facecolors="none", edgecolors="#d62728",
|
||||
linewidths=1.8, zorder=4)
|
||||
# label up apexes in boundary order 0..6
|
||||
for k, i in enumerate(g.up_edges):
|
||||
x, y = pos[f"u{i}"]
|
||||
ax.annotate(str(k), (x, y), textcoords="offset points", xytext=(0, 9),
|
||||
ha="center", fontsize=7, color="#d62728")
|
||||
ax.set_xlim(-1.7, 1.7)
|
||||
ax.set_ylim(-1.9, 1.7)
|
||||
ax.set_aspect("equal")
|
||||
ax.axis("off")
|
||||
ax.set_title("structure: 7 up teeth (red-ringed = size-7 outer rim)\n"
|
||||
"bite (3,11) in purple; singleton down teeth d5,d7,d9",
|
||||
fontsize=8)
|
||||
|
||||
|
||||
def draw_colored(ax, g, coloring):
|
||||
pos = _positions(g)
|
||||
for u, v in g.edges():
|
||||
ax.plot([pos[u][0], pos[v][0]], [pos[u][1], pos[v][1]],
|
||||
color="#cccccc", lw=0.6, zorder=1)
|
||||
for k in range(g.n):
|
||||
a, b = f"a{k}", f"a{(k + 1) % g.n}"
|
||||
ax.plot([pos[a][0], pos[b][0]], [pos[a][1], pos[b][1]],
|
||||
color="#555555", lw=1.2, zorder=2)
|
||||
for v, (x, y) in pos.items():
|
||||
is_bite = v.startswith("p")
|
||||
ax.scatter([x], [y], s=80 if is_bite else 55, color=PALETTE[coloring[v]],
|
||||
edgecolors="black", linewidths=0.5, zorder=3)
|
||||
ux = [pos[f"u{i}"][0] for i in g.up_edges]
|
||||
uy = [pos[f"u{i}"][1] for i in g.up_edges]
|
||||
ax.scatter(ux, uy, s=240, facecolors="none", edgecolors="#222222",
|
||||
linewidths=1.6, zorder=4)
|
||||
raw = seq_str(tuple(coloring[f"u{i}"] for i in g.up_edges))
|
||||
neck = seq_str(necklace(tuple(coloring[f"u{i}"] for i in g.up_edges)))
|
||||
ax.set_xlim(-1.7, 1.7)
|
||||
ax.set_ylim(-1.9, 1.7)
|
||||
ax.set_aspect("equal")
|
||||
ax.axis("off")
|
||||
ax.set_title(f"a Kempe-balanced colouring\nouter rim = {raw} → necklace {neck}",
|
||||
fontsize=8)
|
||||
|
||||
|
||||
def main():
|
||||
import matplotlib
|
||||
matplotlib.use("Agg")
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
g = FullMedialTireGraph(n=N, tooth_word=WORD, bites=BITE)
|
||||
|
||||
# confirm: outer rim realises 9/10 admissible necklaces, never 0001112
|
||||
realized = set()
|
||||
sample = None
|
||||
for c, v in classify_colorings(g, dedup_colors=True):
|
||||
if not v.valid:
|
||||
continue
|
||||
nk = necklace(tuple(c[f"u{i}"] for i in g.up_edges))
|
||||
realized.add(nk)
|
||||
if sample is None:
|
||||
sample = c
|
||||
target = necklace(tuple(map(int, "0001112")))
|
||||
print(f"breaker {WORD} bite (3,11): outer rim realises {len(realized)} necklaces")
|
||||
print(f" contains 0001112? {target in realized} (expect False)")
|
||||
|
||||
fig, axes = plt.subplots(1, 2, figsize=(10, 5.4))
|
||||
draw_structure(axes[0], g)
|
||||
draw_colored(axes[1], g, sample)
|
||||
fig.suptitle(
|
||||
"Size-7 universal breaker (n=12): word=UUUDUDUDUDUD, bite=(3,11)\n"
|
||||
"outer rim realises 9 of 10 admissible size-7 necklaces — never 0001112",
|
||||
fontsize=11, y=0.99,
|
||||
)
|
||||
fig.tight_layout(rect=(0, 0, 1, 0.93))
|
||||
png = os.path.join(HERE, "breaker_tile_n12.png")
|
||||
pdf = os.path.join(HERE, "breaker_tile_n12.pdf")
|
||||
fig.savefig(png, dpi=200)
|
||||
fig.savefig(pdf)
|
||||
print(f"wrote {png}")
|
||||
print(f"wrote {pdf}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user