Compare commits

...

8 Commits

Author SHA1 Message Date
didericis 94d59ceaed Relabel medial comparison plots by walk depth 2026-06-15 02:11:27 -04:00
didericis 24af5485d2 Add medial cut comparison plots 2026-06-15 01:47:23 -04:00
didericis ea1ab0b986 Add source cap cut to medial tire figures 2026-06-15 01:11:04 -04:00
didericis c64c720e5a Draw the whole medial graph with all tire cuts
Add a --whole mode to draw_medial_tire_cut.py that renders the entire
medial graph M(G) (the assembled cut graph), on a Kamada-Kawai layout,
with the recognised tires highlighted (black annular vertices, blue/red
teeth carrying walk depths, larger red bite apex) and the rest of M(G)
in grey. Add the resulting figure (Figure 3) and a describing paragraph
to the paper for the n=20 seed-72 example, via an \input-ed .tikz file.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 00:07:00 -04:00
didericis 9d7cb7644e Draw a medial tire cut from a random n=20 graph
Add experiments/draw_medial_tire_cut.py, the paper-graphics companion
that imports run_experiment and emits a TikZ panel (walk-depth labels +
cut slits) per recognised tread via to_tikz. Add the resulting figure
(Example 3.2, Figure 2): the single recognised tread T_2 of the medial
tire decomposition of a random maximal planar graph on 20 vertices
(seed 72), an 8-cycle piece with a bite, labelled and cut.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 23:55:00 -04:00
didericis a22ca4b888 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>
2026-06-14 23:46:49 -04:00
didericis b4ddc7da8b Add walk-depth labelling/cut script and worked example
New experiments/medial_tire_cut_labelling.py: takes a full medial tire
graph and an entry up tooth and runs the walk-depth labelling-and-cut
procedure, reusing the full medial tire generator's model and emitting
TikZ. Add a generator-produced 8-tooth example to the paper (Figure 1,
Example 2.3) showing the labelling and the two cuts, plus a remark
fixing the cut's closing tooth for descended faces.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 22:00:52 -04:00
didericis 291f7e98c7 Add Medial Tire Cuts paper with walk-depth labelling and cut
New paper "Medial Tire Cuts" citing the medial tire decompositions
paper. States the goal of decomposing the medial graph into a tree of
3-faces, and gives the walk-depth labelling-and-cut procedure for a
single full medial tire graph: a cut duplicates the annular vertex
where a face's tooth traversal closes (planar unzip), reducing the
inner faces to teeth.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 21:39:03 -04:00
12 changed files with 2873 additions and 0 deletions
@@ -0,0 +1,286 @@
"""Draw the walk-depth labelling and cut of a medial tire decomposition.
Paper-graphics companion to ``run_medial_tire_cut_experiment.py``: it imports
``run_experiment`` from there, runs the pipeline on a random maximal planar
graph, and emits TikZ. By default it draws one ``tikzpicture`` (walk-depth
labels + cut slits) per recognised full medial tire graph, using ``to_tikz``
from ``medial_tire_cut_labelling``. With ``--whole`` it instead draws a
two-panel Figure 3 graphic: the source graph with its source highlighted and
the whole medial graph M(G) drawn with every medial vertex at the midpoint of
its source edge and labelled by that source edge, with the full BFS-level chain
shown and the currently computed walk-depth labels and cuts marked.
This script only renders; the experiment itself draws nothing. Run with the
repo venv (networkx): ``.venv/bin/python``.
Examples:
.venv/bin/python draw_medial_tire_cut.py -n 20 --seed 59 > panels.tex
.venv/bin/python draw_medial_tire_cut.py -n 20 --seed 59 --whole > whole.tex
"""
from __future__ import annotations
import argparse
import math
import os
import sys
import networkx as nx
import numpy as np
_HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, _HERE)
from run_medial_tire_cut_experiment import run_experiment # noqa: E402
from medial_tire_cut_labelling import to_tikz # noqa: E402
from tire_realization_analysis import triangular_faces # noqa: E402
def tikz_panels(n: int, seed: int, scale: float = 1.6,
min_degree: int = 5, attempts: int = 1000) -> tuple[dict, list[str]]:
"""Run the experiment and return ``(result, panels)``, one TikZ panel per
recognised tread, each showing that tread's walk-depth labelling and cut."""
result = run_experiment(n=n, seed=seed, min_degree=min_degree, attempts=attempts)
panels = []
for d in sorted(result["results"]):
rec = result["results"][d]
panels.append(to_tikz(rec["g"], depth=rec["depth"], cuts=rec["cuts"],
entry_edge=rec["entry_edge"], scale=scale))
return result, panels
# --------------------------------------------------------------------------- #
# Figure 3: the source graph and midpoint drawing of the whole medial graph.
# --------------------------------------------------------------------------- #
def _source_layout(G: nx.Graph) -> dict[int, tuple[float, float]]:
"""Straight-line planar layout for the source graph, normalised to the unit
box and reused by the medial drawing."""
faces, _ = triangular_faces(G)
outer = list(faces[0])
outer_set = set(outer)
raw = {}
for i, v in enumerate(outer):
angle = math.radians(90.0 - i * 360.0 / len(outer))
raw[v] = np.array([math.cos(angle), math.sin(angle)], dtype=float)
inner = [v for v in sorted(G.nodes()) if v not in outer_set]
if inner:
idx = {v: i for i, v in enumerate(inner)}
n = len(inner)
A = np.zeros((n, n))
bx = np.zeros(n)
by = np.zeros(n)
for i, v in enumerate(inner):
nbrs = list(G.neighbors(v))
A[i, i] = 1.0
for w in nbrs:
if w in idx:
A[i, idx[w]] -= 1.0 / len(nbrs)
else:
bx[i] += raw[w][0] / len(nbrs)
by[i] += raw[w][1] / len(nbrs)
xs = np.linalg.solve(A, bx)
ys = np.linalg.solve(A, by)
for v in inner:
raw[v] = np.array([xs[idx[v]], ys[idx[v]]], dtype=float)
pts = np.array([raw[v] for v in G.nodes()], dtype=float)
center = 0.5 * (pts.max(axis=0) + pts.min(axis=0))
span = float(max(*(pts.max(axis=0) - pts.min(axis=0)), 1.0))
return {
v: tuple((raw[v] - center) / span)
for v in G.nodes()
}
def _edge_midpoint(pos: dict, edge) -> tuple[float, float]:
u, v = edge
ux, uy = pos[u]
vx, vy = pos[v]
return (0.5 * (ux + vx), 0.5 * (uy + vy))
def _edge_label(edge) -> str:
u, v = edge
return f"${u}\\!{{-}}\\!{v}$"
def _source_graph_tikz(result: dict, pos: dict, scale: float) -> str:
G, source = result["G"], result["source"]
L = []
A = L.append
A(f"\\begin{{tikzpicture}}[scale={scale},")
A(" sedge/.style={black!50, line width=0.35pt},")
A(" sv/.style={circle, draw=black!60, fill=white, inner sep=1.1pt},")
A(" srcv/.style={circle, draw=blue!75!black, fill=blue!18, line width=0.7pt, inner sep=1.8pt}]")
def pt(v):
x, y = pos[v]
return f"({x:.3f},{y:.3f})"
for u, v in sorted(G.edges()):
A(f"\\draw[sedge] {pt(u)}--{pt(v)};")
for v in sorted(G.nodes()):
style = "srcv" if v == source else "sv"
A(f"\\node[{style}] at {pt(v)} {{}};")
sx, sy = pos[source]
A(f"\\node[font=\\scriptsize, text=blue!70!black] at ({sx:.3f},{sy - 0.085:.3f}) {{source {source}}};")
A("\\end{tikzpicture}")
return "\n".join(L)
def _medial_midpoint_tikz(result: dict, pos: dict, scale: float) -> str:
"""Draw M(G) with each medial vertex at the midpoint of its source edge.
Every medial vertex is labelled by its source edge; same-level source edges
show the BFS level-chain tooth layers, and interlevel source edges show the
annular layers. Currently computed tire walk-depth labels and cut labels
are overlaid without moving the medial vertices away from their source
edges."""
G, M = result["G"], result["M"]
levels = nx.single_source_shortest_path_length(G, result["source"])
medial_pos = {edge: _edge_midpoint(pos, edge) for edge in M.nodes()}
apex_roles = {}
apex_walks = {}
for r in result["labels"]:
apex_roles[r["apex"]] = r["role"]
apex_walks.setdefault(r["apex"], []).append(r["walk"])
cut_records = []
cut_number = 1
for c in result.get("cap_cuts", []):
cut_records.append((cut_number, c["medial_vertex"], "cap", c))
cut_number += 1
for d in sorted(result["results"]):
rec = result["results"][d]
g, bij = rec["g"], rec["bij"]
for c in rec["cuts"]:
if c.vertex is None:
continue
cut_records.append((cut_number, bij[f"a{c.vertex}"], d, c))
cut_number += 1
L = []
A = L.append
A(f"\\begin{{tikzpicture}}[scale={scale},")
A(" base/.style={black!12, line width=0.25pt},")
A(" med/.style={black!38, line width=0.32pt},")
A(" annv/.style={circle, draw=black!70, fill=black!18, inner sep=1.0pt},")
A(" levone/.style={circle, draw=orange!75!black, fill=orange!20, inner sep=1.2pt},")
A(" levtwo/.style={circle, draw=violet!70!black, fill=violet!18, inner sep=1.2pt},")
A(" levthree/.style={circle, draw=teal!70!black, fill=teal!18, inner sep=1.2pt},")
A(" knownv/.style={circle, draw=red!70!black, fill=red!24, inner sep=1.5pt},")
A(" elbl/.style={font=\\tiny, text=black!70, inner sep=0.2pt},")
A(" dlbl/.style={font=\\tiny\\bfseries, text=black, inner sep=0.5pt},")
A(" cut/.style={red!80!black, line width=1.0pt},")
A(" cutlbl/.style={font=\\tiny, text=red!75!black}]")
def pt_med(edge):
x, y = medial_pos[edge]
return f"({x:.3f},{y:.3f})"
def pt_src(v):
x, y = pos[v]
return f"({x:.3f},{y:.3f})"
for u, v in sorted(result["G"].edges()):
A(f"\\draw[base] {pt_src(u)}--{pt_src(v)};")
for u, v in M.edges():
A(f"\\draw[med] {pt_med(u)}--{pt_med(v)};")
def chain_style(edge):
u, v = edge
lu, lv = levels[u], levels[v]
if lu != lv:
return "annv"
if edge in apex_roles:
return "knownv"
return {1: "levone", 2: "levtwo", 3: "levthree"}.get(lu, "annv")
for mv in sorted(M.nodes()):
A(f"\\node[{chain_style(mv)}] at {pt_med(mv)} {{}};")
for mv in sorted(M.nodes()):
x, y = medial_pos[mv]
A(f"\\node[elbl] at ({x:.3f},{y:.3f}) [yshift=-4.8pt] {{{_edge_label(mv)}}};")
for mv in sorted(apex_walks):
x, y = medial_pos[mv]
label = ",".join(str(w) for w in sorted(apex_walks[mv]))
A(f"\\node[dlbl] at ({x:.3f},{y:.3f}) [yshift=5.0pt] {{{label}}};")
for number, mv, _d, _cut in cut_records:
u, v = mv
ux, uy = pos[u]
vx, vy = pos[v]
mx, my = medial_pos[mv]
ex, ey = vx - ux, vy - uy
length = math.hypot(ex, ey) or 1.0
dx, dy = -0.035 * ey / length, 0.035 * ex / length
A(f"\\draw[cut] ({mx - dx:.3f},{my - dy:.3f})--({mx + dx:.3f},{my + dy:.3f});")
A(f"\\node[cutlbl] at ({mx + 2.4 * dx:.3f},{my + 2.4 * dy:.3f}) {{cut {number}}};")
A("\\end{tikzpicture}")
return "\n".join(L)
def medial_tikz(result: dict, scale: float = 7.0) -> str:
"""Two-panel TikZ for Figure 3: the source graph and the midpoint drawing of
its medial graph with all medial vertices labelled, plus the tire
walk-depth labels and cuts."""
pos = _source_layout(result["G"])
source = _source_graph_tikz(result, pos, scale=0.58 * scale)
medial = _medial_midpoint_tikz(result, pos, scale=scale)
return "\n".join([
"\\begin{tabular}{c}",
source,
"\\\\[-0.25ex]",
"{\\scriptsize source graph $G$}",
"\\\\[1.0ex]",
medial,
"\\\\[-0.25ex]",
"{\\scriptsize medial graph $M(G)$ at edge midpoints}",
"\\end{tabular}",
])
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("-n", type=int, default=20)
parser.add_argument("--seed", type=int, default=72)
parser.add_argument("--scale", type=float, default=1.6)
parser.add_argument("--min-degree", type=int, default=5,
help="reject random graphs below this minimum degree")
parser.add_argument("--attempts", type=int, default=1000,
help="number of consecutive seeds to try for --min-degree")
parser.add_argument("--whole", action="store_true",
help="draw the whole medial graph M(G) with all cuts, "
"instead of one panel per tread")
args = parser.parse_args()
if args.whole:
result = run_experiment(n=args.n, seed=args.seed,
min_degree=args.min_degree, attempts=args.attempts)
treads = sorted(result["results"])
print(f"% whole medial graph: n={args.n} seed={args.seed} "
f"graph_seed={result['graph_seed']} min_degree={result['min_degree']} "
f"source={result['source']} recognised treads={treads} "
f"|M(G)|={result['M'].number_of_nodes()}")
print(medial_tikz(result, scale=args.scale if args.scale != 1.6 else 7.0))
return
result, panels = tikz_panels(args.n, args.seed, scale=args.scale,
min_degree=args.min_degree, attempts=args.attempts)
treads = sorted(result["results"])
print(f"% medial tire cut: n={args.n} seed={args.seed} "
f"graph_seed={result['graph_seed']} min_degree={result['min_degree']} "
f"source={result['source']} recognised treads={treads}")
if not panels:
print("% (no recognised full medial tire graphs for this graph)")
for d, panel in zip(treads, panels):
g = result["results"][d]["g"]
print(f"% --- tread {d}: |A(T)|={g.n} word={g.tooth_word} "
f"bites={sorted(g.bites)} ---")
print(panel)
if __name__ == "__main__":
main()
@@ -0,0 +1,388 @@
"""Walk-depth labelling and cut of a full medial tire graph.
Implements the procedure of Definition 2.1 ("Walk-depth labelling and cut") of
the *Medial Tire Cuts* paper:
1. Pick an arbitrary up tooth, the entry tooth; it has walk depth d.
2. Traverse all teeth bounding the inner face incident to the entry tooth
clockwise until reaching the entry tooth, incrementing the walk depth by 1
for each tooth traversed.
3. On reaching the last tooth in the face, perform a cut by duplicating the
annular vertex at which the traversal closes (the annular vertex shared by
the last tooth and the closing tooth).
4. Find the tooth t of highest walk depth that is a member of a bite.
5. If t is incident to a face F with unlabelled teeth, traverse the teeth of F
starting from t in the direction of the unlabelled tooth incident to t
(sharing an annular vertex), incrementing the walk depth as you go.
6. Repeat steps 3-5 until all teeth are labelled.
The full medial tire graph model (annular cycle A(T), up/down teeth, bites, the
auxiliary plane graph B(T) and its inner faces) is the one from the companion
``full_medial_tire_generator.py`` of the medial tire decompositions paper, which
we import.
Teeth are identified with the annular edges that carry them: edge i sits on the
annular vertices a_i and a_{(i+1) mod n} and carries exactly one tooth. A bite
(i, j) carries two teeth, one on edge i and one on edge j, that share the bite
apex p. The inner non-tooth faces of B(T) are the root face (written ``None``)
and one inner-gap face per bite.
"""
from __future__ import annotations
import argparse
import math
import os
import sys
# Import the full medial tire model from the companion paper's experiments.
_GEN_DIR = os.path.normpath(os.path.join(
os.path.dirname(__file__), "..", "..",
"medial_tire_decompositions_of_plane_triangulations", "experiments",
))
sys.path.insert(0, _GEN_DIR)
from full_medial_tire_generator import ( # noqa: E402
FullMedialTireGraph,
has_incident_bite,
innermost_bite,
satisfies_bite_face_condition,
)
Face = "tuple[int, int] | None" # a bite (i, j), or None for the root face
# ---------------------------------------------------------------------------
# Face structure of B(T).
# ---------------------------------------------------------------------------
def parent_face(graph: FullMedialTireGraph, bite: tuple[int, int]) -> Face:
"""The face directly enclosing ``bite``: the minimal-span bite strictly
containing it, or the root face ``None``."""
i, j = bite
enclosing = [b for b in graph.bites if b[0] < i and b[1] > j]
if not enclosing:
return None
return min(enclosing, key=lambda b: b[1] - b[0])
def door_bite(graph: FullMedialTireGraph, edge: int) -> tuple[int, int] | None:
"""The bite that ``edge`` is a door of (i.e. a bite edge), or None."""
for b in graph.bites:
if edge in b:
return b
return None
def faces_bordered(graph: FullMedialTireGraph, edge: int) -> list[Face]:
"""The inner non-tooth faces whose boundary the tooth on ``edge`` lies on.
A bite door borders two faces (its bite's gap and that bite's parent); any
other tooth borders the single face directly containing its edge.
"""
bite = door_bite(graph, edge)
if bite is not None:
return [bite, parent_face(graph, bite)]
return [innermost_bite(edge, graph.bites)]
def face_boundary(graph: FullMedialTireGraph, face: Face) -> list[int]:
"""The teeth (annular edges) bounding ``face``, in clockwise cyclic order.
Clockwise is increasing edge index. For the root face the boundary is read
around the whole cycle; for a bite gap (i, j) it is read along the arc
i, i+1, ..., j and closes through the bite apex. Edges enclosed by a child
bite are skipped (they belong to the child's gap face).
"""
n = graph.n
arc = range(n) if face is None else range(face[0], face[1] + 1)
return [k for k in arc if face in faces_bordered(graph, k)]
def all_faces(graph: FullMedialTireGraph) -> list[Face]:
return [None] + sorted(graph.bites)
def shared_annular_vertex(graph: FullMedialTireGraph, e1: int, e2: int) -> int | None:
"""The annular vertex a_k shared by edges ``e1`` and ``e2``, or None."""
n = graph.n
common = {e1, (e1 + 1) % n} & {e2, (e2 + 1) % n}
return next(iter(common)) if common else None
# ---------------------------------------------------------------------------
# The walk-depth labelling and cut.
# ---------------------------------------------------------------------------
class Cut:
"""A cut performed when a face traversal closes: the duplicated annular
vertex, together with the last labelled tooth and the closing tooth that
share it, and the face being closed."""
__slots__ = ("vertex", "last_tooth", "closing_tooth", "face", "order")
def __init__(self, vertex, last_tooth, closing_tooth, face, order):
self.vertex = vertex
self.last_tooth = last_tooth
self.closing_tooth = closing_tooth
self.face = face
self.order = order
def __repr__(self):
f = "root" if self.face is None else f"bite{self.face}"
return (f"Cut(order={self.order}, a{self.vertex}, "
f"last=e{self.last_tooth}, closing=e{self.closing_tooth}, face={f})")
def label_and_cut(graph: FullMedialTireGraph, entry_edge: int,
start_depth: int = 0) -> tuple[dict[int, int], list[Cut]]:
"""Run the procedure starting from up tooth ``entry_edge``.
Returns ``(depth, cuts)`` where ``depth`` maps each annular edge (tooth) to
its walk depth, and ``cuts`` is the list of cuts in the order performed.
"""
if graph.tooth_word[entry_edge] != "U":
raise ValueError(f"entry edge {entry_edge} is not an up tooth")
depth: dict[int, int] = {}
cuts: list[Cut] = []
counter = start_depth
def traverse(face: Face, start_edge: int, is_entry: bool) -> None:
nonlocal counter
boundary = face_boundary(graph, face)
m = len(boundary)
pos = boundary.index(start_edge)
if is_entry:
depth[start_edge] = counter
counter += 1
direction = +1
else:
# head toward the unlabelled tooth incident to the door t
direction = +1 if boundary[(pos + 1) % m] not in depth else -1
last_new = start_edge
i = pos
while True:
i = (i + direction) % m
edge = boundary[i]
if edge in depth: # the closing tooth
cuts.append(Cut(
vertex=shared_annular_vertex(graph, last_new, edge),
last_tooth=last_new, closing_tooth=edge,
face=face, order=len(cuts),
))
return
depth[edge] = counter
counter += 1
last_new = edge
# Steps 1-3: the entry face.
traverse(innermost_bite(entry_edge, graph.bites), entry_edge, is_entry=True)
# 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),
key=lambda e: depth[e], reverse=True,
)
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))),
_MISSING)
if target is not _MISSING:
traverse(target, t, is_entry=False)
break
else:
break # no progress possible
return depth, cuts
# ---------------------------------------------------------------------------
# TikZ rendering.
# ---------------------------------------------------------------------------
def _coords(graph: FullMedialTireGraph,
r_ann=1.0, r_up=1.46, r_down=0.60) -> dict[str, tuple[float, float]]:
n = graph.n
def ang(k): # a_0 at the top, increasing k clockwise
return math.radians(90.0 - k * 360.0 / n)
def edge_mid_dir(i): # angle of the bisector of edge i's two endpoints
a0, a1 = ang(i), ang((i + 1) % n)
return math.atan2(math.sin(a0) + math.sin(a1), math.cos(a0) + math.cos(a1))
pos = {f"a{k}": (r_ann * math.cos(ang(k)), r_ann * math.sin(ang(k)))
for k in range(n)}
for i in graph.up_edges:
a = edge_mid_dir(i)
pos[f"u{i}"] = (r_up * math.cos(a), r_up * math.sin(a))
for i in graph.singleton_down_edges:
a = edge_mid_dir(i)
pos[f"d{i}"] = (r_down * math.cos(a), r_down * math.sin(a))
for (i, j) in graph.bites:
pts = [pos[f"a{i}"], pos[f"a{(i + 1) % n}"],
pos[f"a{j}"], pos[f"a{(j + 1) % n}"]]
cx = sum(p[0] for p in pts) / 4.0
cy = sum(p[1] for p in pts) / 4.0
pos[f"p{i}_{j}"] = (0.9 * cx, 0.9 * cy)
return pos
def _edge_midpoint(pos, graph, edge):
n = graph.n
a, b = pos[f"a{edge}"], pos[f"a{(edge + 1) % n}"]
return (0.5 * (a[0] + b[0]), 0.5 * (a[1] + b[1]))
def to_tikz(graph: FullMedialTireGraph,
depth: dict[int, int] | None = None,
cuts: list[Cut] | None = None,
entry_edge: int | None = None,
scale: float = 2.2) -> str:
"""A standalone ``tikzpicture`` for ``graph``; if ``depth`` is given, draw
the walk-depth labels and (with ``cuts``) the cut marks."""
pos = _coords(graph)
n = graph.n
L = []
A = L.append
A(f"\\begin{{tikzpicture}}[scale={scale},")
A(" ann/.style={circle, fill=black, inner sep=1.0pt},")
A(" upv/.style={circle, draw=blue!70!black, fill=blue!12, inner sep=1.4pt},")
A(" downv/.style={circle, draw=red!70!black, fill=red!12, inner sep=1.4pt},")
A(" bitev/.style={circle, draw=red!70!black, fill=red!32, inner sep=1.7pt},")
A(" cyc/.style={black, line width=1.0pt},")
A(" tth/.style={black!55, line width=0.4pt},")
A(" lbl/.style={font=\\scriptsize},")
A(" dlbl/.style={font=\\scriptsize\\bfseries, text=black},")
A(" cut/.style={red!80!black, line width=1.3pt},")
A(" cutlbl/.style={font=\\tiny, text=red!75!black}]")
def pt(name):
x, y = pos[name]
return f"({x:.3f},{y:.3f})"
# annular cycle
cyc = "--".join(pt(f"a{k}") for k in range(n)) + "--cycle"
A(f"\\draw[cyc] {cyc};")
# spokes
for i in graph.up_edges:
A(f"\\draw[tth] {pt(f'u{i}')}--{pt(f'a{i}')} {pt(f'u{i}')}--{pt(f'a{(i+1)%n}')};")
for i in graph.singleton_down_edges:
A(f"\\draw[tth] {pt(f'd{i}')}--{pt(f'a{i}')} {pt(f'd{i}')}--{pt(f'a{(i+1)%n}')};")
for (i, j) in graph.bites:
apex = f"p{i}_{j}"
for e in (i, j):
A(f"\\draw[tth] {pt(apex)}--{pt(f'a{e}')} {pt(apex)}--{pt(f'a{(e+1)%n}')};")
# vertices
for k in range(n):
A(f"\\node[ann] at {pt(f'a{k}')} {{}};")
for i in graph.up_edges:
A(f"\\node[upv] at {pt(f'u{i}')} {{}};")
for i in graph.singleton_down_edges:
A(f"\\node[downv] at {pt(f'd{i}')} {{}};")
for (i, j) in sorted(graph.bites):
A(f"\\node[bitev] at {pt(f'p{i}_{j}')} {{}};")
# walk-depth labels: placed along the spoke from apex toward the edge mid
if depth is not None:
for edge in range(n):
apex = graph.apex_of_edge(edge)
ax, ay = pos[apex]
mx, my = _edge_midpoint(pos, graph, edge)
f = 0.5
lx, ly = ax + f * (mx - ax), ay + f * (my - ay)
A(f"\\node[dlbl] at ({lx:.3f},{ly:.3f}) {{{depth[edge]}}};")
# cut marks: a short red slit across the duplicated annular vertex
if cuts:
for c in cuts:
if c.vertex is None:
continue
vx, vy = pos[f"a{c.vertex}"]
rad = math.atan2(vy, vx)
dx, dy = 0.16 * math.cos(rad), 0.16 * math.sin(rad)
A(f"\\draw[cut] ({vx-dx:.3f},{vy-dy:.3f})--({vx+dx:.3f},{vy+dy:.3f});")
lx, ly = vx + 0.30 * math.cos(rad), vy + 0.30 * math.sin(rad)
A(f"\\node[cutlbl] at ({lx:.3f},{ly:.3f}) {{cut {c.order+1}}};")
if entry_edge is not None:
ex, ey = pos[graph.apex_of_edge(entry_edge)]
rad = math.atan2(ey, ex)
tx, ty = ex + 0.34 * math.cos(rad), ey + 0.34 * math.sin(rad)
A(f"\\node[lbl, text=blue!60!black] at ({tx:.3f},{ty:.3f}) {{entry}};")
A("\\end{tikzpicture}")
return "\n".join(L)
# ---------------------------------------------------------------------------
# Worked example and CLI.
# ---------------------------------------------------------------------------
def worked_example() -> FullMedialTireGraph:
"""A clean 8-tooth piece: one bite (0,4), three down singletons 1,2,3 in its
gap, three up teeth 5,6,7 in the root face."""
return FullMedialTireGraph(n=8, tooth_word="DDDDDUUU", bites=frozenset({(0, 4)}))
def _check(graph: FullMedialTireGraph) -> None:
assert not has_incident_bite(graph.bites, graph.n), "bite uses incident edges"
assert satisfies_bite_face_condition(graph.tooth_word, graph.bites), \
"violates the bite-face condition"
assert graph.tooth_word.count("U") >= 3, "fewer than three up teeth"
def _describe(graph, depth, cuts) -> str:
lines = ["edge type walk-depth"]
for e in range(graph.n):
t = graph.tooth_word[e]
kind = {"U": "up"}.get(t, "down")
if door_bite(graph, e) is not None:
kind = "bite"
lines.append(f" e{e} {kind:<5} {depth[e]}")
lines.append("cuts (in order):")
for c in cuts:
f = "root" if c.face is None else f"bite{c.face}"
lines.append(f" cut {c.order+1}: duplicate a{c.vertex} "
f"(closing tooth e{c.closing_tooth} of {f})")
return "\n".join(lines)
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("--entry", default="u5",
help="entry up tooth, as an edge index or apex name like u5")
parser.add_argument("--start-depth", type=int, default=0)
parser.add_argument("--tikz", choices=["plain", "labelled", "both"],
help="emit TikZ for the worked example")
args = parser.parse_args()
entry = args.entry
edge = int(entry[1:]) if isinstance(entry, str) and entry.startswith("u") else int(entry)
graph = worked_example()
_check(graph)
depth, cuts = label_and_cut(graph, edge, start_depth=args.start_depth)
if args.tikz == "plain":
print(to_tikz(graph))
elif args.tikz == "labelled":
print(to_tikz(graph, depth=depth, cuts=cuts, entry_edge=edge))
elif args.tikz == "both":
print("% --- plain ---")
print(to_tikz(graph))
print("% --- labelled + cut ---")
print(to_tikz(graph, depth=depth, cuts=cuts, entry_edge=edge))
else:
print(f"worked example: n={graph.n} word={graph.tooth_word} "
f"bites={sorted(graph.bites)} entry=e{edge}")
print(_describe(graph, depth, cuts))
if __name__ == "__main__":
main()
@@ -0,0 +1,414 @@
"""Medial tire cut experiment.
End-to-end experiment for the *Medial Tire Cuts* paper:
1. Generate a random maximal planar graph G on n vertices (stacked seed plus
random diagonal flips; ``random_maximal_planar`` from the medial tire
decompositions experiments), optionally rejecting samples below a requested
minimum degree.
2. Build its medial graph M(G).
3. Take the nested tire decomposition at one random vertex level source: the
BFS-level treads, each realized as a FullMedialTireGraph.
4. Walk-depth label and cut each full medial tire graph, chaining the labels
down the tire tree, and assemble one final cut graph of M(G) with a global
label map.
This script produces *data* (the final cut graph and its labels); it draws
nothing. Anything for the paper (figures) lives in a separate script that
imports ``run_experiment`` from here.
Chaining rule (walk depths across the tire tree).
* The root tread (no recognised parent) is entered at an arbitrary up tooth
with walk depth 0.
* A child tread is entered at the up tooth whose apex is the *same medial
vertex* as the parent's down tooth of lowest walk depth -- a parent down
tooth and the child up tooth glued to it across the shared level cycle are
the same medial vertex of M(G). The entry up tooth's walk depth is that
parent down tooth's depth + 1, and the walk increments locally from there.
* The source cap contributes one additional cut. It is placed at the
counter-clockwise source edge incident to the cap down tooth whose apex is
the root tread's entry up tooth.
Run with the repo venv (networkx + scipy): ``.venv/bin/python``.
"""
from __future__ import annotations
import argparse
import json
import os
import random
import subprocess
import sys
import networkx as nx
# Reuse the realization pipeline from the medial tire decompositions paper, and
# the walk-depth labelling/cut from this paper's companion script.
_HERE = os.path.dirname(os.path.abspath(__file__))
_MTD = os.path.normpath(os.path.join(
_HERE, "..", "..",
"medial_tire_decompositions_of_plane_triangulations", "experiments"))
sys.path.insert(0, _MTD)
sys.path.insert(0, _HERE)
from tire_realization_analysis import ( # noqa: E402
ekey, extract_tread, medial_graph, medial_tire_facemodel,
random_maximal_planar, recognise, triangular_faces,
)
from medial_tire_cut_labelling import door_bite, label_and_cut # noqa: E402
# --------------------------------------------------------------------------- #
# 4. Walk-depth labelling and cut, chained down the tire tree.
# --------------------------------------------------------------------------- #
def _apex_vertex(g, bij, edge):
"""The medial vertex that is the apex of the tooth on annular ``edge``."""
return bij[g.apex_of_edge(edge)]
def _label_treads(treads, results):
"""Fill ``results[d]`` with the walk-depth labelling and cuts for each
recognised tread ``d``, chaining child entries to parent down teeth."""
for d in sorted(treads):
g, bij = treads[d]
parent = treads.get(d - 1)
if parent is None:
entry_edge, start_depth = g.up_edges[0], 0 # arbitrary root entry
else:
pg, pbij = parent
pdepth = results[d - 1]["depth"]
# parent down teeth, lowest walk depth first
down = sorted((pdepth[k], _apex_vertex(pg, pbij, k))
for k in pg.down_edges)
child_up_apex = {bij[f"u{m}"]: m for m in g.up_edges}
entry_edge = start_depth = None
for value, apex in down:
if apex in child_up_apex:
entry_edge, start_depth = child_up_apex[apex], value + 1
break
if entry_edge is None: # no shared apex (degenerate); root-style
entry_edge, start_depth = g.up_edges[0], 0
depth, cuts = label_and_cut(g, entry_edge, start_depth=start_depth)
results[d] = {"g": g, "bij": bij, "entry_edge": entry_edge,
"start_depth": start_depth, "depth": depth, "cuts": cuts}
def _cap_cut(G, emb, source, levels, results):
"""The source-cap cut determined by the first recognised tread's entry.
If the root tread enters at an up tooth whose apex is the level-1 edge
``xy``, then ``xy`` is a down tooth of the source cap. Cut the
counter-clockwise source edge incident to that down tooth. The returned
record also stores the local neighbour split used to unzip the medial
vertex in the whole medial graph.
"""
if not results:
return []
root_depth = min(results)
rec = results[root_depth]
g, bij = rec["g"], rec["bij"]
x, y = _apex_vertex(g, bij, rec["entry_edge"])
if levels.get(x) != 1 or levels.get(y) != 1:
return []
order = list(emb.neighbors_cw_order(source))
if x not in order or y not in order:
return []
next_cw = {v: order[(i + 1) % len(order)] for i, v in enumerate(order)}
prev_cw = {v: order[(i - 1) % len(order)] for i, v in enumerate(order)}
if next_cw[x] == y:
cut_endpoint, other_endpoint = x, y
elif next_cw[y] == x:
cut_endpoint, other_endpoint = y, x
else:
return []
other_cap_endpoint = prev_cw[cut_endpoint]
mv = ekey(source, cut_endpoint)
return [{
"medial_vertex": mv,
"down_tooth": ekey(cut_endpoint, other_endpoint),
"neighbours_a": [
ekey(source, other_endpoint),
ekey(cut_endpoint, other_endpoint),
],
"neighbours_b": [
ekey(source, other_cap_endpoint),
ekey(cut_endpoint, other_cap_endpoint),
],
}]
# --------------------------------------------------------------------------- #
# Assemble one final cut graph of M(G) with a global label map.
# --------------------------------------------------------------------------- #
def _assemble_cut_graph(M, results, cap_cuts=None):
"""Apply every tread's cuts to M(G).
Each cut duplicates an annular medial vertex, splitting its four incident
medial edges along the slit between the two teeth meeting there: the tooth
on the previous annular edge (with that edge's far annular vertex) goes to
one copy, the tooth on the next annular edge to the other.
Returns ``(H, label_records, warnings)`` where ``H`` is the cut graph (a
networkx graph whose split vertices are keyed ``(medial_vertex, "A"/"B",
tread)``) and ``label_records`` lists every tooth's walk depth.
"""
# Per cut annular vertex: map each original neighbour -> which copy keeps it.
split = {} # medial_vertex -> {neighbour_medial_vertex: copy_node}
warnings = []
for i, c in enumerate(cap_cuts or []):
mv = c["medial_vertex"]
if mv in split:
warnings.append(f"cap cut at {mv} was already cut; skipped")
continue
copy_a = (mv, "A", f"cap{i}")
copy_b = (mv, "B", f"cap{i}")
split[mv] = {
**{v: copy_a for v in c["neighbours_a"]},
**{v: copy_b for v in c["neighbours_b"]},
}
for d in sorted(results):
g, bij = results[d]["g"], results[d]["bij"]
n = g.n
for c in results[d]["cuts"]:
kk = c.vertex
if kk is None:
continue
mv = bij[f"a{kk}"]
if mv in split:
warnings.append(f"annular vertex a{kk} of tread {d} cut twice; "
f"second cut not applied")
continue
e_prev, e_next = (kk - 1) % n, kk
copy_a = (mv, "A", d)
copy_b = (mv, "B", d)
split[mv] = {
bij[f"a{(kk - 1) % n}"]: copy_a,
_apex_vertex(g, bij, e_prev): copy_a,
bij[f"a{(kk + 1) % n}"]: copy_b,
_apex_vertex(g, bij, e_next): copy_b,
}
def resolve(node, other):
return split[node][other] if node in split else node
H = nx.Graph()
H.add_nodes_from(v for v in M.nodes() if v not in split)
for v, copies in split.items():
H.add_nodes_from(set(copies.values()))
for u, v in M.edges():
H.add_edge(resolve(u, v), resolve(v, u))
label_records = []
for d in sorted(results):
g, bij, depth = results[d]["g"], results[d]["bij"], results[d]["depth"]
for k in range(g.n):
role = ("up" if g.tooth_word[k] == "U"
else "bite" if door_bite(g, k) is not None else "down")
label_records.append({
"tread": d, "edge": k, "role": role,
"apex": _apex_vertex(g, bij, k), "walk": depth[k],
})
return H, label_records, warnings
# --------------------------------------------------------------------------- #
# Driver.
# --------------------------------------------------------------------------- #
def random_maximal_planar_min_degree(n: int, seed: int, flips: int = 400,
min_degree: int = 0,
attempts: int = 1000) -> tuple[nx.Graph, int]:
"""Generate a random maximal planar graph with minimum degree at least
``min_degree``. The returned seed is the actual sample seed used."""
if min_degree <= 0:
return random_maximal_planar(n, seed, flips=flips), seed
if min_degree >= 5:
plantri = os.path.normpath(os.path.join(_HERE, "..", "..", "..",
"plantri", "plantri"))
if os.path.exists(plantri):
data = subprocess.check_output(
[plantri, f"-m{min_degree}", "-g", str(n)],
stderr=subprocess.DEVNULL)
graphs = [line for line in data.splitlines() if line]
if graphs:
G = nx.from_graph6_bytes(graphs[seed % len(graphs)])
return nx.convert_node_labels_to_integers(G), seed
for offset in range(attempts):
sample_seed = seed + offset
G = random_maximal_planar(n, sample_seed, flips=flips)
if min(dict(G.degree()).values()) >= min_degree:
return G, sample_seed
raise RuntimeError(
f"no random maximal planar graph on {n} vertices with "
f"minimum degree >= {min_degree} found in {attempts} attempts "
f"starting at seed {seed}")
def run_experiment(n: int = 12, seed: int = 0, flips: int = 400,
min_degree: int = 5, attempts: int = 1000) -> dict:
"""Run the full pipeline and return a structured result.
Result keys: ``n, seed, G, M, source, treads`` (dict depth -> (g, bij)),
``results`` (dict depth -> labelling/cut record), ``skipped`` (list of
(depth, reason)), ``cut_graph`` (networkx graph), ``labels`` (list of tooth
records), ``warnings``.
"""
G, graph_seed = random_maximal_planar_min_degree(
n, seed, flips=flips, min_degree=min_degree, attempts=attempts)
faces, emb = triangular_faces(G)
M = medial_graph(G)
source = random.Random(f"source-{graph_seed}").choice(sorted(G.nodes()))
levels = nx.single_source_shortest_path_length(G, source)
treads, skipped = {}, []
for d in range(max(levels.values())):
tread = extract_tread(faces, levels, d)
if tread is None:
skipped.append((d, "no tread faces"))
continue
if len(tread["up"]) < 3:
skipped.append((d, f"only {len(tread['up'])} up teeth"))
continue
rec = recognise(medial_tire_facemodel(tread["tread_faces"]), tread)
if rec is None:
skipped.append((d, "not a valid full medial tire graph"))
continue
treads[d] = rec
results = {}
_label_treads(treads, results)
cap_cuts = _cap_cut(G, emb, source, levels, results)
cut_graph, labels, warnings = _assemble_cut_graph(M, results, cap_cuts=cap_cuts)
return {
"n": n, "seed": seed, "graph_seed": graph_seed,
"min_degree": min(dict(G.degree()).values()),
"G": G, "M": M, "source": source,
"treads": treads, "results": results, "cap_cuts": cap_cuts,
"skipped": skipped,
"cut_graph": cut_graph, "labels": labels, "warnings": warnings,
}
# --------------------------------------------------------------------------- #
# Serialization / reporting.
# --------------------------------------------------------------------------- #
def _vname(v) -> str:
"""Stable string name for a medial vertex (an edge key) or a split node."""
if isinstance(v, tuple) and len(v) == 3 and v[1] in ("A", "B"):
mv, side, d = v
return f"{mv[0]}-{mv[1]}#{side}@T{d}"
return f"{v[0]}-{v[1]}"
def to_json(result: dict) -> dict:
res = result["results"]
treads_out = []
for d in sorted(res):
g, bij = res[d]["g"], res[d]["bij"]
depth, cuts = res[d]["depth"], res[d]["cuts"]
teeth = [{
"edge": k,
"role": ("up" if g.tooth_word[k] == "U"
else "bite" if door_bite(g, k) is not None else "down"),
"apex": _vname(_apex_vertex(g, bij, k)),
"walk": depth[k],
} for k in range(g.n)]
treads_out.append({
"depth": d, "n": g.n, "tooth_word": g.tooth_word,
"bites": sorted(list(b) for b in g.bites),
"entry_edge": res[d]["entry_edge"], "start_depth": res[d]["start_depth"],
"teeth": teeth,
"cuts": [{
"annular_index": c.vertex,
"annular_vertex": _vname(bij[f"a{c.vertex}"]),
"last_edge": c.last_tooth, "closing_edge": c.closing_tooth,
} for c in cuts],
})
H = result["cut_graph"]
return {
"n": result["n"], "seed": result["seed"],
"graph_seed": result["graph_seed"], "min_degree": result["min_degree"],
"source": result["source"],
"graph_edges": sorted([int(u), int(v)] for u, v in result["G"].edges()),
"medial_vertices": result["M"].number_of_nodes(),
"skipped": [[d, why] for d, why in result["skipped"]],
"cap_cuts": [{
"medial_vertex": _vname(c["medial_vertex"]),
"down_tooth": _vname(c["down_tooth"]),
} for c in result["cap_cuts"]],
"treads": treads_out,
"cut_graph": {
"nodes": sorted(_vname(v) for v in H.nodes()),
"edges": sorted([_vname(u), _vname(v)] for u, v in H.edges()),
},
"labels": [{
"tread": r["tread"], "edge": r["edge"], "role": r["role"],
"apex": _vname(r["apex"]), "walk": r["walk"],
} for r in result["labels"]],
"warnings": result["warnings"],
}
def summary(result: dict) -> str:
H, res = result["cut_graph"], result["results"]
lines = [
f"random maximal planar graph: n={result['n']} requested seed={result['seed']} "
f"graph seed={result['graph_seed']} "
f"({result['G'].number_of_edges()} edges, min degree {result['min_degree']})",
f"medial graph M(G): {result['M'].number_of_nodes()} vertices",
f"level source: vertex {result['source']}",
f"recognised treads: {sorted(res)}",
f"skipped treads: {result['skipped']}",
]
for d in sorted(res):
g = res[d]["g"]
ncuts = len(res[d]["cuts"])
lines.append(
f" tread {d}: |A(T)|={g.n} word={g.tooth_word} "
f"bites={sorted(g.bites)} entry=e{res[d]['entry_edge']} "
f"start_depth={res[d]['start_depth']} cuts={ncuts}")
lines.append(
f"final cut graph: {H.number_of_nodes()} vertices, "
f"{H.number_of_edges()} edges, "
f"{len(result['cap_cuts']) + sum(len(r['cuts']) for r in res.values())} cuts total")
if result["warnings"]:
lines.append("warnings: " + "; ".join(result["warnings"]))
return "\n".join(lines)
def main() -> None:
parser = argparse.ArgumentParser(
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("-n", type=int, default=12, help="number of vertices")
parser.add_argument("--seed", type=int, default=0)
parser.add_argument("--flips", type=int, default=400,
help="number of random diagonal flips when building G")
parser.add_argument("--min-degree", type=int, default=5,
help="reject random graphs below this minimum degree")
parser.add_argument("--attempts", type=int, default=1000,
help="number of consecutive seeds to try for --min-degree")
parser.add_argument("--json", metavar="PATH",
help="write the full result as JSON to PATH")
args = parser.parse_args()
result = run_experiment(n=args.n, seed=args.seed, flips=args.flips,
min_degree=args.min_degree, attempts=args.attempts)
print(summary(result))
if args.json:
with open(args.json, "w") as fh:
json.dump(to_json(result), fh, indent=2)
print(f"wrote {args.json}")
if __name__ == "__main__":
main()
+29
View File
@@ -0,0 +1,29 @@
\relax
\citation{bauerfeld-medial-tire}
\citation{bauerfeld-medial-tire}
\citation{bauerfeld-medial-tire}
\@writefile{toc}{\contentsline {section}{\tocsection {}{1}{Introduction}}{1}{}\protected@file@percent }
\@writefile{toc}{\contentsline {section}{\tocsection {}{2}{Cutting a full medial tire graph}}{1}{}\protected@file@percent }
\newlabel{def:walk-depth-cut}{{2.1}{1}}
\citation{bauerfeld-medial-tire}
\citation{bauerfeld-medial-tire}
\newlabel{rem:closing-tooth}{{2.2}{2}}
\newlabel{ex:worked-cut}{{2.3}{2}}
\@writefile{toc}{\contentsline {section}{\tocsection {}{3}{Chaining across the tire tree}}{2}{}\protected@file@percent }
\citation{bauerfeld-medial-tire}
\@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces A full medial tire graph (left) and its walk-depth labelling and cut (right), from Example\nonbreakingspace 2.3\hbox {}. Black vertices are the annular medial vertices of the cycle $A(T)$; blue vertices are up-tooth apexes, red vertices are down-tooth apexes, and the larger red vertex is the shared apex of the bite on annular edges $0$ and $4$. On the right, each tooth carries its walk depth, and the two red slits mark the cuts: \emph {cut\nonbreakingspace 1} duplicates $a_5$ as the root-face traversal closes, and \emph {cut\nonbreakingspace 2} duplicates $a_1$ as the bite's inner-gap face closes. After the cuts the only bounded faces are the eight teeth.}}{3}{}\protected@file@percent }
\newlabel{fig:worked-cut}{{1}{3}}
\newlabel{rem:chaining-candidates}{{3.1}{3}}
\newlabel{ex:real-cut}{{3.2}{4}}
\@writefile{lof}{\contentsline {figure}{\numberline {2}{\ignorespaces The recognised tread $T_2$ of the medial tire decomposition of a random maximal planar graph on $20$ vertices (Example\nonbreakingspace 3.2\hbox {}), with its walk-depth labelling and cut. Black vertices are the annular medial vertices of $A(T)$; blue vertices are up-tooth apexes and red vertices down-tooth apexes, the larger red vertex being the shared apex of the bite on annular edges $2$ and $5$. Each tooth carries its walk depth; the red slits are the two cuts.}}{4}{}\protected@file@percent }
\newlabel{fig:real-cut}{{2}{4}}
\bibcite{bauerfeld-medial-tire}{1}
\newlabel{tocindent-1}{0pt}
\newlabel{tocindent0}{12.7778pt}
\newlabel{tocindent1}{17.77782pt}
\newlabel{tocindent2}{0pt}
\newlabel{tocindent3}{0pt}
\@writefile{lof}{\contentsline {figure}{\numberline {3}{\ignorespaces The source graph $G$ and the whole medial graph $M(G)$ of the minimum-degree-$5$ maximal planar graph on $20$ vertices generated by \texttt {plantri -m5} at seed $59$. The source vertex $5$ is highlighted in the top panel. In the bottom panel, each medial vertex is placed at the midpoint of its corresponding source edge and labelled by that edge. Black vertices come from source edges between consecutive levels; coloured vertices come from source edges within a single level of the chain. The red-highlighted vertices, walk-depth labels, and seven red slits are the computed source-cap cut and full-medial-tire labelling cuts for the recognised treads $T_1$ and $T_2$. Drawn by \texttt {experiments/draw\_medial\_tire\_cut.py} with \texttt {--whole --min-degree 5}.}}{5}{}\protected@file@percent }
\newlabel{fig:whole-medial}{{3}{5}}
\@writefile{toc}{\contentsline {section}{\tocsection {}{}{References}}{5}{}\protected@file@percent }
\gdef \@abspage@last{5}
+533
View File
@@ -0,0 +1,533 @@
This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022) (preloaded format=pdflatex 2022.10.5) 15 JUN 2026 01:07
entering extended mode
restricted \write18 enabled.
%&-line parsing enabled.
**paper.tex
(./paper.tex
LaTeX2e <2021-11-15> patch level 1
L3 programming layer <2022-02-24>
(/usr/local/texlive/2022/texmf-dist/tex/latex/amscls/amsart.cls
Document Class: amsart 2020/05/29 v2.20.6
\linespacing=\dimen138
\normalparindent=\dimen139
\normaltopskip=\skip47
(/usr/local/texlive/2022/texmf-dist/tex/latex/amsmath/amsmath.sty
Package: amsmath 2021/10/15 v2.17l AMS math features
\@mathmargin=\skip48
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@=\dimen140
))
(/usr/local/texlive/2022/texmf-dist/tex/latex/amsmath/amsbsy.sty
Package: amsbsy 1999/11/29 v1.2d Bold Symbols
\pmbraise@=\dimen141
)
(/usr/local/texlive/2022/texmf-dist/tex/latex/amsmath/amsopn.sty
Package: amsopn 2021/08/26 v2.02 operator names
)
\inf@bad=\count185
LaTeX Info: Redefining \frac on input line 234.
\uproot@=\count186
\leftroot@=\count187
LaTeX Info: Redefining \overline on input line 399.
\classnum@=\count188
\DOTSCASE@=\count189
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=\dimen142
LaTeX Font Info: Redeclaring font encoding OML on input line 743.
LaTeX Font Info: Redeclaring font encoding OMS on input line 744.
\macc@depth=\count190
\c@MaxMatrixCols=\count191
\dotsspace@=\muskip16
\c@parentequation=\count192
\dspbrk@lvl=\count193
\tag@help=\toks17
\row@=\count194
\column@=\count195
\maxfields@=\count196
\andhelp@=\toks18
\eqnshift@=\dimen143
\alignsep@=\dimen144
\tagshift@=\dimen145
\tagwidth@=\dimen146
\totwidth@=\dimen147
\lineht@=\dimen148
\@envbody=\toks19
\multlinegap=\skip49
\multlinetaggap=\skip50
\mathdisplay@stack=\toks20
LaTeX Info: Redefining \[ on input line 2938.
LaTeX Info: Redefining \] on input line 2939.
)
LaTeX Font Info: Trying to load font information for U+msa on input line 397
.
(/usr/local/texlive/2022/texmf-dist/tex/latex/amsfonts/umsa.fd
File: umsa.fd 2013/01/14 v3.01 AMS symbols A
)
(/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.
)
\copyins=\insert199
\abstractbox=\box52
\listisep=\skip51
\c@part=\count197
\c@section=\count198
\c@subsection=\count266
\c@subsubsection=\count267
\c@paragraph=\count268
\c@subparagraph=\count269
\c@figure=\count270
\c@table=\count271
\abovecaptionskip=\skip52
\belowcaptionskip=\skip53
\captionindent=\dimen149
\thm@style=\toks21
\thm@bodyfont=\toks22
\thm@headfont=\toks23
\thm@notefont=\toks24
\thm@headpunct=\toks25
\thm@preskip=\skip54
\thm@postskip=\skip55
\thm@headsep=\skip56
\dth@everypar=\toks26
)
(/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/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=\dimen150
\Gin@req@width=\dimen151
)
(/usr/local/texlive/2022/texmf-dist/tex/latex/pgf/frontendlayer/tikz.sty
(/usr/local/texlive/2022/texmf-dist/tex/latex/pgf/basiclayer/pgf.sty
(/usr/local/texlive/2022/texmf-dist/tex/latex/pgf/utilities/pgfrcs.sty
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/utilities/pgfutil-common.te
x
\pgfutil@everybye=\toks28
\pgfutil@tempdima=\dimen152
\pgfutil@tempdimb=\dimen153
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/utilities/pgfutil-common-li
sts.tex))
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/utilities/pgfutil-latex.def
\pgfutil@abb=\box53
) (/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/utilities/pgfrcs.code.tex
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/pgf.revision.tex)
Package: pgfrcs 2021/05/15 v3.1.9a (3.1.9a)
))
Package: pgf 2021/05/15 v3.1.9a (3.1.9a)
(/usr/local/texlive/2022/texmf-dist/tex/latex/pgf/basiclayer/pgfcore.sty
(/usr/local/texlive/2022/texmf-dist/tex/latex/pgf/systemlayer/pgfsys.sty
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/systemlayer/pgfsys.code.tex
Package: pgfsys 2021/05/15 v3.1.9a (3.1.9a)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/utilities/pgfkeys.code.tex
\pgfkeys@pathtoks=\toks29
\pgfkeys@temptoks=\toks30
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/utilities/pgfkeysfiltered.c
ode.tex
\pgfkeys@tmptoks=\toks31
))
\pgf@x=\dimen154
\pgf@y=\dimen155
\pgf@xa=\dimen156
\pgf@ya=\dimen157
\pgf@xb=\dimen158
\pgf@yb=\dimen159
\pgf@xc=\dimen160
\pgf@yc=\dimen161
\pgf@xd=\dimen162
\pgf@yd=\dimen163
\w@pgf@writea=\write3
\r@pgf@reada=\read2
\c@pgf@counta=\count272
\c@pgf@countb=\count273
\c@pgf@countc=\count274
\c@pgf@countd=\count275
\t@pgf@toka=\toks32
\t@pgf@tokb=\toks33
\t@pgf@tokc=\toks34
\pgf@sys@id@count=\count276
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/systemlayer/pgf.cfg
File: pgf.cfg 2021/05/15 v3.1.9a (3.1.9a)
)
Driver file for pgf: pgfsys-pdftex.def
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/systemlayer/pgfsys-pdftex.d
ef
File: pgfsys-pdftex.def 2021/05/15 v3.1.9a (3.1.9a)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/systemlayer/pgfsys-common-p
df.def
File: pgfsys-common-pdf.def 2021/05/15 v3.1.9a (3.1.9a)
)))
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/systemlayer/pgfsyssoftpath.
code.tex
File: pgfsyssoftpath.code.tex 2021/05/15 v3.1.9a (3.1.9a)
\pgfsyssoftpath@smallbuffer@items=\count277
\pgfsyssoftpath@bigbuffer@items=\count278
)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/systemlayer/pgfsysprotocol.
code.tex
File: pgfsysprotocol.code.tex 2021/05/15 v3.1.9a (3.1.9a)
)) (/usr/local/texlive/2022/texmf-dist/tex/latex/xcolor/xcolor.sty
Package: xcolor 2021/10/31 v2.13 LaTeX color extensions (UK)
(/usr/local/texlive/2022/texmf-dist/tex/latex/graphics-cfg/color.cfg
File: color.cfg 2016/01/02 v1.6 sample color configuration
)
Package xcolor Info: Driver file: pdftex.def on input line 227.
Package xcolor Info: Model `cmy' substituted by `cmy0' on input line 1352.
Package xcolor Info: Model `hsb' substituted by `rgb' on input line 1356.
Package xcolor Info: Model `RGB' extended on input line 1368.
Package xcolor Info: Model `HTML' substituted by `rgb' on input line 1370.
Package xcolor Info: Model `Hsb' substituted by `hsb' on input line 1371.
Package xcolor Info: Model `tHsb' substituted by `hsb' on input line 1372.
Package xcolor Info: Model `HSB' substituted by `hsb' on input line 1373.
Package xcolor Info: Model `Gray' substituted by `gray' on input line 1374.
Package xcolor Info: Model `wave' substituted by `hsb' on input line 1375.
)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/basiclayer/pgfcore.code.tex
Package: pgfcore 2021/05/15 v3.1.9a (3.1.9a)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/math/pgfmathcalc.code.tex
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/math/pgfmathutil.code.tex)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/math/pgfmathparser.code.tex
\pgfmath@dimen=\dimen164
\pgfmath@count=\count279
\pgfmath@box=\box54
\pgfmath@toks=\toks35
\pgfmath@stack@operand=\toks36
\pgfmath@stack@operation=\toks37
)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.code.
tex
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.basic
.code.tex)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.trigo
nometric.code.tex)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.rando
m.code.tex)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.compa
rison.code.tex)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.base.
code.tex)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.round
.code.tex)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.misc.
code.tex)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/math/pgfmathfunctions.integ
erarithmetics.code.tex)))
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/math/pgfmathfloat.code.tex
\c@pgfmathroundto@lastzeros=\count280
)) (/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/math/pgfint.code.tex)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepoints.co
de.tex
File: pgfcorepoints.code.tex 2021/05/15 v3.1.9a (3.1.9a)
\pgf@picminx=\dimen165
\pgf@picmaxx=\dimen166
\pgf@picminy=\dimen167
\pgf@picmaxy=\dimen168
\pgf@pathminx=\dimen169
\pgf@pathmaxx=\dimen170
\pgf@pathminy=\dimen171
\pgf@pathmaxy=\dimen172
\pgf@xx=\dimen173
\pgf@xy=\dimen174
\pgf@yx=\dimen175
\pgf@yy=\dimen176
\pgf@zx=\dimen177
\pgf@zy=\dimen178
)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathconst
ruct.code.tex
File: pgfcorepathconstruct.code.tex 2021/05/15 v3.1.9a (3.1.9a)
\pgf@path@lastx=\dimen179
\pgf@path@lasty=\dimen180
)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathusage
.code.tex
File: pgfcorepathusage.code.tex 2021/05/15 v3.1.9a (3.1.9a)
\pgf@shorten@end@additional=\dimen181
\pgf@shorten@start@additional=\dimen182
)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/basiclayer/pgfcorescopes.co
de.tex
File: pgfcorescopes.code.tex 2021/05/15 v3.1.9a (3.1.9a)
\pgfpic=\box55
\pgf@hbox=\box56
\pgf@layerbox@main=\box57
\pgf@picture@serial@count=\count281
)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/basiclayer/pgfcoregraphicst
ate.code.tex
File: pgfcoregraphicstate.code.tex 2021/05/15 v3.1.9a (3.1.9a)
\pgflinewidth=\dimen183
)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/basiclayer/pgfcoretransform
ations.code.tex
File: pgfcoretransformations.code.tex 2021/05/15 v3.1.9a (3.1.9a)
\pgf@pt@x=\dimen184
\pgf@pt@y=\dimen185
\pgf@pt@temp=\dimen186
)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/basiclayer/pgfcorequick.cod
e.tex
File: pgfcorequick.code.tex 2021/05/15 v3.1.9a (3.1.9a)
)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreobjects.c
ode.tex
File: pgfcoreobjects.code.tex 2021/05/15 v3.1.9a (3.1.9a)
)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepathproce
ssing.code.tex
File: pgfcorepathprocessing.code.tex 2021/05/15 v3.1.9a (3.1.9a)
)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/basiclayer/pgfcorearrows.co
de.tex
File: pgfcorearrows.code.tex 2021/05/15 v3.1.9a (3.1.9a)
\pgfarrowsep=\dimen187
)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreshade.cod
e.tex
File: pgfcoreshade.code.tex 2021/05/15 v3.1.9a (3.1.9a)
\pgf@max=\dimen188
\pgf@sys@shading@range@num=\count282
\pgf@shadingcount=\count283
)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreimage.cod
e.tex
File: pgfcoreimage.code.tex 2021/05/15 v3.1.9a (3.1.9a)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/basiclayer/pgfcoreexternal.
code.tex
File: pgfcoreexternal.code.tex 2021/05/15 v3.1.9a (3.1.9a)
\pgfexternal@startupbox=\box58
))
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/basiclayer/pgfcorelayers.co
de.tex
File: pgfcorelayers.code.tex 2021/05/15 v3.1.9a (3.1.9a)
)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/basiclayer/pgfcoretranspare
ncy.code.tex
File: pgfcoretransparency.code.tex 2021/05/15 v3.1.9a (3.1.9a)
)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/basiclayer/pgfcorepatterns.
code.tex
File: pgfcorepatterns.code.tex 2021/05/15 v3.1.9a (3.1.9a)
)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/basiclayer/pgfcorerdf.code.
tex
File: pgfcorerdf.code.tex 2021/05/15 v3.1.9a (3.1.9a)
)))
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/modules/pgfmoduleshapes.cod
e.tex
File: pgfmoduleshapes.code.tex 2021/05/15 v3.1.9a (3.1.9a)
\pgfnodeparttextbox=\box59
)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/modules/pgfmoduleplot.code.
tex
File: pgfmoduleplot.code.tex 2021/05/15 v3.1.9a (3.1.9a)
)
(/usr/local/texlive/2022/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version
-0-65.sty
Package: pgfcomp-version-0-65 2021/05/15 v3.1.9a (3.1.9a)
\pgf@nodesepstart=\dimen189
\pgf@nodesepend=\dimen190
)
(/usr/local/texlive/2022/texmf-dist/tex/latex/pgf/compatibility/pgfcomp-version
-1-18.sty
Package: pgfcomp-version-1-18 2021/05/15 v3.1.9a (3.1.9a)
))
(/usr/local/texlive/2022/texmf-dist/tex/latex/pgf/utilities/pgffor.sty
(/usr/local/texlive/2022/texmf-dist/tex/latex/pgf/utilities/pgfkeys.sty
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/utilities/pgfkeys.code.tex)
) (/usr/local/texlive/2022/texmf-dist/tex/latex/pgf/math/pgfmath.sty
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex))
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/utilities/pgffor.code.tex
Package: pgffor 2021/05/15 v3.1.9a (3.1.9a)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/math/pgfmath.code.tex)
\pgffor@iter=\dimen191
\pgffor@skip=\dimen192
\pgffor@stack=\toks38
\pgffor@toks=\toks39
))
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/frontendlayer/tikz/tikz.cod
e.tex
Package: tikz 2021/05/15 v3.1.9a (3.1.9a)
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/libraries/pgflibraryplothan
dlers.code.tex
File: pgflibraryplothandlers.code.tex 2021/05/15 v3.1.9a (3.1.9a)
\pgf@plot@mark@count=\count284
\pgfplotmarksize=\dimen193
)
\tikz@lastx=\dimen194
\tikz@lasty=\dimen195
\tikz@lastxsaved=\dimen196
\tikz@lastysaved=\dimen197
\tikz@lastmovetox=\dimen198
\tikz@lastmovetoy=\dimen256
\tikzleveldistance=\dimen257
\tikzsiblingdistance=\dimen258
\tikz@figbox=\box60
\tikz@figbox@bg=\box61
\tikz@tempbox=\box62
\tikz@tempbox@bg=\box63
\tikztreelevel=\count285
\tikznumberofchildren=\count286
\tikznumberofcurrentchild=\count287
\tikz@fig@count=\count288
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/modules/pgfmodulematrix.cod
e.tex
File: pgfmodulematrix.code.tex 2021/05/15 v3.1.9a (3.1.9a)
\pgfmatrixcurrentrow=\count289
\pgfmatrixcurrentcolumn=\count290
\pgf@matrix@numberofcolumns=\count291
)
\tikz@expandcount=\count292
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/frontendlayer/tikz/librarie
s/tikzlibrarytopaths.code.tex
File: tikzlibrarytopaths.code.tex 2021/05/15 v3.1.9a (3.1.9a)
)))
(/usr/local/texlive/2022/texmf-dist/tex/generic/pgf/frontendlayer/tikz/librarie
s/tikzlibrarybackgrounds.code.tex
File: tikzlibrarybackgrounds.code.tex 2021/05/15 v3.1.9a (3.1.9a)
\pgf@layerbox@background=\box64
\pgf@layerboxsaved@background=\box65
)
\c@theorem=\count293
(/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=\count294
\l__pdf_internal_box=\box66
)
(./paper.aux)
\openout1 = `paper.aux'.
LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 29.
LaTeX Font Info: ... okay on input line 29.
LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 29.
LaTeX Font Info: ... okay on input line 29.
LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 29.
LaTeX Font Info: ... okay on input line 29.
LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 29.
LaTeX Font Info: ... okay on input line 29.
LaTeX Font Info: Checking defaults for TS1/cmr/m/n on input line 29.
LaTeX Font Info: ... okay on input line 29.
LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 29.
LaTeX Font Info: ... okay on input line 29.
LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 29.
LaTeX Font Info: ... okay on input line 29.
LaTeX Font Info: Trying to load font information for U+msa on input line 29.
(/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 29.
(/usr/local/texlive/2022/texmf-dist/tex/latex/amsfonts/umsb.fd
File: umsb.fd 2013/01/14 v3.01 AMS symbols B
)
(/usr/local/texlive/2022/texmf-dist/tex/context/base/mkii/supp-pdf.mkii
[Loading MPS to PDF converter (version 2006.09.02).]
\scratchcounter=\count295
\scratchdimen=\dimen259
\scratchbox=\box67
\nofMPsegments=\count296
\nofMParguments=\count297
\everyMPshowfont=\toks40
\MPscratchCnt=\count298
\MPscratchDim=\dimen260
\MPnumerator=\count299
\makeMPintoPDFobject=\count300
\everyMPtoPDFconversion=\toks41
) (/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
))
[1{/usr/local/texlive/2022/texmf-var/fonts/map/pdftex/updmap/pdftex.map}]
LaTeX Warning: `h' float specifier changed to `ht'.
[2] [3] (./whole_medial_seed59_min5.tikz) [4] [5] (./paper.aux) )
Here is how much of TeX's memory you used:
13803 strings out of 478268
275582 string characters out of 5846347
655790 words of memory out of 5000000
31627 multiletter control sequences out of 15000+600000
477661 words of font info for 60 fonts, out of 8000000 for 9000
1302 hyphenation exceptions out of 8191
84i,15n,89p,907b,804s stack positions out of 10000i,1000n,20000p,200000b,200000s
</usr/local/te
xlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx10.pfb></usr/local/tex
live/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx6.pfb></usr/local/texli
ve/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx7.pfb></usr/local/texlive
/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmcsc10.pfb></usr/local/texlive
/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi10.pfb></usr/local/texlive/
2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi7.pfb></usr/local/texlive/20
22/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb></usr/local/texlive/2022
/texmf-dist/fonts/type1/public/amsfonts/cm/cmr6.pfb></usr/local/texlive/2022/te
xmf-dist/fonts/type1/public/amsfonts/cm/cmr7.pfb></usr/local/texlive/2022/texmf
-dist/fonts/type1/public/amsfonts/cm/cmr8.pfb></usr/local/texlive/2022/texmf-di
st/fonts/type1/public/amsfonts/cm/cmss10.pfb></usr/local/texlive/2022/texmf-dis
t/fonts/type1/public/amsfonts/cm/cmsy10.pfb></usr/local/texlive/2022/texmf-dist
/fonts/type1/public/amsfonts/cm/cmsy6.pfb></usr/local/texlive/2022/texmf-dist/f
onts/type1/public/amsfonts/cm/cmti10.pfb></usr/local/texlive/2022/texmf-dist/fo
nts/type1/public/amsfonts/cm/cmti8.pfb></usr/local/texlive/2022/texmf-dist/font
s/type1/public/amsfonts/cm/cmtt10.pfb>
Output written on paper.pdf (5 pages, 226751 bytes).
PDF statistics:
103 PDF objects out of 1000 (max. 8388607)
63 compressed objects within 1 object stream
0 named destinations out of 1000 (max. 500000)
13 words of extra memory for PDF output out of 10000 (max. 10000000)
Binary file not shown.
+438
View File
@@ -0,0 +1,438 @@
%% filename: amsart-template.tex
%% American Mathematical Society
%% AMS-LaTeX v.2 template for use with amsart
%% ====================================================================
\documentclass{amsart}
\usepackage{amssymb}
\usepackage{graphicx}
\usepackage{tikz}
\usetikzlibrary{backgrounds}
\newtheorem{theorem}{Theorem}[section]
\newtheorem{lemma}[theorem]{Lemma}
\newtheorem{corollary}[theorem]{Corollary}
\newtheorem{proposition}[theorem]{Proposition}
\newtheorem{conjecture}[theorem]{Conjecture}
\theoremstyle{definition}
\newtheorem{definition}[theorem]{Definition}
\newtheorem{example}[theorem]{Example}
\newtheorem{xca}[theorem]{Exercise}
\theoremstyle{remark}
\newtheorem{remark}[theorem]{Remark}
\numberwithin{equation}{section}
\begin{document}
\title{Medial Tire Cuts}
% author one information
\author{Eric Bauerfeld}
\address{}
\curraddr{}
\email{}
\thanks{}
\subjclass[2010]{Primary }
\keywords{plane graph, triangulation, medial graph, tire graph, Tait coloring, Four Colour Theorem}
\date{}
\dedicatory{}
\begin{abstract}
Starting from the medial tire decomposition of a plane triangulation, we
study the cuts that medial tires make in the full medial graph. We will
show how to use medial tires to decompose the medial graph into a tree of
three faces.
\end{abstract}
\maketitle
\section{Introduction}
This paper builds on the medial tire decomposition
of~\cite{bauerfeld-medial-tire}. For a plane triangulation $G$ with
fixed embedding we use freely the terminology and notation introduced
there: the full medial graph $M(G)$, its decomposition into full medial
tire graphs $\mathsf{M}(T)$ indexed by the treads $T$ of the tire tree
$\mathcal{T}(G,S)$ at a level source $S$, the annular medial cycle
$A(T)$, and the boundary medial vertex sets.
We will show how to use medial tires to decompose the medial graph into
a tree of three faces.
\section{Cutting a full medial tire graph}
We first describe a procedure that simultaneously \emph{labels} and
\emph{cuts} a single full medial tire graph $\mathsf{M}(T)$ so that,
after the cuts, the only faces are the outer face and $3$-faces
(triangles)---the teeth of~\cite{bauerfeld-medial-tire}. The labelling
assigns to each tooth an integer \emph{walk depth}; the cuts break the
cyclic adjacencies of the teeth so that what remains is a tree of
$3$-faces.
By a \emph{cut} we mean the duplication of a single vertex of
$\mathsf{M}(T)$: the vertex is split into two copies and the embedding is
slit open along it (a planar unzip), separating the faces that meet only
at that vertex. A cut therefore reduces the number of bounded faces that
are not teeth.
Throughout we use the teeth, up and down teeth, apexes, bites, the
annular medial cycle $A(T)$, and the auxiliary plane graph $B(T)$
of~\cite{bauerfeld-medial-tire}. Each tooth is a $3$-face of
$\mathsf{M}(T)$, and the inner faces of $B(T)$ (the root face and the
bite inner-gap faces) are the larger faces to be cut into teeth.
\begin{definition}[Walk-depth labelling and cut]
\label{def:walk-depth-cut}
Let $\mathsf{M}(T)$ be a full medial tire graph. Assign walk depths and
cuts as follows.
\begin{enumerate}
\item Pick an arbitrary up tooth, the \emph{entry tooth}. It has walk
depth $d$.
\item Traverse all the teeth that bound the inner face incident to the
entry tooth clockwise until we reach the entry tooth, incrementing the
walk depth by $1$ for each tooth traversed. (The \emph{inner face
incident to the entry tooth} is the inner face of $B(T)$ whose boundary
contains the annular edge of $A(T)$ carrying the entry tooth.)
\item When you reach the last tooth in the face, perform a \emph{cut}
by duplicating the annular vertex at which the traversal closes---the
annular vertex of $A(T)$ shared by the last tooth and the entry tooth.
\item Find the tooth $t$ with the highest walk depth which is a member
of a bite.
\item If $t$ is incident to a face $F$ with unlabelled teeth, traverse
the teeth in $F$ starting from $t$ in the direction of the tooth
incident to $t$ which is unlabelled, and increment the walk depth by
$1$ as you travel. (Here a tooth is \emph{incident to $t$} when it
shares an annular vertex of $A(T)$ with $t$.)
\item Repeat steps (3)--(5) until all teeth have been labelled.
\end{enumerate}
\end{definition}
\begin{remark}[Closing tooth of a descended face]
\label{rem:closing-tooth}
For the entry face the traversal of step (2) closes by returning to the
entry tooth, so the cut of step (3) duplicates the annular vertex shared
by the last tooth and the entry tooth. For a face $F$ entered in step
(5), the traversal instead closes upon reaching an already-labelled
tooth: the other tooth of the bite through which $F$ was entered. In
both cases the cut of step (3) duplicates the annular vertex shared by
the last newly labelled tooth and this \emph{closing tooth}. Since both
teeth of a bite are labelled while traversing its parent face, every
descended face closes on such a tooth.
\end{remark}
\begin{example}[A worked walk-depth labelling and cut]
\label{ex:worked-cut}
Figure~\ref{fig:worked-cut} shows a full medial tire graph with annular
cycle of length $8$, generated by the full medial tire generator
of~\cite{bauerfeld-medial-tire}. Its eight teeth are: three up teeth on
the annular edges $5,6,7$ in the root face; one bite pairing the annular
edges $0$ and $4$; and three singleton down teeth on the annular edges
$1,2,3$ lying in that bite's inner-gap face.
Take the up tooth on edge $5$ as the entry tooth, with walk depth $0$.
Its inner face is the root face, bounded by the teeth on edges
$5,6,7,0,4$ in clockwise order. Step (2) labels them
\[
5\mapsto 0,\quad 6\mapsto 1,\quad 7\mapsto 2,\quad
0\mapsto 3,\quad 4\mapsto 4,
\]
and step (3) cuts by duplicating the annular vertex $a_5$ shared by the
last tooth (edge $4$) and the entry tooth (edge $5$). The highest-depth
bite tooth is now the one on edge $4$ (walk depth $4$); it is incident to
the still-unlabelled inner-gap face of the bite $(0,4)$. Entering that
face from edge $4$ toward its unlabelled neighbour, step (5) labels the
three down teeth
\[
3\mapsto 5,\quad 2\mapsto 6,\quad 1\mapsto 7,
\]
and closes on the already-labelled bite tooth of edge $0$, so step (3)
cuts by duplicating the annular vertex $a_1$
(Remark~\ref{rem:closing-tooth}). All eight teeth are now labelled, and
the two cuts leave only the outer face and the eight teeth as
$3$-faces. The labelling and cuts are produced by the script
\texttt{experiments/medial\_tire\_cut\_labelling.py}.
\end{example}
\begin{figure}[h]
\centering
\begin{tikzpicture}[scale=1.6,
ann/.style={circle, fill=black, inner sep=1.0pt},
upv/.style={circle, draw=blue!70!black, fill=blue!12, inner sep=1.4pt},
downv/.style={circle, draw=red!70!black, fill=red!12, inner sep=1.4pt},
bitev/.style={circle, draw=red!70!black, fill=red!32, inner sep=1.7pt},
cyc/.style={black, line width=1.0pt},
tth/.style={black!55, line width=0.4pt},
lbl/.style={font=\scriptsize},
dlbl/.style={font=\scriptsize\bfseries, text=black},
cut/.style={red!80!black, line width=1.3pt},
cutlbl/.style={font=\tiny, text=red!75!black}]
\draw[cyc] (0.000,1.000)--(0.707,0.707)--(1.000,0.000)--(0.707,-0.707)--(0.000,-1.000)--(-0.707,-0.707)--(-1.000,-0.000)--(-0.707,0.707)--cycle;
\draw[tth] (-1.349,-0.559)--(-0.707,-0.707) (-1.349,-0.559)--(-1.000,-0.000);
\draw[tth] (-1.349,0.559)--(-1.000,-0.000) (-1.349,0.559)--(-0.707,0.707);
\draw[tth] (-0.559,1.349)--(-0.707,0.707) (-0.559,1.349)--(0.000,1.000);
\draw[tth] (0.554,0.230)--(0.707,0.707) (0.554,0.230)--(1.000,0.000);
\draw[tth] (0.554,-0.230)--(1.000,0.000) (0.554,-0.230)--(0.707,-0.707);
\draw[tth] (0.230,-0.554)--(0.707,-0.707) (0.230,-0.554)--(0.000,-1.000);
\draw[tth] (0.000,-0.000)--(0.000,1.000) (0.000,-0.000)--(0.707,0.707);
\draw[tth] (0.000,-0.000)--(0.000,-1.000) (0.000,-0.000)--(-0.707,-0.707);
\node[ann] at (0.000,1.000) {};
\node[ann] at (0.707,0.707) {};
\node[ann] at (1.000,0.000) {};
\node[ann] at (0.707,-0.707) {};
\node[ann] at (0.000,-1.000) {};
\node[ann] at (-0.707,-0.707) {};
\node[ann] at (-1.000,-0.000) {};
\node[ann] at (-0.707,0.707) {};
\node[upv] at (-1.349,-0.559) {};
\node[upv] at (-1.349,0.559) {};
\node[upv] at (-0.559,1.349) {};
\node[downv] at (0.554,0.230) {};
\node[downv] at (0.554,-0.230) {};
\node[downv] at (0.230,-0.554) {};
\node[bitev] at (0.000,-0.000) {};
\end{tikzpicture}
\qquad
\begin{tikzpicture}[scale=1.6,
ann/.style={circle, fill=black, inner sep=1.0pt},
upv/.style={circle, draw=blue!70!black, fill=blue!12, inner sep=1.4pt},
downv/.style={circle, draw=red!70!black, fill=red!12, inner sep=1.4pt},
bitev/.style={circle, draw=red!70!black, fill=red!32, inner sep=1.7pt},
cyc/.style={black, line width=1.0pt},
tth/.style={black!55, line width=0.4pt},
lbl/.style={font=\scriptsize},
dlbl/.style={font=\scriptsize\bfseries, text=black},
cut/.style={red!80!black, line width=1.3pt},
cutlbl/.style={font=\tiny, text=red!75!black}]
\draw[cyc] (0.000,1.000)--(0.707,0.707)--(1.000,0.000)--(0.707,-0.707)--(0.000,-1.000)--(-0.707,-0.707)--(-1.000,-0.000)--(-0.707,0.707)--cycle;
\draw[tth] (-1.349,-0.559)--(-0.707,-0.707) (-1.349,-0.559)--(-1.000,-0.000);
\draw[tth] (-1.349,0.559)--(-1.000,-0.000) (-1.349,0.559)--(-0.707,0.707);
\draw[tth] (-0.559,1.349)--(-0.707,0.707) (-0.559,1.349)--(0.000,1.000);
\draw[tth] (0.554,0.230)--(0.707,0.707) (0.554,0.230)--(1.000,0.000);
\draw[tth] (0.554,-0.230)--(1.000,0.000) (0.554,-0.230)--(0.707,-0.707);
\draw[tth] (0.230,-0.554)--(0.707,-0.707) (0.230,-0.554)--(0.000,-1.000);
\draw[tth] (0.000,-0.000)--(0.000,1.000) (0.000,-0.000)--(0.707,0.707);
\draw[tth] (0.000,-0.000)--(0.000,-1.000) (0.000,-0.000)--(-0.707,-0.707);
\node[ann] at (0.000,1.000) {};
\node[ann] at (0.707,0.707) {};
\node[ann] at (1.000,0.000) {};
\node[ann] at (0.707,-0.707) {};
\node[ann] at (0.000,-1.000) {};
\node[ann] at (-0.707,-0.707) {};
\node[ann] at (-1.000,-0.000) {};
\node[ann] at (-0.707,0.707) {};
\node[upv] at (-1.349,-0.559) {};
\node[upv] at (-1.349,0.559) {};
\node[upv] at (-0.559,1.349) {};
\node[downv] at (0.554,0.230) {};
\node[downv] at (0.554,-0.230) {};
\node[downv] at (0.230,-0.554) {};
\node[bitev] at (0.000,-0.000) {};
\node[dlbl] at (0.177,0.427) {3};
\node[dlbl] at (0.704,0.292) {7};
\node[dlbl] at (0.704,-0.292) {6};
\node[dlbl] at (0.292,-0.704) {5};
\node[dlbl] at (-0.177,-0.427) {4};
\node[dlbl] at (-1.101,-0.456) {0};
\node[dlbl] at (-1.101,0.456) {1};
\node[dlbl] at (-0.456,1.101) {2};
\draw[cut] (-0.594,-0.594)--(-0.820,-0.820);
\node[cutlbl] at (-0.919,-0.919) {cut 1};
\draw[cut] (0.594,0.594)--(0.820,0.820);
\node[cutlbl] at (0.919,0.919) {cut 2};
\node[lbl, text=blue!60!black] at (-1.663,-0.689) {entry};
\end{tikzpicture}
\caption{A full medial tire graph (left) and its walk-depth labelling and
cut (right), from Example~\ref{ex:worked-cut}. Black vertices are the
annular medial vertices of the cycle $A(T)$; blue vertices are up-tooth
apexes, red vertices are down-tooth apexes, and the larger red vertex is
the shared apex of the bite on annular edges $0$ and $4$. On the right,
each tooth carries its walk depth, and the two red slits mark the cuts:
\emph{cut~1} duplicates $a_5$ as the root-face traversal closes, and
\emph{cut~2} duplicates $a_1$ as the bite's inner-gap face closes. After
the cuts the only bounded faces are the eight teeth.}
\label{fig:worked-cut}
\end{figure}
\section{Chaining across the tire tree}
Definition~\ref{def:walk-depth-cut} labels and cuts a single full medial
tire graph. We extend it to the whole medial graph $M(G)$ through the
medial tire decomposition of~\cite{bauerfeld-medial-tire}: the tire tree
decomposes $M(G)$ into full medial tire graphs $\mathsf{M}(T)$, one per
tread $T$, glued along their boundary medial vertices. A parent tread's
inner level cycle is a child tread's outer level cycle, and the boundary
medial vertices on that shared cycle belong to both treads.
The key incidence is this. A \emph{boundary} (singleton) down tooth of a
parent tread and the up tooth of the child tread glued to it across the
shared level cycle have the \emph{same apex}: both apexes are the same
medial vertex of $M(G)$, namely the medial vertex of an edge with both
endpoints on the shared level cycle. We use this to carry the walk depth
from a parent into its children.
We label tread by tread, outward from the root:
\begin{itemize}
\item a tread with no parent in the decomposition---in particular the
innermost recognised tread---is treated as a \emph{root} and entered at
an arbitrary up tooth with walk depth $0$;
\item a child tread is entered at the up tooth whose apex is the parent's
boundary down tooth of lowest walk depth; that entry up tooth's walk depth
is one more than that down tooth's, and the walk then increments locally
within the child as in Definition~\ref{def:walk-depth-cut}.
\end{itemize}
The source cap contributes one additional cut before the recognised
treads are assembled. If the root tread enters at an up tooth whose apex
is the cap down tooth $xy$, we cut the cap annular vertex corresponding
to the counter-clockwise source edge incident to $xy$. In the example of
Figure~\ref{fig:whole-medial}, the root entry apex is the cap down tooth
$14\!-\!4$, so the cap cut is placed at the medial vertex $14\!-\!5$.
\begin{remark}[Candidate down teeth for chaining]
\label{rem:chaining-candidates}
The down teeth eligible to fix a child's entry are exactly the
\emph{boundary} (singleton) down teeth of the parent: those lying in a
single tread face, whose apex is the shared boundary medial vertex glued to
a child up tooth. A bite's two down teeth are \emph{not} eligible. By the
definition of a bite in~\cite{bauerfeld-medial-tire} its annular edge borders
two tread faces, so a bite tooth is interior to the parent tread and its
apex is a boundary medial vertex of no child. Hence ``the down tooth of
lowest walk depth'' is read among the boundary down teeth only; a bite of
even lower walk depth is skipped.
\end{remark}
Applying every tread's cuts to $M(G)$ assembles the per-tread labellings
and cuts into a single cut graph of $M(G)$ together with a global
walk-depth label map. This pipeline---random maximal planar graph, medial
graph, tire decomposition at a vertex level source, and chained walk-depth
labelling and cut---is carried out by the experiment script
\texttt{experiments/run\_medial\_tire\_cut\_experiment.py}.
\begin{example}[A medial tire cut from a random graph]
\label{ex:real-cut}
Run on a random maximal planar graph on $20$ vertices (seed $72$, level
source vertex $9$), the experiment yields a single recognised tread
$T_2$, drawn in Figure~\ref{fig:real-cut} with the walk-depth labelling
and cut emitted by the graphics companion
\texttt{experiments/draw\_medial\_tire\_cut.py}. Its annular cycle has
length $8$, with up teeth on annular edges $0,3,4$, singleton down teeth
on $1,6,7$, and a bite on the non-incident annular edges $2$ and $5$ (the
central shared apex). Entering at the up tooth on edge $0$ with walk
depth $0$, the root face is labelled in order ($0,1,2$ then $3,4,5$) and
\emph{cut~1} duplicates $a_0$ as it closes; the walk then descends through
the bite into its inner-gap face, labelling the two teeth there ($6,7$),
and \emph{cut~2} duplicates $a_3$ as that face closes. The two cuts leave
only the outer face and the eight teeth as $3$-faces.
\end{example}
\begin{figure}[h]
\centering
\begin{tikzpicture}[scale=1.6,
ann/.style={circle, fill=black, inner sep=1.0pt},
upv/.style={circle, draw=blue!70!black, fill=blue!12, inner sep=1.4pt},
downv/.style={circle, draw=red!70!black, fill=red!12, inner sep=1.4pt},
bitev/.style={circle, draw=red!70!black, fill=red!32, inner sep=1.7pt},
cyc/.style={black, line width=1.0pt},
tth/.style={black!55, line width=0.4pt},
lbl/.style={font=\scriptsize},
dlbl/.style={font=\scriptsize\bfseries, text=black},
cut/.style={red!80!black, line width=1.3pt},
cutlbl/.style={font=\tiny, text=red!75!black}]
\draw[cyc] (0.000,1.000)--(0.707,0.707)--(1.000,0.000)--(0.707,-0.707)--(0.000,-1.000)--(-0.707,-0.707)--(-1.000,-0.000)--(-0.707,0.707)--cycle;
\draw[tth] (0.559,1.349)--(0.000,1.000) (0.559,1.349)--(0.707,0.707);
\draw[tth] (0.559,-1.349)--(0.707,-0.707) (0.559,-1.349)--(0.000,-1.000);
\draw[tth] (-0.559,-1.349)--(0.000,-1.000) (-0.559,-1.349)--(-0.707,-0.707);
\draw[tth] (0.554,0.230)--(0.707,0.707) (0.554,0.230)--(1.000,0.000);
\draw[tth] (-0.554,0.230)--(-1.000,-0.000) (-0.554,0.230)--(-0.707,0.707);
\draw[tth] (-0.230,0.554)--(-0.707,0.707) (-0.230,0.554)--(0.000,1.000);
\draw[tth] (0.000,-0.318)--(1.000,0.000) (0.000,-0.318)--(0.707,-0.707);
\draw[tth] (0.000,-0.318)--(-0.707,-0.707) (0.000,-0.318)--(-1.000,-0.000);
\node[ann] at (0.000,1.000) {};
\node[ann] at (0.707,0.707) {};
\node[ann] at (1.000,0.000) {};
\node[ann] at (0.707,-0.707) {};
\node[ann] at (0.000,-1.000) {};
\node[ann] at (-0.707,-0.707) {};
\node[ann] at (-1.000,-0.000) {};
\node[ann] at (-0.707,0.707) {};
\node[upv] at (0.559,1.349) {};
\node[upv] at (0.559,-1.349) {};
\node[upv] at (-0.559,-1.349) {};
\node[downv] at (0.554,0.230) {};
\node[downv] at (-0.554,0.230) {};
\node[downv] at (-0.230,0.554) {};
\node[bitev] at (0.000,-0.318) {};
\node[dlbl] at (0.456,1.101) {0};
\node[dlbl] at (0.704,0.292) {1};
\node[dlbl] at (0.427,-0.336) {2};
\node[dlbl] at (0.456,-1.101) {7};
\node[dlbl] at (-0.456,-1.101) {6};
\node[dlbl] at (-0.427,-0.336) {3};
\node[dlbl] at (-0.704,0.292) {4};
\node[dlbl] at (-0.292,0.704) {5};
\draw[cut] (0.000,0.840)--(0.000,1.160);
\node[cutlbl] at (0.000,1.300) {cut 1};
\draw[cut] (0.594,-0.594)--(0.820,-0.820);
\node[cutlbl] at (0.919,-0.919) {cut 2};
\node[lbl, text=blue!60!black] at (0.689,1.663) {entry};
\end{tikzpicture}
\caption{The recognised tread $T_2$ of the medial tire decomposition of a
random maximal planar graph on $20$ vertices
(Example~\ref{ex:real-cut}), with its walk-depth labelling and cut. Black
vertices are the annular medial vertices of $A(T)$; blue vertices are
up-tooth apexes and red vertices down-tooth apexes, the larger red vertex
being the shared apex of the bite on annular edges $2$ and $5$. Each
tooth carries its walk depth; the red slits are the two cuts.}
\label{fig:real-cut}
\end{figure}
Figure~\ref{fig:whole-medial} repeats the whole-medial-graph drawing on a
random maximal planar graph on $20$ vertices with minimum degree $5$
(plantri seed $59$, level source vertex $5$). The experiment recognises
two full medial tire treads, $T_1$ and $T_2$, and produces seven cuts:
one source-cap cut and six full-tread cuts. The
top panel shows the source triangulation with its level source
highlighted; the bottom panel draws $M(G)$ on the same straight-line
embedding by placing each medial vertex at the midpoint of its
corresponding source edge. Every medial vertex is labelled by that source
edge. Black vertices correspond to source edges joining consecutive
levels, and coloured vertices correspond to source edges within one level.
The red-highlighted vertices, walk-depth labels, and red slits are the
computed full-medial-tire labelling and cuts.
\begin{figure}[h]
\centering
\input{whole_medial_seed59_min5.tikz}
\caption{The source graph $G$ and the whole medial graph $M(G)$ of the
minimum-degree-$5$ maximal planar graph on $20$ vertices generated by
\texttt{plantri -m5} at seed $59$. The source vertex $5$ is highlighted
in the top panel. In the bottom panel, each medial vertex is placed at
the midpoint of its corresponding source edge and labelled by that edge.
Black vertices come from source edges between consecutive levels; coloured
vertices come from source edges within a single level of the chain. The
red-highlighted vertices, walk-depth labels, and seven red slits are the
computed source-cap cut and full-medial-tire labelling cuts for the
recognised treads $T_1$ and $T_2$. Drawn by
\texttt{experiments/draw\_medial\_tire\_cut.py} with
\texttt{--whole --min-degree 5}.}
\label{fig:whole-medial}
\end{figure}
\begin{thebibliography}{9}
\bibitem{bauerfeld-medial-tire}
E.~Bauerfeld,
\emph{Medial Tire Decompositions of Plane Triangulations},
manuscript (math-research repository), 2026.
\end{thebibliography}
\end{document}
Binary file not shown.

After

Width:  |  Height:  |  Size: 262 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 KiB

@@ -0,0 +1,403 @@
% whole medial graph: n=20 seed=59 graph_seed=59 min_degree=5 source=5 recognised treads=[1, 2] |M(G)|=54
\begin{tabular}{c}
\begin{tikzpicture}[scale=4.06,
sedge/.style={black!50, line width=0.35pt},
sv/.style={circle, draw=black!60, fill=white, inner sep=1.1pt},
srcv/.style={circle, draw=blue!75!black, fill=blue!18, line width=0.7pt, inner sep=1.8pt}]
\draw[sedge] (0.000,0.433)--(-0.500,-0.433);
\draw[sedge] (0.000,0.433)--(0.500,-0.433);
\draw[sedge] (0.000,0.433)--(0.084,-0.096);
\draw[sedge] (0.000,0.433)--(-0.018,0.026);
\draw[sedge] (0.000,0.433)--(-0.128,-0.048);
\draw[sedge] (-0.500,-0.433)--(0.500,-0.433);
\draw[sedge] (-0.500,-0.433)--(-0.128,-0.048);
\draw[sedge] (-0.500,-0.433)--(-0.073,-0.186);
\draw[sedge] (-0.500,-0.433)--(0.019,-0.303);
\draw[sedge] (0.500,-0.433)--(0.084,-0.096);
\draw[sedge] (0.500,-0.433)--(0.019,-0.303);
\draw[sedge] (0.500,-0.433)--(0.139,-0.245);
\draw[sedge] (0.084,-0.096)--(-0.018,0.026);
\draw[sedge] (0.084,-0.096)--(0.139,-0.245);
\draw[sedge] (0.084,-0.096)--(0.060,-0.177);
\draw[sedge] (0.084,-0.096)--(0.035,-0.147);
\draw[sedge] (0.084,-0.096)--(0.024,-0.131);
\draw[sedge] (0.084,-0.096)--(0.015,-0.113);
\draw[sedge] (0.084,-0.096)--(0.002,-0.076);
\draw[sedge] (-0.018,0.026)--(-0.128,-0.048);
\draw[sedge] (-0.018,0.026)--(0.002,-0.076);
\draw[sedge] (-0.018,0.026)--(-0.048,-0.081);
\draw[sedge] (-0.128,-0.048)--(-0.073,-0.186);
\draw[sedge] (-0.128,-0.048)--(-0.048,-0.081);
\draw[sedge] (-0.073,-0.186)--(0.019,-0.303);
\draw[sedge] (-0.073,-0.186)--(-0.048,-0.081);
\draw[sedge] (-0.073,-0.186)--(-0.023,-0.119);
\draw[sedge] (-0.073,-0.186)--(-0.012,-0.141);
\draw[sedge] (-0.073,-0.186)--(-0.003,-0.156);
\draw[sedge] (-0.073,-0.186)--(0.010,-0.177);
\draw[sedge] (-0.073,-0.186)--(0.031,-0.218);
\draw[sedge] (0.019,-0.303)--(0.139,-0.245);
\draw[sedge] (0.019,-0.303)--(0.031,-0.218);
\draw[sedge] (0.139,-0.245)--(0.060,-0.177);
\draw[sedge] (0.139,-0.245)--(0.031,-0.218);
\draw[sedge] (0.060,-0.177)--(0.035,-0.147);
\draw[sedge] (0.060,-0.177)--(0.010,-0.177);
\draw[sedge] (0.060,-0.177)--(0.031,-0.218);
\draw[sedge] (0.035,-0.147)--(0.024,-0.131);
\draw[sedge] (0.035,-0.147)--(-0.003,-0.156);
\draw[sedge] (0.035,-0.147)--(0.010,-0.177);
\draw[sedge] (0.024,-0.131)--(0.015,-0.113);
\draw[sedge] (0.024,-0.131)--(-0.012,-0.141);
\draw[sedge] (0.024,-0.131)--(-0.003,-0.156);
\draw[sedge] (0.015,-0.113)--(0.002,-0.076);
\draw[sedge] (0.015,-0.113)--(-0.023,-0.119);
\draw[sedge] (0.015,-0.113)--(-0.012,-0.141);
\draw[sedge] (0.002,-0.076)--(-0.048,-0.081);
\draw[sedge] (0.002,-0.076)--(-0.023,-0.119);
\draw[sedge] (-0.048,-0.081)--(-0.023,-0.119);
\draw[sedge] (-0.023,-0.119)--(-0.012,-0.141);
\draw[sedge] (-0.012,-0.141)--(-0.003,-0.156);
\draw[sedge] (-0.003,-0.156)--(0.010,-0.177);
\draw[sedge] (0.010,-0.177)--(0.031,-0.218);
\node[sv] at (0.000,0.433) {};
\node[sv] at (-0.500,-0.433) {};
\node[sv] at (0.500,-0.433) {};
\node[sv] at (0.084,-0.096) {};
\node[sv] at (-0.018,0.026) {};
\node[srcv] at (-0.128,-0.048) {};
\node[sv] at (-0.073,-0.186) {};
\node[sv] at (0.019,-0.303) {};
\node[sv] at (0.139,-0.245) {};
\node[sv] at (0.060,-0.177) {};
\node[sv] at (0.035,-0.147) {};
\node[sv] at (0.024,-0.131) {};
\node[sv] at (0.015,-0.113) {};
\node[sv] at (0.002,-0.076) {};
\node[sv] at (-0.048,-0.081) {};
\node[sv] at (-0.023,-0.119) {};
\node[sv] at (-0.012,-0.141) {};
\node[sv] at (-0.003,-0.156) {};
\node[sv] at (0.010,-0.177) {};
\node[sv] at (0.031,-0.218) {};
\node[font=\scriptsize, text=blue!70!black] at (-0.128,-0.133) {source 5};
\end{tikzpicture}
\\[-0.25ex]
{\scriptsize source graph $G$}
\\[1.0ex]
\begin{tikzpicture}[scale=7.0,
base/.style={black!12, line width=0.25pt},
med/.style={black!38, line width=0.32pt},
annv/.style={circle, draw=black!70, fill=black!18, inner sep=1.0pt},
levone/.style={circle, draw=orange!75!black, fill=orange!20, inner sep=1.2pt},
levtwo/.style={circle, draw=violet!70!black, fill=violet!18, inner sep=1.2pt},
levthree/.style={circle, draw=teal!70!black, fill=teal!18, inner sep=1.2pt},
knownv/.style={circle, draw=red!70!black, fill=red!24, inner sep=1.5pt},
elbl/.style={font=\tiny, text=black!70, inner sep=0.2pt},
dlbl/.style={font=\tiny\bfseries, text=black, inner sep=0.5pt},
cut/.style={red!80!black, line width=1.0pt},
cutlbl/.style={font=\tiny, text=red!75!black}]
\draw[base] (0.000,0.433)--(-0.500,-0.433);
\draw[base] (0.000,0.433)--(0.500,-0.433);
\draw[base] (0.000,0.433)--(0.084,-0.096);
\draw[base] (0.000,0.433)--(-0.018,0.026);
\draw[base] (0.000,0.433)--(-0.128,-0.048);
\draw[base] (-0.500,-0.433)--(0.500,-0.433);
\draw[base] (-0.500,-0.433)--(-0.128,-0.048);
\draw[base] (-0.500,-0.433)--(-0.073,-0.186);
\draw[base] (-0.500,-0.433)--(0.019,-0.303);
\draw[base] (0.500,-0.433)--(0.084,-0.096);
\draw[base] (0.500,-0.433)--(0.019,-0.303);
\draw[base] (0.500,-0.433)--(0.139,-0.245);
\draw[base] (0.084,-0.096)--(-0.018,0.026);
\draw[base] (0.084,-0.096)--(0.139,-0.245);
\draw[base] (0.084,-0.096)--(0.060,-0.177);
\draw[base] (0.084,-0.096)--(0.035,-0.147);
\draw[base] (0.084,-0.096)--(0.024,-0.131);
\draw[base] (0.084,-0.096)--(0.015,-0.113);
\draw[base] (0.084,-0.096)--(0.002,-0.076);
\draw[base] (-0.018,0.026)--(-0.128,-0.048);
\draw[base] (-0.018,0.026)--(0.002,-0.076);
\draw[base] (-0.018,0.026)--(-0.048,-0.081);
\draw[base] (-0.128,-0.048)--(-0.073,-0.186);
\draw[base] (-0.128,-0.048)--(-0.048,-0.081);
\draw[base] (-0.073,-0.186)--(0.019,-0.303);
\draw[base] (-0.073,-0.186)--(-0.048,-0.081);
\draw[base] (-0.073,-0.186)--(-0.023,-0.119);
\draw[base] (-0.073,-0.186)--(-0.012,-0.141);
\draw[base] (-0.073,-0.186)--(-0.003,-0.156);
\draw[base] (-0.073,-0.186)--(0.010,-0.177);
\draw[base] (-0.073,-0.186)--(0.031,-0.218);
\draw[base] (0.019,-0.303)--(0.139,-0.245);
\draw[base] (0.019,-0.303)--(0.031,-0.218);
\draw[base] (0.139,-0.245)--(0.060,-0.177);
\draw[base] (0.139,-0.245)--(0.031,-0.218);
\draw[base] (0.060,-0.177)--(0.035,-0.147);
\draw[base] (0.060,-0.177)--(0.010,-0.177);
\draw[base] (0.060,-0.177)--(0.031,-0.218);
\draw[base] (0.035,-0.147)--(0.024,-0.131);
\draw[base] (0.035,-0.147)--(-0.003,-0.156);
\draw[base] (0.035,-0.147)--(0.010,-0.177);
\draw[base] (0.024,-0.131)--(0.015,-0.113);
\draw[base] (0.024,-0.131)--(-0.012,-0.141);
\draw[base] (0.024,-0.131)--(-0.003,-0.156);
\draw[base] (0.015,-0.113)--(0.002,-0.076);
\draw[base] (0.015,-0.113)--(-0.023,-0.119);
\draw[base] (0.015,-0.113)--(-0.012,-0.141);
\draw[base] (0.002,-0.076)--(-0.048,-0.081);
\draw[base] (0.002,-0.076)--(-0.023,-0.119);
\draw[base] (-0.048,-0.081)--(-0.023,-0.119);
\draw[base] (-0.023,-0.119)--(-0.012,-0.141);
\draw[base] (-0.012,-0.141)--(-0.003,-0.156);
\draw[base] (-0.003,-0.156)--(0.010,-0.177);
\draw[base] (0.010,-0.177)--(0.031,-0.218);
\draw[med] (-0.250,0.000)--(-0.064,0.192);
\draw[med] (-0.250,0.000)--(0.250,0.000);
\draw[med] (-0.250,0.000)--(0.000,-0.433);
\draw[med] (-0.250,0.000)--(-0.314,-0.241);
\draw[med] (0.250,0.000)--(0.042,0.169);
\draw[med] (0.250,0.000)--(0.000,-0.433);
\draw[med] (0.250,0.000)--(0.292,-0.264);
\draw[med] (0.042,0.169)--(-0.009,0.230);
\draw[med] (0.042,0.169)--(0.292,-0.264);
\draw[med] (0.042,0.169)--(0.033,-0.035);
\draw[med] (-0.009,0.230)--(-0.064,0.192);
\draw[med] (-0.009,0.230)--(0.033,-0.035);
\draw[med] (-0.009,0.230)--(-0.073,-0.011);
\draw[med] (-0.064,0.192)--(-0.073,-0.011);
\draw[med] (-0.064,0.192)--(-0.314,-0.241);
\draw[med] (0.000,-0.433)--(-0.240,-0.368);
\draw[med] (0.000,-0.433)--(0.260,-0.368);
\draw[med] (-0.314,-0.241)--(-0.286,-0.310);
\draw[med] (-0.314,-0.241)--(-0.100,-0.117);
\draw[med] (-0.286,-0.310)--(-0.240,-0.368);
\draw[med] (-0.286,-0.310)--(-0.100,-0.117);
\draw[med] (-0.286,-0.310)--(-0.027,-0.245);
\draw[med] (-0.240,-0.368)--(-0.027,-0.245);
\draw[med] (-0.240,-0.368)--(0.260,-0.368);
\draw[med] (0.292,-0.264)--(0.319,-0.339);
\draw[med] (0.292,-0.264)--(0.111,-0.171);
\draw[med] (0.260,-0.368)--(0.319,-0.339);
\draw[med] (0.260,-0.368)--(0.079,-0.274);
\draw[med] (0.319,-0.339)--(0.079,-0.274);
\draw[med] (0.319,-0.339)--(0.111,-0.171);
\draw[med] (0.033,-0.035)--(0.043,-0.086);
\draw[med] (0.033,-0.035)--(-0.008,-0.025);
\draw[med] (0.111,-0.171)--(0.072,-0.136);
\draw[med] (0.111,-0.171)--(0.099,-0.211);
\draw[med] (0.072,-0.136)--(0.059,-0.122);
\draw[med] (0.072,-0.136)--(0.099,-0.211);
\draw[med] (0.072,-0.136)--(0.047,-0.162);
\draw[med] (0.059,-0.122)--(0.054,-0.113);
\draw[med] (0.059,-0.122)--(0.047,-0.162);
\draw[med] (0.059,-0.122)--(0.029,-0.139);
\draw[med] (0.054,-0.113)--(0.049,-0.104);
\draw[med] (0.054,-0.113)--(0.029,-0.139);
\draw[med] (0.054,-0.113)--(0.019,-0.122);
\draw[med] (0.049,-0.104)--(0.043,-0.086);
\draw[med] (0.049,-0.104)--(0.019,-0.122);
\draw[med] (0.049,-0.104)--(0.008,-0.095);
\draw[med] (0.043,-0.086)--(0.008,-0.095);
\draw[med] (0.043,-0.086)--(-0.008,-0.025);
\draw[med] (-0.073,-0.011)--(-0.033,-0.027);
\draw[med] (-0.073,-0.011)--(-0.088,-0.064);
\draw[med] (-0.008,-0.025)--(-0.033,-0.027);
\draw[med] (-0.008,-0.025)--(-0.023,-0.079);
\draw[med] (-0.033,-0.027)--(-0.023,-0.079);
\draw[med] (-0.033,-0.027)--(-0.088,-0.064);
\draw[med] (-0.100,-0.117)--(-0.088,-0.064);
\draw[med] (-0.100,-0.117)--(-0.060,-0.134);
\draw[med] (-0.088,-0.064)--(-0.060,-0.134);
\draw[med] (-0.027,-0.245)--(-0.021,-0.202);
\draw[med] (-0.027,-0.245)--(0.025,-0.260);
\draw[med] (-0.060,-0.134)--(-0.048,-0.153);
\draw[med] (-0.060,-0.134)--(-0.035,-0.100);
\draw[med] (-0.048,-0.153)--(-0.042,-0.164);
\draw[med] (-0.048,-0.153)--(-0.035,-0.100);
\draw[med] (-0.048,-0.153)--(-0.018,-0.130);
\draw[med] (-0.042,-0.164)--(-0.038,-0.171);
\draw[med] (-0.042,-0.164)--(-0.018,-0.130);
\draw[med] (-0.042,-0.164)--(-0.008,-0.149);
\draw[med] (-0.038,-0.171)--(-0.031,-0.182);
\draw[med] (-0.038,-0.171)--(-0.008,-0.149);
\draw[med] (-0.038,-0.171)--(0.003,-0.167);
\draw[med] (-0.031,-0.182)--(-0.021,-0.202);
\draw[med] (-0.031,-0.182)--(0.003,-0.167);
\draw[med] (-0.031,-0.182)--(0.021,-0.197);
\draw[med] (-0.021,-0.202)--(0.021,-0.197);
\draw[med] (-0.021,-0.202)--(0.025,-0.260);
\draw[med] (0.079,-0.274)--(0.025,-0.260);
\draw[med] (0.079,-0.274)--(0.085,-0.231);
\draw[med] (0.025,-0.260)--(0.085,-0.231);
\draw[med] (0.099,-0.211)--(0.085,-0.231);
\draw[med] (0.099,-0.211)--(0.045,-0.197);
\draw[med] (0.085,-0.231)--(0.045,-0.197);
\draw[med] (0.047,-0.162)--(0.035,-0.177);
\draw[med] (0.047,-0.162)--(0.022,-0.162);
\draw[med] (0.035,-0.177)--(0.045,-0.197);
\draw[med] (0.035,-0.177)--(0.021,-0.197);
\draw[med] (0.035,-0.177)--(0.022,-0.162);
\draw[med] (0.045,-0.197)--(0.021,-0.197);
\draw[med] (0.029,-0.139)--(0.016,-0.152);
\draw[med] (0.029,-0.139)--(0.010,-0.144);
\draw[med] (0.016,-0.152)--(0.022,-0.162);
\draw[med] (0.016,-0.152)--(0.003,-0.167);
\draw[med] (0.016,-0.152)--(0.010,-0.144);
\draw[med] (0.022,-0.162)--(0.003,-0.167);
\draw[med] (0.019,-0.122)--(0.006,-0.136);
\draw[med] (0.019,-0.122)--(0.001,-0.127);
\draw[med] (0.006,-0.136)--(0.010,-0.144);
\draw[med] (0.006,-0.136)--(-0.008,-0.149);
\draw[med] (0.006,-0.136)--(0.001,-0.127);
\draw[med] (0.010,-0.144)--(-0.008,-0.149);
\draw[med] (0.008,-0.095)--(-0.004,-0.116);
\draw[med] (0.008,-0.095)--(-0.011,-0.098);
\draw[med] (-0.004,-0.116)--(0.001,-0.127);
\draw[med] (-0.004,-0.116)--(-0.018,-0.130);
\draw[med] (-0.004,-0.116)--(-0.011,-0.098);
\draw[med] (0.001,-0.127)--(-0.018,-0.130);
\draw[med] (-0.023,-0.079)--(-0.011,-0.098);
\draw[med] (-0.023,-0.079)--(-0.035,-0.100);
\draw[med] (-0.011,-0.098)--(-0.035,-0.100);
\node[knownv] at (-0.250,0.000) {};
\node[annv] at (0.250,0.000) {};
\node[annv] at (0.042,0.169) {};
\node[knownv] at (-0.009,0.230) {};
\node[annv] at (-0.064,0.192) {};
\node[annv] at (0.000,-0.433) {};
\node[annv] at (-0.314,-0.241) {};
\node[knownv] at (-0.286,-0.310) {};
\node[annv] at (-0.240,-0.368) {};
\node[knownv] at (0.292,-0.264) {};
\node[knownv] at (0.260,-0.368) {};
\node[annv] at (0.319,-0.339) {};
\node[annv] at (0.033,-0.035) {};
\node[annv] at (0.111,-0.171) {};
\node[annv] at (0.072,-0.136) {};
\node[annv] at (-0.073,-0.011) {};
\node[annv] at (-0.100,-0.117) {};
\node[annv] at (-0.027,-0.245) {};
\node[annv] at (0.079,-0.274) {};
\node[knownv] at (0.099,-0.211) {};
\node[annv] at (0.059,-0.122) {};
\node[knownv] at (0.047,-0.162) {};
\node[knownv] at (0.029,-0.139) {};
\node[annv] at (0.016,-0.152) {};
\node[annv] at (0.022,-0.162) {};
\node[annv] at (0.054,-0.113) {};
\node[knownv] at (0.019,-0.122) {};
\node[annv] at (0.006,-0.136) {};
\node[annv] at (0.010,-0.144) {};
\node[annv] at (0.049,-0.104) {};
\node[annv] at (0.008,-0.095) {};
\node[annv] at (-0.004,-0.116) {};
\node[annv] at (0.001,-0.127) {};
\node[knownv] at (0.043,-0.086) {};
\node[annv] at (-0.008,-0.025) {};
\node[annv] at (-0.023,-0.079) {};
\node[knownv] at (-0.011,-0.098) {};
\node[knownv] at (-0.033,-0.027) {};
\node[annv] at (-0.088,-0.064) {};
\node[knownv] at (-0.060,-0.134) {};
\node[annv] at (-0.035,-0.100) {};
\node[annv] at (-0.048,-0.153) {};
\node[knownv] at (-0.018,-0.130) {};
\node[annv] at (-0.042,-0.164) {};
\node[knownv] at (-0.008,-0.149) {};
\node[annv] at (-0.038,-0.171) {};
\node[knownv] at (0.003,-0.167) {};
\node[annv] at (-0.031,-0.182) {};
\node[annv] at (0.035,-0.177) {};
\node[knownv] at (0.021,-0.197) {};
\node[annv] at (-0.021,-0.202) {};
\node[knownv] at (0.025,-0.260) {};
\node[annv] at (0.085,-0.231) {};
\node[annv] at (0.045,-0.197) {};
\node[elbl] at (-0.250,0.000) [yshift=-4.8pt] {$0\!{-}\!1$};
\node[elbl] at (0.250,0.000) [yshift=-4.8pt] {$0\!{-}\!2$};
\node[elbl] at (0.042,0.169) [yshift=-4.8pt] {$0\!{-}\!3$};
\node[elbl] at (-0.009,0.230) [yshift=-4.8pt] {$0\!{-}\!4$};
\node[elbl] at (-0.064,0.192) [yshift=-4.8pt] {$0\!{-}\!5$};
\node[elbl] at (0.000,-0.433) [yshift=-4.8pt] {$1\!{-}\!2$};
\node[elbl] at (-0.314,-0.241) [yshift=-4.8pt] {$1\!{-}\!5$};
\node[elbl] at (-0.286,-0.310) [yshift=-4.8pt] {$1\!{-}\!6$};
\node[elbl] at (-0.240,-0.368) [yshift=-4.8pt] {$1\!{-}\!7$};
\node[elbl] at (0.292,-0.264) [yshift=-4.8pt] {$2\!{-}\!3$};
\node[elbl] at (0.260,-0.368) [yshift=-4.8pt] {$2\!{-}\!7$};
\node[elbl] at (0.319,-0.339) [yshift=-4.8pt] {$2\!{-}\!8$};
\node[elbl] at (0.033,-0.035) [yshift=-4.8pt] {$3\!{-}\!4$};
\node[elbl] at (0.111,-0.171) [yshift=-4.8pt] {$3\!{-}\!8$};
\node[elbl] at (0.072,-0.136) [yshift=-4.8pt] {$3\!{-}\!9$};
\node[elbl] at (-0.073,-0.011) [yshift=-4.8pt] {$4\!{-}\!5$};
\node[elbl] at (-0.100,-0.117) [yshift=-4.8pt] {$5\!{-}\!6$};
\node[elbl] at (-0.027,-0.245) [yshift=-4.8pt] {$6\!{-}\!7$};
\node[elbl] at (0.079,-0.274) [yshift=-4.8pt] {$7\!{-}\!8$};
\node[elbl] at (0.099,-0.211) [yshift=-4.8pt] {$8\!{-}\!9$};
\node[elbl] at (0.059,-0.122) [yshift=-4.8pt] {$10\!{-}\!3$};
\node[elbl] at (0.047,-0.162) [yshift=-4.8pt] {$10\!{-}\!9$};
\node[elbl] at (0.029,-0.139) [yshift=-4.8pt] {$10\!{-}\!11$};
\node[elbl] at (0.016,-0.152) [yshift=-4.8pt] {$10\!{-}\!17$};
\node[elbl] at (0.022,-0.162) [yshift=-4.8pt] {$10\!{-}\!18$};
\node[elbl] at (0.054,-0.113) [yshift=-4.8pt] {$11\!{-}\!3$};
\node[elbl] at (0.019,-0.122) [yshift=-4.8pt] {$11\!{-}\!12$};
\node[elbl] at (0.006,-0.136) [yshift=-4.8pt] {$11\!{-}\!16$};
\node[elbl] at (0.010,-0.144) [yshift=-4.8pt] {$11\!{-}\!17$};
\node[elbl] at (0.049,-0.104) [yshift=-4.8pt] {$12\!{-}\!3$};
\node[elbl] at (0.008,-0.095) [yshift=-4.8pt] {$12\!{-}\!13$};
\node[elbl] at (-0.004,-0.116) [yshift=-4.8pt] {$12\!{-}\!15$};
\node[elbl] at (0.001,-0.127) [yshift=-4.8pt] {$12\!{-}\!16$};
\node[elbl] at (0.043,-0.086) [yshift=-4.8pt] {$13\!{-}\!3$};
\node[elbl] at (-0.008,-0.025) [yshift=-4.8pt] {$13\!{-}\!4$};
\node[elbl] at (-0.023,-0.079) [yshift=-4.8pt] {$13\!{-}\!14$};
\node[elbl] at (-0.011,-0.098) [yshift=-4.8pt] {$13\!{-}\!15$};
\node[elbl] at (-0.033,-0.027) [yshift=-4.8pt] {$14\!{-}\!4$};
\node[elbl] at (-0.088,-0.064) [yshift=-4.8pt] {$14\!{-}\!5$};
\node[elbl] at (-0.060,-0.134) [yshift=-4.8pt] {$14\!{-}\!6$};
\node[elbl] at (-0.035,-0.100) [yshift=-4.8pt] {$14\!{-}\!15$};
\node[elbl] at (-0.048,-0.153) [yshift=-4.8pt] {$15\!{-}\!6$};
\node[elbl] at (-0.018,-0.130) [yshift=-4.8pt] {$15\!{-}\!16$};
\node[elbl] at (-0.042,-0.164) [yshift=-4.8pt] {$16\!{-}\!6$};
\node[elbl] at (-0.008,-0.149) [yshift=-4.8pt] {$16\!{-}\!17$};
\node[elbl] at (-0.038,-0.171) [yshift=-4.8pt] {$17\!{-}\!6$};
\node[elbl] at (0.003,-0.167) [yshift=-4.8pt] {$17\!{-}\!18$};
\node[elbl] at (-0.031,-0.182) [yshift=-4.8pt] {$18\!{-}\!6$};
\node[elbl] at (0.035,-0.177) [yshift=-4.8pt] {$18\!{-}\!9$};
\node[elbl] at (0.021,-0.197) [yshift=-4.8pt] {$18\!{-}\!19$};
\node[elbl] at (-0.021,-0.202) [yshift=-4.8pt] {$19\!{-}\!6$};
\node[elbl] at (0.025,-0.260) [yshift=-4.8pt] {$19\!{-}\!7$};
\node[elbl] at (0.085,-0.231) [yshift=-4.8pt] {$19\!{-}\!8$};
\node[elbl] at (0.045,-0.197) [yshift=-4.8pt] {$19\!{-}\!9$};
\node[dlbl] at (-0.250,0.000) [yshift=5.0pt] {4};
\node[dlbl] at (-0.009,0.230) [yshift=5.0pt] {2};
\node[dlbl] at (-0.286,-0.310) [yshift=5.0pt] {6};
\node[dlbl] at (0.292,-0.264) [yshift=5.0pt] {3,18};
\node[dlbl] at (0.260,-0.368) [yshift=5.0pt] {5,17};
\node[dlbl] at (0.099,-0.211) [yshift=5.0pt] {13,14};
\node[dlbl] at (0.047,-0.162) [yshift=5.0pt] {11,12};
\node[dlbl] at (0.029,-0.139) [yshift=5.0pt] {7,8};
\node[dlbl] at (0.019,-0.122) [yshift=5.0pt] {5,6};
\node[dlbl] at (0.043,-0.086) [yshift=5.0pt] {1,2};
\node[dlbl] at (-0.011,-0.098) [yshift=5.0pt] {3,13};
\node[dlbl] at (-0.033,-0.027) [yshift=5.0pt] {0};
\node[dlbl] at (-0.060,-0.134) [yshift=5.0pt] {12};
\node[dlbl] at (-0.018,-0.130) [yshift=5.0pt] {4,11};
\node[dlbl] at (-0.008,-0.149) [yshift=5.0pt] {9,10};
\node[dlbl] at (0.003,-0.167) [yshift=5.0pt] {9,10};
\node[dlbl] at (0.021,-0.197) [yshift=5.0pt] {8,15};
\node[dlbl] at (0.025,-0.260) [yshift=5.0pt] {7,16};
\draw[cut] (-0.075,-0.032)--(-0.101,-0.097);
\node[cutlbl] at (-0.120,-0.142) {cut 1};
\draw[cut] (-0.026,-0.044)--(-0.020,-0.114);
\node[cutlbl] at (-0.016,-0.162) {cut 2};
\draw[cut] (0.058,-0.138)--(0.041,-0.070);
\node[cutlbl] at (0.030,-0.023) {cut 3};
\draw[cut] (-0.004,-0.102)--(0.016,-0.169);
\node[cutlbl] at (0.029,-0.217) {cut 4};
\draw[cut] (0.085,-0.146)--(0.034,-0.097);
\node[cutlbl] at (-0.001,-0.063) {cut 5};
\draw[cut] (0.035,-0.212)--(0.035,-0.142);
\node[cutlbl] at (0.034,-0.093) {cut 6};
\draw[cut] (0.079,-0.183)--(0.144,-0.158);
\node[cutlbl] at (0.190,-0.142) {cut 7};
\end{tikzpicture}
\\[-0.25ex]
{\scriptsize medial graph $M(G)$ at edge midpoints}
\end{tabular}
@@ -0,0 +1,382 @@
% whole medial graph: n=20 seed=72 source=9 recognised treads=[2] |M(G)|=54
\begin{tabular}{c}
\begin{tikzpicture}[scale=4.06,
sedge/.style={black!50, line width=0.35pt},
sv/.style={circle, draw=black!60, fill=white, inner sep=1.1pt},
srcv/.style={circle, draw=blue!75!black, fill=blue!18, line width=0.7pt, inner sep=1.8pt}]
\draw[sedge] (0.000,0.433)--(-0.500,-0.433);
\draw[sedge] (0.000,0.433)--(0.500,-0.433);
\draw[sedge] (0.000,0.433)--(0.027,-0.257);
\draw[sedge] (0.000,0.433)--(0.199,-0.203);
\draw[sedge] (0.000,0.433)--(-0.158,-0.086);
\draw[sedge] (-0.500,-0.433)--(0.500,-0.433);
\draw[sedge] (-0.500,-0.433)--(0.027,-0.257);
\draw[sedge] (-0.500,-0.433)--(0.012,-0.355);
\draw[sedge] (-0.500,-0.433)--(-0.170,-0.348);
\draw[sedge] (-0.500,-0.433)--(-0.218,-0.346);
\draw[sedge] (-0.500,-0.433)--(-0.158,-0.086);
\draw[sedge] (-0.500,-0.433)--(-0.230,-0.345);
\draw[sedge] (0.500,-0.433)--(0.027,-0.257);
\draw[sedge] (0.500,-0.433)--(0.199,-0.203);
\draw[sedge] (0.500,-0.433)--(0.012,-0.355);
\draw[sedge] (0.500,-0.433)--(0.234,-0.280);
\draw[sedge] (0.500,-0.433)--(0.292,-0.291);
\draw[sedge] (0.500,-0.433)--(0.151,-0.341);
\draw[sedge] (0.500,-0.433)--(0.254,-0.323);
\draw[sedge] (0.027,-0.257)--(0.199,-0.203);
\draw[sedge] (0.027,-0.257)--(0.012,-0.355);
\draw[sedge] (0.027,-0.257)--(0.234,-0.280);
\draw[sedge] (0.027,-0.257)--(-0.170,-0.348);
\draw[sedge] (0.027,-0.257)--(0.151,-0.341);
\draw[sedge] (0.027,-0.257)--(0.254,-0.323);
\draw[sedge] (0.027,-0.257)--(-0.218,-0.346);
\draw[sedge] (0.027,-0.257)--(0.063,-0.317);
\draw[sedge] (0.027,-0.257)--(0.146,-0.243);
\draw[sedge] (0.027,-0.257)--(-0.158,-0.086);
\draw[sedge] (0.027,-0.257)--(0.124,-0.234);
\draw[sedge] (0.027,-0.257)--(-0.230,-0.345);
\draw[sedge] (0.199,-0.203)--(0.234,-0.280);
\draw[sedge] (0.199,-0.203)--(0.292,-0.291);
\draw[sedge] (0.199,-0.203)--(0.233,-0.249);
\draw[sedge] (0.199,-0.203)--(0.221,-0.241);
\draw[sedge] (0.199,-0.203)--(0.146,-0.243);
\draw[sedge] (0.199,-0.203)--(0.218,-0.231);
\draw[sedge] (0.199,-0.203)--(0.124,-0.234);
\draw[sedge] (0.012,-0.355)--(-0.170,-0.348);
\draw[sedge] (0.012,-0.355)--(0.151,-0.341);
\draw[sedge] (0.012,-0.355)--(0.063,-0.317);
\draw[sedge] (0.234,-0.280)--(0.292,-0.291);
\draw[sedge] (0.234,-0.280)--(0.233,-0.249);
\draw[sedge] (0.234,-0.280)--(0.254,-0.323);
\draw[sedge] (0.234,-0.280)--(0.221,-0.241);
\draw[sedge] (0.234,-0.280)--(0.146,-0.243);
\draw[sedge] (0.292,-0.291)--(0.233,-0.249);
\draw[sedge] (0.233,-0.249)--(0.221,-0.241);
\draw[sedge] (0.233,-0.249)--(0.218,-0.231);
\draw[sedge] (-0.170,-0.348)--(-0.218,-0.346);
\draw[sedge] (0.151,-0.341)--(0.063,-0.317);
\draw[sedge] (-0.218,-0.346)--(-0.230,-0.345);
\draw[sedge] (0.221,-0.241)--(0.218,-0.231);
\draw[sedge] (0.146,-0.243)--(0.124,-0.234);
\node[sv] at (0.000,0.433) {};
\node[sv] at (-0.500,-0.433) {};
\node[sv] at (0.500,-0.433) {};
\node[sv] at (0.027,-0.257) {};
\node[sv] at (0.199,-0.203) {};
\node[sv] at (0.012,-0.355) {};
\node[sv] at (0.234,-0.280) {};
\node[sv] at (0.292,-0.291) {};
\node[sv] at (0.233,-0.249) {};
\node[srcv] at (-0.170,-0.348) {};
\node[sv] at (0.151,-0.341) {};
\node[sv] at (0.254,-0.323) {};
\node[sv] at (-0.218,-0.346) {};
\node[sv] at (0.221,-0.241) {};
\node[sv] at (0.063,-0.317) {};
\node[sv] at (0.146,-0.243) {};
\node[sv] at (0.218,-0.231) {};
\node[sv] at (-0.158,-0.086) {};
\node[sv] at (0.124,-0.234) {};
\node[sv] at (-0.230,-0.345) {};
\node[font=\scriptsize, text=blue!70!black] at (-0.170,-0.433) {source 9};
\end{tikzpicture}
\\[-0.25ex]
{\scriptsize source graph $G$}
\\[1.0ex]
\begin{tikzpicture}[scale=7.0,
base/.style={black!12, line width=0.25pt},
med/.style={black!38, line width=0.32pt},
annv/.style={circle, draw=black!70, fill=black!18, inner sep=1.0pt},
levone/.style={circle, draw=orange!75!black, fill=orange!20, inner sep=1.2pt},
levtwo/.style={circle, draw=violet!70!black, fill=violet!18, inner sep=1.2pt},
levthree/.style={circle, draw=teal!70!black, fill=teal!18, inner sep=1.2pt},
knownv/.style={circle, draw=red!70!black, fill=red!24, inner sep=1.5pt},
elbl/.style={font=\tiny, text=black!70, inner sep=0.2pt},
dlbl/.style={font=\tiny\bfseries, text=black, inner sep=0.5pt},
cut/.style={red!80!black, line width=1.0pt},
cutlbl/.style={font=\tiny, text=red!75!black}]
\draw[base] (0.000,0.433)--(-0.500,-0.433);
\draw[base] (0.000,0.433)--(0.500,-0.433);
\draw[base] (0.000,0.433)--(0.027,-0.257);
\draw[base] (0.000,0.433)--(0.199,-0.203);
\draw[base] (0.000,0.433)--(-0.158,-0.086);
\draw[base] (-0.500,-0.433)--(0.500,-0.433);
\draw[base] (-0.500,-0.433)--(0.027,-0.257);
\draw[base] (-0.500,-0.433)--(0.012,-0.355);
\draw[base] (-0.500,-0.433)--(-0.170,-0.348);
\draw[base] (-0.500,-0.433)--(-0.218,-0.346);
\draw[base] (-0.500,-0.433)--(-0.158,-0.086);
\draw[base] (-0.500,-0.433)--(-0.230,-0.345);
\draw[base] (0.500,-0.433)--(0.027,-0.257);
\draw[base] (0.500,-0.433)--(0.199,-0.203);
\draw[base] (0.500,-0.433)--(0.012,-0.355);
\draw[base] (0.500,-0.433)--(0.234,-0.280);
\draw[base] (0.500,-0.433)--(0.292,-0.291);
\draw[base] (0.500,-0.433)--(0.151,-0.341);
\draw[base] (0.500,-0.433)--(0.254,-0.323);
\draw[base] (0.027,-0.257)--(0.199,-0.203);
\draw[base] (0.027,-0.257)--(0.012,-0.355);
\draw[base] (0.027,-0.257)--(0.234,-0.280);
\draw[base] (0.027,-0.257)--(-0.170,-0.348);
\draw[base] (0.027,-0.257)--(0.151,-0.341);
\draw[base] (0.027,-0.257)--(0.254,-0.323);
\draw[base] (0.027,-0.257)--(-0.218,-0.346);
\draw[base] (0.027,-0.257)--(0.063,-0.317);
\draw[base] (0.027,-0.257)--(0.146,-0.243);
\draw[base] (0.027,-0.257)--(-0.158,-0.086);
\draw[base] (0.027,-0.257)--(0.124,-0.234);
\draw[base] (0.027,-0.257)--(-0.230,-0.345);
\draw[base] (0.199,-0.203)--(0.234,-0.280);
\draw[base] (0.199,-0.203)--(0.292,-0.291);
\draw[base] (0.199,-0.203)--(0.233,-0.249);
\draw[base] (0.199,-0.203)--(0.221,-0.241);
\draw[base] (0.199,-0.203)--(0.146,-0.243);
\draw[base] (0.199,-0.203)--(0.218,-0.231);
\draw[base] (0.199,-0.203)--(0.124,-0.234);
\draw[base] (0.012,-0.355)--(-0.170,-0.348);
\draw[base] (0.012,-0.355)--(0.151,-0.341);
\draw[base] (0.012,-0.355)--(0.063,-0.317);
\draw[base] (0.234,-0.280)--(0.292,-0.291);
\draw[base] (0.234,-0.280)--(0.233,-0.249);
\draw[base] (0.234,-0.280)--(0.254,-0.323);
\draw[base] (0.234,-0.280)--(0.221,-0.241);
\draw[base] (0.234,-0.280)--(0.146,-0.243);
\draw[base] (0.292,-0.291)--(0.233,-0.249);
\draw[base] (0.233,-0.249)--(0.221,-0.241);
\draw[base] (0.233,-0.249)--(0.218,-0.231);
\draw[base] (-0.170,-0.348)--(-0.218,-0.346);
\draw[base] (0.151,-0.341)--(0.063,-0.317);
\draw[base] (-0.218,-0.346)--(-0.230,-0.345);
\draw[base] (0.221,-0.241)--(0.218,-0.231);
\draw[base] (0.146,-0.243)--(0.124,-0.234);
\draw[med] (-0.250,0.000)--(-0.079,0.174);
\draw[med] (-0.250,0.000)--(0.250,0.000);
\draw[med] (-0.250,0.000)--(0.000,-0.433);
\draw[med] (-0.250,0.000)--(-0.329,-0.259);
\draw[med] (0.250,0.000)--(0.100,0.115);
\draw[med] (0.250,0.000)--(0.000,-0.433);
\draw[med] (0.250,0.000)--(0.350,-0.318);
\draw[med] (0.014,0.088)--(-0.079,0.174);
\draw[med] (0.014,0.088)--(0.100,0.115);
\draw[med] (0.014,0.088)--(0.113,-0.230);
\draw[med] (0.014,0.088)--(-0.065,-0.171);
\draw[med] (0.100,0.115)--(0.350,-0.318);
\draw[med] (0.100,0.115)--(0.113,-0.230);
\draw[med] (-0.079,0.174)--(-0.065,-0.171);
\draw[med] (-0.079,0.174)--(-0.329,-0.259);
\draw[med] (0.000,-0.433)--(-0.244,-0.394);
\draw[med] (0.000,-0.433)--(0.256,-0.394);
\draw[med] (-0.236,-0.345)--(-0.365,-0.389);
\draw[med] (-0.236,-0.345)--(-0.329,-0.259);
\draw[med] (-0.236,-0.345)--(-0.065,-0.171);
\draw[med] (-0.236,-0.345)--(-0.102,-0.301);
\draw[med] (-0.244,-0.394)--(-0.335,-0.390);
\draw[med] (-0.244,-0.394)--(-0.079,-0.351);
\draw[med] (-0.244,-0.394)--(0.256,-0.394);
\draw[med] (-0.335,-0.390)--(-0.359,-0.389);
\draw[med] (-0.335,-0.390)--(-0.194,-0.347);
\draw[med] (-0.335,-0.390)--(-0.079,-0.351);
\draw[med] (-0.359,-0.389)--(-0.365,-0.389);
\draw[med] (-0.359,-0.389)--(-0.224,-0.345);
\draw[med] (-0.359,-0.389)--(-0.194,-0.347);
\draw[med] (-0.329,-0.259)--(-0.065,-0.171);
\draw[med] (-0.365,-0.389)--(-0.102,-0.301);
\draw[med] (-0.365,-0.389)--(-0.224,-0.345);
\draw[med] (0.264,-0.345)--(0.377,-0.378);
\draw[med] (0.264,-0.345)--(0.325,-0.387);
\draw[med] (0.264,-0.345)--(0.140,-0.290);
\draw[med] (0.264,-0.345)--(0.089,-0.299);
\draw[med] (0.350,-0.318)--(0.396,-0.362);
\draw[med] (0.350,-0.318)--(0.245,-0.247);
\draw[med] (0.256,-0.394)--(0.325,-0.387);
\draw[med] (0.256,-0.394)--(0.081,-0.348);
\draw[med] (0.367,-0.357)--(0.396,-0.362);
\draw[med] (0.367,-0.357)--(0.377,-0.378);
\draw[med] (0.367,-0.357)--(0.244,-0.302);
\draw[med] (0.367,-0.357)--(0.263,-0.286);
\draw[med] (0.396,-0.362)--(0.263,-0.286);
\draw[med] (0.396,-0.362)--(0.245,-0.247);
\draw[med] (0.325,-0.387)--(0.081,-0.348);
\draw[med] (0.325,-0.387)--(0.089,-0.299);
\draw[med] (0.377,-0.378)--(0.140,-0.290);
\draw[med] (0.377,-0.378)--(0.244,-0.302);
\draw[med] (0.113,-0.230)--(0.076,-0.246);
\draw[med] (0.113,-0.230)--(0.162,-0.218);
\draw[med] (0.019,-0.306)--(-0.071,-0.302);
\draw[med] (0.019,-0.306)--(0.045,-0.287);
\draw[med] (0.019,-0.306)--(-0.079,-0.351);
\draw[med] (0.019,-0.306)--(0.038,-0.336);
\draw[med] (0.131,-0.268)--(0.140,-0.290);
\draw[med] (0.131,-0.268)--(0.087,-0.250);
\draw[med] (0.131,-0.268)--(0.190,-0.262);
\draw[med] (0.131,-0.268)--(0.244,-0.302);
\draw[med] (-0.071,-0.302)--(-0.096,-0.301);
\draw[med] (-0.071,-0.302)--(-0.079,-0.351);
\draw[med] (-0.071,-0.302)--(-0.194,-0.347);
\draw[med] (0.089,-0.299)--(0.045,-0.287);
\draw[med] (0.089,-0.299)--(0.107,-0.329);
\draw[med] (0.140,-0.290)--(0.244,-0.302);
\draw[med] (-0.096,-0.301)--(-0.102,-0.301);
\draw[med] (-0.096,-0.301)--(-0.194,-0.347);
\draw[med] (-0.096,-0.301)--(-0.224,-0.345);
\draw[med] (0.045,-0.287)--(0.107,-0.329);
\draw[med] (0.045,-0.287)--(0.038,-0.336);
\draw[med] (0.087,-0.250)--(0.076,-0.246);
\draw[med] (0.087,-0.250)--(0.135,-0.239);
\draw[med] (0.087,-0.250)--(0.190,-0.262);
\draw[med] (0.076,-0.246)--(0.162,-0.218);
\draw[med] (0.076,-0.246)--(0.135,-0.239);
\draw[med] (-0.102,-0.301)--(-0.224,-0.345);
\draw[med] (0.217,-0.241)--(0.173,-0.223);
\draw[med] (0.217,-0.241)--(0.210,-0.222);
\draw[med] (0.217,-0.241)--(0.190,-0.262);
\draw[med] (0.217,-0.241)--(0.227,-0.260);
\draw[med] (0.245,-0.247)--(0.216,-0.226);
\draw[med] (0.245,-0.247)--(0.262,-0.270);
\draw[med] (0.216,-0.226)--(0.209,-0.217);
\draw[med] (0.216,-0.226)--(0.262,-0.270);
\draw[med] (0.216,-0.226)--(0.225,-0.240);
\draw[med] (0.210,-0.222)--(0.209,-0.217);
\draw[med] (0.210,-0.222)--(0.219,-0.236);
\draw[med] (0.210,-0.222)--(0.227,-0.260);
\draw[med] (0.173,-0.223)--(0.162,-0.218);
\draw[med] (0.173,-0.223)--(0.190,-0.262);
\draw[med] (0.173,-0.223)--(0.135,-0.239);
\draw[med] (0.209,-0.217)--(0.225,-0.240);
\draw[med] (0.209,-0.217)--(0.219,-0.236);
\draw[med] (0.162,-0.218)--(0.135,-0.239);
\draw[med] (0.081,-0.348)--(0.038,-0.336);
\draw[med] (0.081,-0.348)--(0.107,-0.329);
\draw[med] (0.038,-0.336)--(0.107,-0.329);
\draw[med] (0.263,-0.286)--(0.233,-0.265);
\draw[med] (0.263,-0.286)--(0.262,-0.270);
\draw[med] (0.233,-0.265)--(0.227,-0.260);
\draw[med] (0.233,-0.265)--(0.227,-0.245);
\draw[med] (0.233,-0.265)--(0.262,-0.270);
\draw[med] (0.227,-0.260)--(0.227,-0.245);
\draw[med] (0.227,-0.245)--(0.225,-0.240);
\draw[med] (0.227,-0.245)--(0.219,-0.236);
\draw[med] (0.225,-0.240)--(0.219,-0.236);
\node[annv] at (-0.250,0.000) {};
\node[levtwo] at (0.250,0.000) {};
\node[annv] at (0.014,0.088) {};
\node[levtwo] at (0.100,0.115) {};
\node[levtwo] at (-0.079,0.174) {};
\node[annv] at (0.000,-0.433) {};
\node[levone] at (-0.236,-0.345) {};
\node[levone] at (-0.244,-0.394) {};
\node[annv] at (-0.335,-0.390) {};
\node[levone] at (-0.359,-0.389) {};
\node[annv] at (-0.329,-0.259) {};
\node[annv] at (-0.365,-0.389) {};
\node[annv] at (0.264,-0.345) {};
\node[knownv] at (0.350,-0.318) {};
\node[annv] at (0.256,-0.394) {};
\node[knownv] at (0.367,-0.357) {};
\node[annv] at (0.396,-0.362) {};
\node[annv] at (0.113,-0.230) {};
\node[levone] at (0.019,-0.306) {};
\node[annv] at (0.131,-0.268) {};
\node[annv] at (-0.071,-0.302) {};
\node[knownv] at (0.217,-0.241) {};
\node[annv] at (0.245,-0.247) {};
\node[annv] at (0.216,-0.226) {};
\node[annv] at (-0.079,-0.351) {};
\node[annv] at (0.263,-0.286) {};
\node[annv] at (0.233,-0.265) {};
\node[knownv] at (0.262,-0.270) {};
\node[levtwo] at (0.325,-0.387) {};
\node[annv] at (0.089,-0.299) {};
\node[annv] at (0.081,-0.348) {};
\node[levtwo] at (0.107,-0.329) {};
\node[levtwo] at (0.377,-0.378) {};
\node[annv] at (0.140,-0.290) {};
\node[levtwo] at (0.244,-0.302) {};
\node[levone] at (-0.096,-0.301) {};
\node[annv] at (-0.194,-0.347) {};
\node[annv] at (-0.224,-0.345) {};
\node[annv] at (0.210,-0.222) {};
\node[annv] at (0.227,-0.260) {};
\node[knownv] at (0.227,-0.245) {};
\node[knownv] at (0.219,-0.236) {};
\node[annv] at (0.045,-0.287) {};
\node[annv] at (0.038,-0.336) {};
\node[annv] at (0.087,-0.250) {};
\node[levtwo] at (0.173,-0.223) {};
\node[levtwo] at (0.190,-0.262) {};
\node[levtwo] at (0.135,-0.239) {};
\node[annv] at (0.209,-0.217) {};
\node[knownv] at (0.225,-0.240) {};
\node[annv] at (-0.065,-0.171) {};
\node[annv] at (0.076,-0.246) {};
\node[levtwo] at (0.162,-0.218) {};
\node[annv] at (-0.102,-0.301) {};
\node[elbl] at (-0.250,0.000) [yshift=-4.8pt] {$0\!{-}\!1$};
\node[elbl] at (0.250,0.000) [yshift=-4.8pt] {$0\!{-}\!2$};
\node[elbl] at (0.014,0.088) [yshift=-4.8pt] {$0\!{-}\!3$};
\node[elbl] at (0.100,0.115) [yshift=-4.8pt] {$0\!{-}\!4$};
\node[elbl] at (-0.079,0.174) [yshift=-4.8pt] {$0\!{-}\!17$};
\node[elbl] at (0.000,-0.433) [yshift=-4.8pt] {$1\!{-}\!2$};
\node[elbl] at (-0.236,-0.345) [yshift=-4.8pt] {$1\!{-}\!3$};
\node[elbl] at (-0.244,-0.394) [yshift=-4.8pt] {$1\!{-}\!5$};
\node[elbl] at (-0.335,-0.390) [yshift=-4.8pt] {$1\!{-}\!9$};
\node[elbl] at (-0.359,-0.389) [yshift=-4.8pt] {$1\!{-}\!12$};
\node[elbl] at (-0.329,-0.259) [yshift=-4.8pt] {$1\!{-}\!17$};
\node[elbl] at (-0.365,-0.389) [yshift=-4.8pt] {$1\!{-}\!19$};
\node[elbl] at (0.264,-0.345) [yshift=-4.8pt] {$2\!{-}\!3$};
\node[elbl] at (0.350,-0.318) [yshift=-4.8pt] {$2\!{-}\!4$};
\node[elbl] at (0.256,-0.394) [yshift=-4.8pt] {$2\!{-}\!5$};
\node[elbl] at (0.367,-0.357) [yshift=-4.8pt] {$2\!{-}\!6$};
\node[elbl] at (0.396,-0.362) [yshift=-4.8pt] {$2\!{-}\!7$};
\node[elbl] at (0.113,-0.230) [yshift=-4.8pt] {$3\!{-}\!4$};
\node[elbl] at (0.019,-0.306) [yshift=-4.8pt] {$3\!{-}\!5$};
\node[elbl] at (0.131,-0.268) [yshift=-4.8pt] {$3\!{-}\!6$};
\node[elbl] at (-0.071,-0.302) [yshift=-4.8pt] {$3\!{-}\!9$};
\node[elbl] at (0.217,-0.241) [yshift=-4.8pt] {$4\!{-}\!6$};
\node[elbl] at (0.245,-0.247) [yshift=-4.8pt] {$4\!{-}\!7$};
\node[elbl] at (0.216,-0.226) [yshift=-4.8pt] {$4\!{-}\!8$};
\node[elbl] at (-0.079,-0.351) [yshift=-4.8pt] {$5\!{-}\!9$};
\node[elbl] at (0.263,-0.286) [yshift=-4.8pt] {$6\!{-}\!7$};
\node[elbl] at (0.233,-0.265) [yshift=-4.8pt] {$6\!{-}\!8$};
\node[elbl] at (0.262,-0.270) [yshift=-4.8pt] {$7\!{-}\!8$};
\node[elbl] at (0.325,-0.387) [yshift=-4.8pt] {$10\!{-}\!2$};
\node[elbl] at (0.089,-0.299) [yshift=-4.8pt] {$10\!{-}\!3$};
\node[elbl] at (0.081,-0.348) [yshift=-4.8pt] {$10\!{-}\!5$};
\node[elbl] at (0.107,-0.329) [yshift=-4.8pt] {$10\!{-}\!14$};
\node[elbl] at (0.377,-0.378) [yshift=-4.8pt] {$11\!{-}\!2$};
\node[elbl] at (0.140,-0.290) [yshift=-4.8pt] {$11\!{-}\!3$};
\node[elbl] at (0.244,-0.302) [yshift=-4.8pt] {$11\!{-}\!6$};
\node[elbl] at (-0.096,-0.301) [yshift=-4.8pt] {$12\!{-}\!3$};
\node[elbl] at (-0.194,-0.347) [yshift=-4.8pt] {$12\!{-}\!9$};
\node[elbl] at (-0.224,-0.345) [yshift=-4.8pt] {$12\!{-}\!19$};
\node[elbl] at (0.210,-0.222) [yshift=-4.8pt] {$13\!{-}\!4$};
\node[elbl] at (0.227,-0.260) [yshift=-4.8pt] {$13\!{-}\!6$};
\node[elbl] at (0.227,-0.245) [yshift=-4.8pt] {$13\!{-}\!8$};
\node[elbl] at (0.219,-0.236) [yshift=-4.8pt] {$13\!{-}\!16$};
\node[elbl] at (0.045,-0.287) [yshift=-4.8pt] {$14\!{-}\!3$};
\node[elbl] at (0.038,-0.336) [yshift=-4.8pt] {$14\!{-}\!5$};
\node[elbl] at (0.087,-0.250) [yshift=-4.8pt] {$15\!{-}\!3$};
\node[elbl] at (0.173,-0.223) [yshift=-4.8pt] {$15\!{-}\!4$};
\node[elbl] at (0.190,-0.262) [yshift=-4.8pt] {$15\!{-}\!6$};
\node[elbl] at (0.135,-0.239) [yshift=-4.8pt] {$15\!{-}\!18$};
\node[elbl] at (0.209,-0.217) [yshift=-4.8pt] {$16\!{-}\!4$};
\node[elbl] at (0.225,-0.240) [yshift=-4.8pt] {$16\!{-}\!8$};
\node[elbl] at (-0.065,-0.171) [yshift=-4.8pt] {$17\!{-}\!3$};
\node[elbl] at (0.076,-0.246) [yshift=-4.8pt] {$18\!{-}\!3$};
\node[elbl] at (0.162,-0.218) [yshift=-4.8pt] {$18\!{-}\!4$};
\node[elbl] at (-0.102,-0.301) [yshift=-4.8pt] {$19\!{-}\!3$};
\node[dlbl] at (0.350,-0.318) [yshift=5.0pt] {6};
\node[dlbl] at (0.367,-0.357) [yshift=5.0pt] {7};
\node[dlbl] at (0.217,-0.241) [yshift=5.0pt] {0};
\node[dlbl] at (0.262,-0.270) [yshift=5.0pt] {2,3};
\node[dlbl] at (0.227,-0.245) [yshift=5.0pt] {1};
\node[dlbl] at (0.219,-0.236) [yshift=5.0pt] {5};
\node[dlbl] at (0.225,-0.240) [yshift=5.0pt] {4};
\draw[cut] (0.241,-0.204)--(0.180,-0.239);
\node[cutlbl] at (0.137,-0.263) {cut 1};
\draw[cut] (0.256,-0.320)--(0.269,-0.251);
\node[cutlbl] at (0.279,-0.203) {cut 2};
\end{tikzpicture}
\\[-0.25ex]
{\scriptsize medial graph $M(G)$ at edge midpoints}
\end{tabular}