coloring_nested_tire_graphs: add bridge-example partial tire dual figure beneath Fig 3

Adds fig_partial_tire_dual_bridge.png beneath the existing partial-
tire-dual figure (Figure 3).  The new figure shows a tire graph
whose inner outerplanar O has a bridge:
  B_out = triangle on {0, 1, 2};
  O     = triangle {3, 4, 5} plus pendant edge 5-6 (the bridge);
  annular triangulation with 8 triangles (constructed by hand).

Key contrast with the previous figure: because both faces incident
to the bridge are annular triangles, the bridge contributes an
INTERIOR DUAL EDGE rather than two leaves.  Consequently the
interior dual subgraph is no longer a single (n+m)-cycle (as in
Prop 1.8 for spoke-only tires) but a theta graph: two trivalent
d_f vertices connected by three internally vertex-disjoint paths.
Leaves come only from B_out (3 of them) and the three non-bridge
triangle edges of O (the inner-triangle face boundary).

Adds experiments/draw_partial_tire_dual_bridge.py to generate the
figure.

Paper grows from 8 to 9 pages.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-25 20:44:02 -04:00
parent d121d2d3b6
commit 7e4ccf2cc2
7 changed files with 334 additions and 34 deletions
@@ -0,0 +1,264 @@
"""Draw a partial tire dual D(T) for a tire whose inner outerplanar
graph O has a bridge.
Tire construction:
- Outer cycle B_out: triangle on {0, 1, 2}.
- Inner outerplanar O on {3, 4, 5, 6}: triangle 3-4-5 plus pendant
edge 5-6 (the bridge of O).
- Annular triangulation with 8 triangles (computed by hand below).
The bridge 5-6 has both incident faces in the annular region, so in
the partial tire dual it contributes an interior dual edge (not a
leaf). This makes the interior dual subgraph a theta graph rather
than a single cycle: two trivalent vertices (the two annular faces
incident to the bridge) connected by three paths.
"""
import math
import os
import sys
from collections import defaultdict
import matplotlib.pyplot as plt
import matplotlib.patches as patches
# Explicit vertex positions
POS = {
0: (0.0, 1.0),
1: (-0.866, -0.5),
2: (0.866, -0.5),
3: (0.0, 0.32),
4: (-0.27, -0.17),
5: (0.13, -0.17),
6: (0.52, -0.07),
}
# Annular triangles (in lattice-path-like order, but here just listed)
TRIANGLES = [
(0, 1, 4), # T1 -- O-move
(0, 4, 3), # T2 -- has edge 4-3 boundary (inner triangle)
(1, 2, 5), # T3 -- O-move
(1, 5, 4), # T4 -- inner-triangle-edge boundary
(2, 0, 6), # T5 -- O-move
(0, 3, 6), # T6 -- ALL INTERIOR (bridge neighbour)
(3, 5, 6), # T7 -- inner-triangle-edge boundary, contains bridge
(5, 2, 6), # T8 -- ALL INTERIOR (bridge neighbour)
]
# Tire edges (all)
T_EDGES = [
# outer cycle (B_out)
(0, 1), (1, 2), (2, 0),
# O: triangle 3-4-5
(3, 4), (4, 5), (3, 5),
# O: pendant / bridge
(5, 6),
# spokes
(0, 3), (1, 4), (2, 5),
# diagonals from annular triangulation
(0, 4), (1, 5), (0, 6), (2, 6), (3, 6),
]
# Boundary edges
B_OUT_EDGES = [(0, 1), (1, 2), (2, 0)]
# Edges of O on inner-triangle-face boundary (i.e., NOT the bridge)
B_IN_EDGES = [(3, 4), (4, 5), (3, 5)]
# Bridge edge (interior to annulus)
BRIDGE = (5, 6)
def main():
# Map: edge -> list of triangle indices containing it
edge_to_tris = defaultdict(list)
for i, t in enumerate(TRIANGLES):
for e in (frozenset({t[0], t[1]}),
frozenset({t[1], t[2]}),
frozenset({t[0], t[2]})):
edge_to_tris[e].append(i)
# Verify each B_out edge is in exactly 1 annular triangle
for u, v in B_OUT_EDGES:
ts = edge_to_tris[frozenset({u, v})]
assert len(ts) == 1, f"B_out edge {u}-{v} in {ts}"
# Each B_in (= non-bridge O edge) is in exactly 1 annular triangle
for u, v in B_IN_EDGES:
ts = edge_to_tris[frozenset({u, v})]
assert len(ts) == 1, f"B_in edge {u}-{v} in {ts}"
# Bridge is in exactly 2 annular triangles (interior to annulus)
bts = edge_to_tris[frozenset(BRIDGE)]
print(f"Bridge {BRIDGE} is in annular triangles {bts}")
assert len(bts) == 2
# Interior dual subgraph: connect annular triangles sharing an edge
n_tri = len(TRIANGLES)
tri_adj = defaultdict(set)
for e, ts in edge_to_tris.items():
if len(ts) == 2:
tri_adj[ts[0]].add(ts[1])
tri_adj[ts[1]].add(ts[0])
print("Interior dual subgraph degree sequence:")
for i in range(n_tri):
print(f" T{i+1} ({TRIANGLES[i]}): degree {len(tri_adj[i])}")
# Centroids of triangles for d_f positions
centroids = []
for t in TRIANGLES:
cx = (POS[t[0]][0] + POS[t[1]][0] + POS[t[2]][0]) / 3
cy = (POS[t[0]][1] + POS[t[1]][1] + POS[t[2]][1]) / 3
centroids.append((cx, cy))
# === Plot ===
fig, ax = plt.subplots(figsize=(10, 9))
# Draw underlying tire edges faintly
outer_set = {0, 1, 2}
inner_set = {3, 4, 5, 6}
for u, v in T_EDGES:
x1, y1 = POS[u]; x2, y2 = POS[v]
if u in outer_set and v in outer_set:
color = '#a8c9e8'; lw = 2.0
elif u in inner_set and v in inner_set:
# Distinguish bridge (pendant) from triangle edges
if frozenset({u, v}) == frozenset(BRIDGE):
color = '#cc6677'; lw = 2.5 # darker red for bridge
else:
color = '#e8a8a8'; lw = 2.0
else:
color = '#cccccc'; lw = 1.0
ax.plot([x1, x2], [y1, y2], color=color, linewidth=lw, zorder=1)
# Tire vertices
for v in [0, 1, 2]:
x, y = POS[v]
ax.plot(x, y, 'o', color='#a8c9e8', markersize=15, zorder=2)
ax.annotate(str(v), (x, y), color='white', ha='center', va='center',
fontsize=9, fontweight='bold', zorder=3)
for v in [3, 4, 5, 6]:
x, y = POS[v]
ax.plot(x, y, 'o', color='#e8a8a8', markersize=13, zorder=2)
ax.annotate(str(v), (x, y), color='white', ha='center', va='center',
fontsize=8, fontweight='bold', zorder=3)
DUAL_COLOR = '#7d3c98'
LEAF_COLOR = '#e67e22'
BRIDGE_DUAL_COLOR = '#cc4444' # color the bridge's dual edge differently
# Interior dual edges
for i in range(n_tri):
for j in tri_adj[i]:
if j <= i:
continue
x1, y1 = centroids[i]; x2, y2 = centroids[j]
# Find shared edge to colour-code bridge edge
ti_es = {frozenset({TRIANGLES[i][a], TRIANGLES[i][b]})
for a, b in [(0, 1), (1, 2), (0, 2)]}
tj_es = {frozenset({TRIANGLES[j][a], TRIANGLES[j][b]})
for a, b in [(0, 1), (1, 2), (0, 2)]}
shared = (ti_es & tj_es).pop()
if shared == frozenset(BRIDGE):
ec, lw = BRIDGE_DUAL_COLOR, 3.0
else:
ec, lw = DUAL_COLOR, 2.0
ax.plot([x1, x2], [y1, y2], color=ec, linewidth=lw, zorder=4)
# Leaves for B_out edges
for u, v in B_OUT_EDGES:
ti = edge_to_tris[frozenset({u, v})][0]
midx = (POS[u][0] + POS[v][0]) / 2
midy = (POS[u][1] + POS[v][1]) / 2
d = math.sqrt(midx**2 + midy**2)
push = 1.20
lpos = (midx * push / d, midy * push / d)
cx, cy = centroids[ti]
ax.plot([cx, lpos[0]], [cy, lpos[1]], color=LEAF_COLOR,
linewidth=1.5, linestyle='--', zorder=4)
ax.plot(lpos[0], lpos[1], 'D', color=LEAF_COLOR, markersize=11,
zorder=5)
ax.annotate(f"$\\ell^{{\\mathrm{{out}}}}_{{{u},{v}}}$", lpos,
color='white', ha='center', va='center', fontsize=6,
fontweight='bold', zorder=6)
# Leaves for non-bridge B_in edges (= the 3 inner triangle edges)
for u, v in B_IN_EDGES:
ti = edge_to_tris[frozenset({u, v})][0]
midx = (POS[u][0] + POS[v][0]) / 2
midy = (POS[u][1] + POS[v][1]) / 2
cx, cy = centroids[ti]
vx, vy = midx - cx, midy - cy
norm = math.sqrt(vx*vx + vy*vy)
offset = 0.10
if norm > 1e-9:
nx, ny = vx / norm, vy / norm
else:
nx, ny = 0, -1
lpos = (midx + nx * offset, midy + ny * offset)
ax.plot([cx, lpos[0]], [cy, lpos[1]], color=LEAF_COLOR,
linewidth=1.5, linestyle='--', zorder=4)
ax.plot(lpos[0], lpos[1], 'D', color=LEAF_COLOR, markersize=11,
zorder=5)
ax.annotate(f"$\\ell^{{\\mathrm{{in}}}}_{{{u},{v}}}$", lpos,
color='white', ha='center', va='center', fontsize=6,
fontweight='bold', zorder=6)
# Interior dual vertices d_f, highlighting the two degree-3
# vertices in a darker color (these are the trivalent vertices
# of the theta graph that the interior dual forms).
for ti, (cx, cy) in enumerate(centroids):
is_deg3 = (len(tri_adj[ti]) == 3)
marker_color = '#5a2273' if is_deg3 else DUAL_COLOR
ax.plot(cx, cy, 's', color=marker_color, markersize=15, zorder=5)
ax.annotate(f"$d_{{{ti}}}$", (cx, cy), color='white', ha='center',
va='center', fontsize=7, fontweight='bold', zorder=6)
# Legend
legend_items = [
plt.Line2D([], [], marker='o', color='w', markerfacecolor='#a8c9e8',
markersize=12, label='$B_{\\mathrm{out}}$ vertex'),
plt.Line2D([], [], marker='o', color='w', markerfacecolor='#e8a8a8',
markersize=11, label='$V(O)$ vertex'),
plt.Line2D([], [], color='#a8c9e8', linewidth=2.0,
label='$B_{\\mathrm{out}}$ edge'),
plt.Line2D([], [], color='#e8a8a8', linewidth=2.0,
label='triangle edge of $O$'),
plt.Line2D([], [], color='#cc6677', linewidth=2.5,
label='bridge of $O$ (= pendant)'),
plt.Line2D([], [], marker='s', color='w', markerfacecolor=DUAL_COLOR,
markersize=12, label='$d_f$ (degree 2 in interior dual)'),
plt.Line2D([], [], marker='s', color='w', markerfacecolor='#5a2273',
markersize=12,
label='$d_f$ (degree 3 -- theta-graph trivalent)'),
plt.Line2D([], [], marker='D', color='w', markerfacecolor=LEAF_COLOR,
markersize=10, label='leaf'),
plt.Line2D([], [], color=DUAL_COLOR, linewidth=2.0,
label='interior dual edge'),
plt.Line2D([], [], color=BRIDGE_DUAL_COLOR, linewidth=3.0,
label='dual of the bridge'),
plt.Line2D([], [], color=LEAF_COLOR, linewidth=1.5, linestyle='--',
label='leaf edge'),
]
ax.legend(handles=legend_items, loc='upper left',
bbox_to_anchor=(1.02, 1.0), fontsize=8, frameon=False)
ax.set_xlim(-1.30, 1.50)
ax.set_ylim(-1.20, 1.20)
ax.set_aspect('equal')
ax.axis('off')
ax.set_title(
'Partial tire dual $D(T)$ when $O$ has a bridge\n'
'$O$ = triangle $\\{3,4,5\\}$ + pendant edge $5$--$6$;\n'
'interior dual is a theta graph (2 deg-3 vertices + 3 paths), '
'not a cycle.',
fontsize=11)
HERE = os.path.dirname(os.path.abspath(__file__))
out = os.path.join(HERE, 'partial_tire_dual_bridge.png')
plt.savefig(out, dpi=160, bbox_inches='tight')
plt.close()
print(f"wrote {out}")
if __name__ == '__main__':
main()
Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

+8 -6
View File
@@ -11,19 +11,21 @@
\@writefile{lof}{\contentsline {figure}{\numberline {3}{\ignorespaces The partial tire dual $D(T)$ (purple squares + orange diamonds) drawn on top of a small tire graph $T$ (faint) with $m = 6$ and $k = 4$. The ten interior vertices $d_f$ at the centroids of the annular triangles form a single $10$-cycle (solid purple); each boundary edge of the annular region (either of $B_{\mathrm {out}}$ or of $B_{\mathrm {in}}$) contributes a degree-$1$ leaf (orange diamond) attached to the unique annular face incident to it (dashed orange), giving the structure $C_{10} \circ K_1$ of Proposition\nonbreakingspace 1.8\hbox {}.}}{4}{}\protected@file@percent }
\newlabel{fig:partial-tire-dual-example}{{3}{4}}
\newlabel{prop:partial-tire-dual-structure}{{1.8}{4}}
\@writefile{lof}{\contentsline {figure}{\numberline {4}{\ignorespaces Partial tire dual $D(T)$ when the inner outerplanar graph $O$ has a bridge. Here $B_{\mathrm {out}}$ is a triangle on $\{0,1,2\}$ and $O$ is a triangle $\{3,4,5\}$ with a pendant edge $5$--$6$ (the bridge of $O$). Because both faces incident to the bridge are annular triangles, the bridge contributes an \emph {interior dual edge} (highlighted in red) rather than two leaves; consequently the interior dual subgraph is no longer the single $(n+m)$-cycle of Proposition\nonbreakingspace 1.8\hbox {}, but a theta graph (two trivalent vertices $d_5, d_7$ connected by three internally vertex-disjoint paths in $D(T)$). Leaves come only from $B_{\mathrm {out}}$ ($n = 3$ leaves) and from the three non-bridge edges of $O$ (the three triangle edges of the inner triangle).}}{5}{}\protected@file@percent }
\newlabel{fig:partial-tire-dual-bridge}{{4}{5}}
\newlabel{prop:no-level-d-pinch}{{1.9}{5}}
\newlabel{lem:tire-component}{{1.10}{5}}
\citation{bauerfeld-pds}
\newlabel{lem:tire-component}{{1.10}{6}}
\citation{bauerfeld-pds}
\newlabel{rem:tire-component-degenerate}{{1.11}{7}}
\newlabel{rem:tire-no-extra-hypotheses}{{1.12}{7}}
\newlabel{prop:edge-vertex-bijection}{{1.13}{7}}
\newlabel{rem:tire-no-extra-hypotheses}{{1.12}{8}}
\newlabel{prop:edge-vertex-bijection}{{1.13}{8}}
\newlabel{rem:edge-vertex-corollary}{{1.14}{8}}
\bibcite{bauerfeld-pds}{1}
\newlabel{tocindent-1}{0pt}
\newlabel{tocindent0}{12.7778pt}
\newlabel{tocindent1}{17.77782pt}
\newlabel{tocindent2}{0pt}
\newlabel{tocindent3}{0pt}
\newlabel{rem:edge-vertex-corollary}{{1.14}{8}}
\@writefile{toc}{\contentsline {section}{\tocsection {}{}{References}}{8}{}\protected@file@percent }
\gdef \@abspage@last{8}
\@writefile{toc}{\contentsline {section}{\tocsection {}{}{References}}{9}{}\protected@file@percent }
\gdef \@abspage@last{9}
+43 -28
View File
@@ -1,4 +1,4 @@
This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022) (preloaded format=pdflatex 2022.10.5) 25 MAY 2026 19:52
This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022) (preloaded format=pdflatex 2022.10.5) 25 MAY 2026 20:43
entering extended mode
restricted \write18 enabled.
%&-line parsing enabled.
@@ -213,36 +213,51 @@ File: fig_partial_tire_dual.png Graphic file (type png)
<use fig_partial_tire_dual.png>
Package pdftex.def Info: fig_partial_tire_dual.png used on input line 225.
(pdftex.def) Requested size: 280.79956pt x 233.36552pt.
[4 <./fig_partial_tire_dual.png>] [5] [6] [7] [8] (./paper.aux) )
<fig_partial_tire_dual_bridge.png, id=31, 765.6103pt x 542.47668pt>
File: fig_partial_tire_dual_bridge.png Graphic file (type png)
<use fig_partial_tire_dual_bridge.png>
Package pdftex.def Info: fig_partial_tire_dual_bridge.png used on input line 2
40.
(pdftex.def) Requested size: 280.79956pt x 198.95839pt.
LaTeX Warning: `h' float specifier changed to `ht'.
[4 <./fig_partial_tire_dual.png>] [5 <./fig_partial_tire_dual_bridge.png>]
[6]
Underfull \vbox (badness 1043) has occurred while \output is active []
[7]
[8] [9] (./paper.aux) )
Here is how much of TeX's memory you used:
3020 strings out of 478268
42387 string characters out of 5846347
345229 words of memory out of 5000000
21066 multiletter control sequences out of 15000+600000
3028 strings out of 478268
42672 string characters out of 5846347
344237 words of memory out of 5000000
21073 multiletter control sequences out of 15000+600000
475666 words of font info for 53 fonts, out of 8000000 for 9000
1302 hyphenation exceptions out of 8191
69i,8n,76p,687b,316s stack positions out of 10000i,1000n,20000p,200000b,200000s
</usr/local/t
exlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx10.pfb></usr/local/te
xlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmcsc10.pfb></usr/local/te
xlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmex10.pfb></usr/local/tex
live/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi10.pfb></usr/local/texl
ive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi5.pfb></usr/local/texliv
e/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi7.pfb></usr/local/texlive/
2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb></usr/local/texlive/20
22/texmf-dist/fonts/type1/public/amsfonts/cm/cmr5.pfb></usr/local/texlive/2022/
texmf-dist/fonts/type1/public/amsfonts/cm/cmr7.pfb></usr/local/texlive/2022/tex
mf-dist/fonts/type1/public/amsfonts/cm/cmr8.pfb></usr/local/texlive/2022/texmf-
dist/fonts/type1/public/amsfonts/cm/cmsy10.pfb></usr/local/texlive/2022/texmf-d
ist/fonts/type1/public/amsfonts/cm/cmsy5.pfb></usr/local/texlive/2022/texmf-dis
t/fonts/type1/public/amsfonts/cm/cmsy7.pfb></usr/local/texlive/2022/texmf-dist/
fonts/type1/public/amsfonts/cm/cmti10.pfb></usr/local/texlive/2022/texmf-dist/f
onts/type1/public/amsfonts/cm/cmti8.pfb></usr/local/texlive/2022/texmf-dist/fon
ts/type1/public/amsfonts/symbols/msam10.pfb>
Output written on paper.pdf (8 pages, 622907 bytes).
69i,8n,76p,907b,316s stack positions out of 10000i,1000n,20000p,200000b,200000s
</usr/local/texlive/2022/texmf-dist/fonts/type1/public/a
msfonts/cm/cmbx10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/am
sfonts/cm/cmcsc10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/am
sfonts/cm/cmex10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/ams
fonts/cm/cmmi10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsf
onts/cm/cmmi5.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfon
ts/cm/cmmi7.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts
/cm/cmr10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/c
m/cmr5.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/c
mr7.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr8
.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy10.
pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy5.pf
b></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy7.pfb>
</usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmti10.pfb><
/usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmti8.pfb></u
sr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/symbols/msam10.pfb
>
Output written on paper.pdf (9 pages, 748857 bytes).
PDF statistics:
118 PDF objects out of 1000 (max. 8388607)
69 compressed objects within 1 object stream
123 PDF objects out of 1000 (max. 8388607)
71 compressed objects within 1 object stream
0 named destinations out of 1000 (max. 500000)
16 words of extra memory for PDF output out of 10000 (max. 10000000)
21 words of extra memory for PDF output out of 10000 (max. 10000000)
Binary file not shown.
@@ -235,6 +235,25 @@ Proposition~\ref{prop:partial-tire-dual-structure}.}
\label{fig:partial-tire-dual-example}
\end{figure}
\begin{figure}[h]
\centering
\includegraphics[width=0.78\textwidth]{fig_partial_tire_dual_bridge.png}
\caption{Partial tire dual $D(T)$ when the inner outerplanar graph
$O$ has a bridge. Here $B_{\mathrm{out}}$ is a triangle on
$\{0,1,2\}$ and $O$ is a triangle $\{3,4,5\}$ with a pendant edge
$5$--$6$ (the bridge of $O$). Because both faces incident to the
bridge are annular triangles, the bridge contributes an
\emph{interior dual edge} (highlighted in red) rather than two
leaves; consequently the interior dual subgraph is no longer the
single $(n+m)$-cycle of
Proposition~\ref{prop:partial-tire-dual-structure}, but a theta
graph (two trivalent vertices $d_5, d_7$ connected by three
internally vertex-disjoint paths in $D(T)$). Leaves come only from
$B_{\mathrm{out}}$ ($n = 3$ leaves) and from the three non-bridge
edges of $O$ (the three triangle edges of the inner triangle).}
\label{fig:partial-tire-dual-bridge}
\end{figure}
\begin{proposition}[Structure of $D(T)$ when the annular triangulation
is spoke-only]
\label{prop:partial-tire-dual-structure}