Add medial tire cut experiment and chaining section

New experiments/run_medial_tire_cut_experiment.py: generates a random
maximal planar graph (stacked seed + random diagonal flips), builds the
medial graph, takes the tire decomposition at a random vertex level
source, walk-depth labels and cuts each full medial tire graph chained
down the tire tree, and assembles one final cut graph of M(G) with a
global label map (data only; graphics go in a separate script).

Fix label_and_cut: the root face is None, which collided with the
next(..., None) sentinel, leaving teeth unlabelled when the entry up
tooth lay inside a bite gap; use a distinct sentinel so the ascent to
the root face runs.

Add a "Chaining across the tire tree" section to the paper, clarifying
that the candidate parent down teeth are the boundary (singleton) down
teeth only -- bite teeth are interior to the parent and shared with no
child, so a lower-walk bite is skipped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-14 23:46:49 -04:00
parent b4ddc7da8b
commit a22ca4b888
6 changed files with 388 additions and 33 deletions
@@ -179,7 +179,9 @@ def label_and_cut(graph: FullMedialTireGraph, entry_edge: int,
# Steps 1-3: the entry face.
traverse(innermost_bite(entry_edge, graph.bites), entry_edge, is_entry=True)
# Steps 4-6: descend through bites, deepest first.
# Steps 4-6: descend (or ascend) through bites, deepest first. The root
# face is ``None``, so we use a distinct sentinel for "no unlabelled face".
_MISSING = object()
while len(depth) < graph.n:
labelled_bite_teeth = sorted(
(e for e in depth if door_bite(graph, e) is not None),
@@ -188,8 +190,8 @@ def label_and_cut(graph: FullMedialTireGraph, entry_edge: int,
for t in labelled_bite_teeth:
target = next((F for F in faces_bordered(graph, t)
if any(e not in depth for e in face_boundary(graph, F))),
None)
if target is not None:
_MISSING)
if target is not _MISSING:
traverse(target, t, is_entry=False)
break
else: