Draw the minimal failing graph with a verified planar embedding

draw_failing_graph.py renders seed2 #26 (ring [3,6,3]+face leaf, 12 vertices),
the smallest graph the programme fails on after exhausting sites x tread-phases x
root colour-orders. Uses networkx planar_layout for a straight-line embedding and
verifies no two non-incident edges cross before drawing. Panel A: plain embedding;
panel B: BFS levels with the odd level-2 seam (the inner triangle 9-11-10) bold,
the terminal leaf face shaded -- the face-leaf/gadget spot where removal fails.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-13 00:09:42 -04:00
parent faf9e01139
commit e7e8536559
2 changed files with 145 additions and 0 deletions
@@ -0,0 +1,145 @@
"""Straight-line planar drawing of the minimal genuine obstruction found by the
even-level-cycle programme: the ring triangulation sizes=[3,6,3], leaf='face'
(generator random.Random(2), the 27th graph), 12 vertices. It survives
exhausting insertion sites x tread phases x root colour-orders (residue_phase_
sweep.py: 24 settings, 0 ok) and fails at the leaf-gadget removal step.
Embedding: networkx planar_layout (a canonical-ordering straight-line embedding
of a planar graph), recentred. We additionally VERIFY no two non-incident edges
cross before drawing. Every triangulation on >=4 vertices is 3-connected, so a
crossing-free straight-line embedding is guaranteed to exist.
"""
import os, random
import numpy as np
import networkx as nx
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon
import kempe_even_program_harness as H
HERE = os.path.dirname(os.path.abspath(__file__))
LEVCOL = {0: "#d9d9d9", 1: "#9ecae1", 2: "#fc9272"} # by BFS level
def reconstruct(seed, idx):
rng = random.Random(seed)
for _ in range(idx + 1):
sizes, leaf = H.random_profile(rng)
g, outer = H.ring_triangulation(sizes, leaf, rng)
return g, outer
def planar_pos(g):
nxg = nx.Graph()
nxg.add_nodes_from(g.rot)
for ed in g.edges():
a, b = tuple(ed); nxg.add_edge(a, b)
ok, _ = nx.check_planarity(nxg)
assert ok, "graph is not planar?!"
pos = nx.planar_layout(nxg)
pts = np.array([pos[v] for v in g.rot])
c = pts.mean(axis=0); s = np.abs(pts - c).max()
return {v: ((pos[v][0] - c[0]) / s, (pos[v][1] - c[1]) / s) for v in g.rot}
def seg_cross(p, q, r, s):
def o(a, b, c):
return (b[0]-a[0])*(c[1]-a[1]) - (b[1]-a[1])*(c[0]-a[0])
d1, d2, d3, d4 = o(r, s, p), o(r, s, q), o(p, q, r), o(p, q, s)
return ((d1 > 0) != (d2 > 0)) and ((d3 > 0) != (d4 > 0))
def verify_planar(g, pos):
edges = [tuple(e) for e in g.edges()]
bad = []
for i in range(len(edges)):
a, b = edges[i]
for j in range(i + 1, len(edges)):
c, d = edges[j]
if len({a, b, c, d}) < 4:
continue
if seg_cross(pos[a], pos[b], pos[c], pos[d]):
bad.append((edges[i], edges[j]))
return bad
g, outer = reconstruct(2, 26)
g.check()
an = H.Analysis(g.copy(), outer)
pos = planar_pos(g)
bad = verify_planar(g, pos)
print("crossing edge-pairs:", bad if bad else "NONE -- valid straight-line planar embedding")
assert not bad, "embedding has crossings"
terminal = tuple(an.terminal[0])
odd_seam = [c for k, c in an.seams if len(c) % 2][0]
faces = [tuple(f) for f in g.faces()]
outer_set = frozenset(outer)
fig, axes = plt.subplots(1, 2, figsize=(13.5, 6.8))
xs = [p[0] for p in pos.values()]; ys = [p[1] for p in pos.values()]
mx = max(abs(min(xs)), abs(max(xs))); my = max(abs(min(ys)), abs(max(ys)))
for ax in axes:
ax.set_aspect("equal"); ax.axis("off")
ax.set_xlim(-mx - 0.25, mx + 0.25); ax.set_ylim(-my - 0.25, my + 0.35)
def draw_faces(ax):
for f in faces:
if frozenset(f) == outer_set:
continue
ax.add_patch(Polygon([pos[v] for v in f], closed=True,
facecolor="#fbfbfb", edgecolor="none", zorder=0))
def draw_edges(ax, bold=None):
bold = bold or set()
for ed in g.edges():
a, b = tuple(ed)
hot = frozenset((a, b)) in bold
ax.plot([pos[a][0], pos[b][0]], [pos[a][1], pos[b][1]],
color="#cc2222" if hot else "#7a7a7a",
lw=2.8 if hot else 1.1, zorder=2)
def draw_verts(ax, by_level=False):
for v, p in pos.items():
fc = LEVCOL[an.level[v]] if by_level else "white"
ax.plot(*p, "o", ms=20, mfc=fc, mec="#222222", mew=1.6, zorder=4)
ax.annotate(str(v), p, ha="center", va="center", fontsize=10,
fontweight="bold", zorder=5)
draw_faces(axes[0]); draw_edges(axes[0]); draw_verts(axes[0])
axes[0].set_title("A. ring [3,6,3] + face leaf, 12 vertices\n"
"straight-line planar embedding (verified crossing-free)",
fontsize=10)
draw_faces(axes[1])
seam_edges = {frozenset((odd_seam[i], odd_seam[(i+1) % len(odd_seam)]))
for i in range(len(odd_seam))}
axes[1].add_patch(Polygon([pos[v] for v in terminal], closed=True,
facecolor="#fee0d2", edgecolor="none", zorder=1))
draw_edges(axes[1], bold=seam_edges)
draw_verts(axes[1], by_level=True)
tc = np.mean([pos[v] for v in terminal], axis=0)
axes[1].annotate("terminal triangle " + "-".join(map(str, terminal)) +
"\n(level-2 odd seam; carries the leaf\ngadget whose removal "
"STILL FAILS)",
xy=tc, xytext=(0.02, 0.99), textcoords="axes fraction",
ha="left", va="top", fontsize=8, color="#a63603",
arrowprops=dict(arrowstyle="->", color="#a63603", lw=1.2),
zorder=6)
axes[1].set_title("B. BFS levels from source 0-1-2 "
"(grey 0 / blue 1 / red 2)\nodd level-2 seam "
+ "-".join(map(str, odd_seam)) + " bold red",
fontsize=10)
fig.suptitle("Minimal genuine obstruction (seed2 #26): the programme fails here "
"even after exhausting\nsites x tread-phases x root colour-orders "
"(24 settings, 0 ok) -- a face-leaf / gadget case.", fontsize=10)
fig.tight_layout(rect=(0, 0, 1, 0.9))
out = os.path.join(HERE, "failing_graph_seed2_26.png")
fig.savefig(out, dpi=160)
print("wrote", out)
Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB