coloring_nested_tire_graphs: add figure of partial tire dual
Adds fig_partial_tire_dual.png next to Definition 1.7 (Partial tire
dual), illustrating the corona-graph structure C_{n+m} ∘ K_1 from
Proposition 1.8 on a concrete m=6, k=4 spoke-only tire.
Drawing details:
- d_f interior vertices (purple squares) at centroids of annular
triangles; the 10 of them form a 10-cycle (solid purple edges).
- B_out leaves (orange diamonds) placed outside B_out; the leaf edge
is dashed orange.
- B_in leaves placed on the central-hole side of each red edge, at
a fixed small offset past the midpoint of the edge in the
d_f -> midpoint direction. This positions each leaf edge to
cross its red edge exactly at the midpoint while keeping the leaf
vertex itself inside the central hole and off the border.
Generator: experiments/draw_partial_tire_dual.py (also committed).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,221 @@
|
||||
"""Draw a partial tire dual on top of a small tire graph.
|
||||
|
||||
Uses a spoke-only tire with m=6 outer cycle, k=4 inner cycle, no
|
||||
chords. Overlays the partial tire dual:
|
||||
- d_f vertices at centroids of annular triangles (purple squares).
|
||||
- Leaf vertices for B_out edges (orange diamonds, outside the tire).
|
||||
- Leaf vertices for B_in edges (orange diamonds, inside the inner hole).
|
||||
- Interior dual edges (dashed purple).
|
||||
- Leaf edges (dashed orange).
|
||||
"""
|
||||
import math
|
||||
import os
|
||||
import sys
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, HERE)
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.patches as patches
|
||||
|
||||
from tire_graph import random_tire, planar_positions
|
||||
|
||||
|
||||
def draw_partial_tire_dual(tire, filename):
|
||||
m, k = tire['m'], tire['k']
|
||||
outer, inner = tire['outer'], tire['inner']
|
||||
triangles = tire['triangles']
|
||||
lattice_path = tire['lattice_path']
|
||||
|
||||
R_out, R_in = 1.0, 0.45
|
||||
pos = planar_positions(tire, R_out=R_out, R_in=R_in)
|
||||
|
||||
fig, ax = plt.subplots(figsize=(9, 9))
|
||||
|
||||
# === Draw underlying tire graph faintly ===
|
||||
outer_set = set(outer)
|
||||
inner_set = set(inner)
|
||||
for u, v in tire['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:
|
||||
color = '#e8a8a8'; lw = 2.0
|
||||
else:
|
||||
color = '#cccccc'; lw = 1.0
|
||||
ax.plot([x1, x2], [y1, y2], color=color, linewidth=lw, zorder=1)
|
||||
for v in outer:
|
||||
x, y = pos[v]
|
||||
ax.plot(x, y, 'o', color='#a8c9e8', markersize=14, zorder=2)
|
||||
ax.annotate(str(v), (x, y), color='white', ha='center', va='center',
|
||||
fontsize=8, fontweight='bold', zorder=3)
|
||||
for v in inner:
|
||||
x, y = pos[v]
|
||||
ax.plot(x, y, 'o', color='#e8a8a8', markersize=12, zorder=2)
|
||||
ax.annotate(str(v), (x, y), color='white', ha='center', va='center',
|
||||
fontsize=7, fontweight='bold', zorder=3)
|
||||
|
||||
# === Reconstruct annular triangles in cyclic order ===
|
||||
# The triangles list from random_tire gives them in lattice-path order.
|
||||
print(f"Lattice path: {lattice_path}")
|
||||
print(f"Triangles: {triangles}")
|
||||
n_tri = len(triangles)
|
||||
assert n_tri == m + k, f"expected {m+k} triangles, got {n_tri}"
|
||||
|
||||
# Compute centroid of each triangle
|
||||
centroids = []
|
||||
for tri in triangles:
|
||||
v1, v2, v3 = tri
|
||||
cx = (pos[v1][0] + pos[v2][0] + pos[v3][0]) / 3
|
||||
cy = (pos[v1][1] + pos[v2][1] + pos[v3][1]) / 3
|
||||
centroids.append((cx, cy))
|
||||
|
||||
# === Compute leaves and which annular face each is incident to ===
|
||||
# For each B_out edge: find which annular triangle contains it.
|
||||
# For each B_in edge: similarly.
|
||||
from collections import defaultdict
|
||||
bout_edges = [frozenset({outer[i], outer[(i+1) % m]}) for i in range(m)]
|
||||
bin_edges = [frozenset({inner[j], inner[(j+1) % k]}) for j in range(k)]
|
||||
|
||||
# Map: edge -> list of triangle indices containing it
|
||||
edge_to_tris = defaultdict(list)
|
||||
for t_idx, tri in enumerate(triangles):
|
||||
e1 = frozenset({tri[0], tri[1]})
|
||||
e2 = frozenset({tri[1], tri[2]})
|
||||
e3 = frozenset({tri[0], tri[2]})
|
||||
for e in (e1, e2, e3):
|
||||
edge_to_tris[e].append(t_idx)
|
||||
|
||||
bout_leaves = [] # list of (edge, tri_idx, leaf_position)
|
||||
for e in bout_edges:
|
||||
tris_with_e = edge_to_tris[e]
|
||||
assert len(tris_with_e) == 1, \
|
||||
f"B_out edge {e} should be in exactly 1 annular triangle"
|
||||
t_idx = tris_with_e[0]
|
||||
u, v = list(e)
|
||||
midx = (pos[u][0] + pos[v][0]) / 2
|
||||
midy = (pos[u][1] + pos[v][1]) / 2
|
||||
# Push outward
|
||||
d = math.sqrt(midx**2 + midy**2)
|
||||
push = 1.18
|
||||
leaf_pos = (midx * push / d, midy * push / d)
|
||||
bout_leaves.append((e, t_idx, leaf_pos))
|
||||
|
||||
bin_leaves = []
|
||||
for e in bin_edges:
|
||||
tris_with_e = edge_to_tris[e]
|
||||
assert len(tris_with_e) == 1, \
|
||||
f"B_in edge {e} should be in exactly 1 annular triangle"
|
||||
t_idx = tris_with_e[0]
|
||||
u, v = list(e)
|
||||
midx = (pos[u][0] + pos[v][0]) / 2
|
||||
midy = (pos[u][1] + pos[v][1]) / 2
|
||||
# Place the leaf aligned with the midpoint of the red edge it crosses,
|
||||
# on the central-hole side, at a fixed small distance past the
|
||||
# midpoint along the (d_f -> midpoint) direction. This keeps the
|
||||
# leaf inside the central hole (not on the border) while making the
|
||||
# leaf edge cross the red edge exactly at its midpoint.
|
||||
cx, cy = centroids[t_idx]
|
||||
vx, vy = midx - cx, midy - cy
|
||||
norm = math.sqrt(vx * vx + vy * vy)
|
||||
if norm < 1e-9:
|
||||
nx, ny = 0.0, -1.0
|
||||
else:
|
||||
nx, ny = vx / norm, vy / norm
|
||||
offset = 0.13 # absolute distance past the midpoint
|
||||
leaf_pos = (midx + nx * offset, midy + ny * offset)
|
||||
bin_leaves.append((e, t_idx, leaf_pos))
|
||||
|
||||
# === Determine interior dual cycle order ===
|
||||
# Two annular triangles are adjacent in the dual cycle iff they share an
|
||||
# interior annular edge (= an edge with both endpoints in V(B_out) ∪ V(B_in)
|
||||
# whose two incident faces are both annular triangles, i.e., shared by 2
|
||||
# of our triangles).
|
||||
# In a spoke-only tire each interior edge is shared by exactly 2 triangles.
|
||||
tri_adj = defaultdict(set)
|
||||
for e, ts in edge_to_tris.items():
|
||||
if len(ts) == 2:
|
||||
t1, t2 = ts
|
||||
tri_adj[t1].add(t2)
|
||||
tri_adj[t2].add(t1)
|
||||
|
||||
# === Draw partial tire dual ===
|
||||
DUAL_COLOR = '#7d3c98' # purple
|
||||
LEAF_COLOR = '#e67e22' # orange
|
||||
|
||||
# Interior dual edges
|
||||
for t1 in range(n_tri):
|
||||
for t2 in tri_adj[t1]:
|
||||
if t2 <= t1:
|
||||
continue
|
||||
x1, y1 = centroids[t1]
|
||||
x2, y2 = centroids[t2]
|
||||
ax.plot([x1, x2], [y1, y2], color=DUAL_COLOR, linewidth=2.0,
|
||||
linestyle='-', zorder=4)
|
||||
|
||||
# Leaf edges
|
||||
for e, t_idx, lpos in bout_leaves + bin_leaves:
|
||||
cx, cy = centroids[t_idx]
|
||||
lx, ly = lpos
|
||||
ax.plot([cx, lx], [lx and cy or cy, ly], visible=False)
|
||||
# use a proper plot:
|
||||
ax.plot([cx, lx], [cy, ly], color=LEAF_COLOR, linewidth=1.8,
|
||||
linestyle='--', zorder=4)
|
||||
|
||||
# Interior dual vertices
|
||||
for t_idx, (cx, cy) in enumerate(centroids):
|
||||
ax.plot(cx, cy, 's', color=DUAL_COLOR, markersize=14, zorder=5)
|
||||
ax.annotate(f"$d_{{{t_idx}}}$", (cx, cy), color='white',
|
||||
ha='center', va='center', fontsize=7, fontweight='bold',
|
||||
zorder=6)
|
||||
|
||||
# Leaf vertices
|
||||
for label_prefix, leaves in (('out', bout_leaves), ('in', bin_leaves)):
|
||||
for i, (e, t_idx, lpos) in enumerate(leaves):
|
||||
ax.plot(lpos[0], lpos[1], 'D', color=LEAF_COLOR,
|
||||
markersize=11, zorder=5)
|
||||
ax.annotate(f"$\\ell^{{{label_prefix}}}_{{{i}}}$",
|
||||
(lpos[0], lpos[1]), color='white', ha='center',
|
||||
va='center', fontsize=6, fontweight='bold', zorder=6)
|
||||
|
||||
# Legend
|
||||
legend_items = [
|
||||
plt.Line2D([], [], marker='o', color='w', markerfacecolor='#a8c9e8',
|
||||
markersize=12, label='$B_{\\mathrm{out}}$ vertex (tire)'),
|
||||
plt.Line2D([], [], marker='o', color='w', markerfacecolor='#e8a8a8',
|
||||
markersize=11, label='$B_{\\mathrm{in}}$ vertex (tire)'),
|
||||
plt.Line2D([], [], marker='s', color='w', markerfacecolor=DUAL_COLOR,
|
||||
markersize=12, label='$d_f$ (interior dual vertex)'),
|
||||
plt.Line2D([], [], marker='D', color='w', markerfacecolor=LEAF_COLOR,
|
||||
markersize=10, label='leaf vertex'),
|
||||
plt.Line2D([], [], color=DUAL_COLOR, linewidth=2.0,
|
||||
label='interior dual edge'),
|
||||
plt.Line2D([], [], color=LEAF_COLOR, linewidth=1.8, linestyle='--',
|
||||
label='leaf edge'),
|
||||
]
|
||||
ax.legend(handles=legend_items, loc='upper left',
|
||||
bbox_to_anchor=(1.0, 1.0), fontsize=9, frameon=False)
|
||||
|
||||
ax.set_xlim(-1.35, 1.35)
|
||||
ax.set_ylim(-1.35, 1.35)
|
||||
ax.set_aspect('equal')
|
||||
ax.axis('off')
|
||||
ax.set_title(
|
||||
f'Partial tire dual $D(T)$ (m={m}, k={k}, spoke-only)\n'
|
||||
f'underlying tire faint; $D(T) \\cong C_{{{m+k}}} \\circ K_1$',
|
||||
fontsize=12)
|
||||
|
||||
plt.savefig(filename, dpi=160, bbox_inches='tight')
|
||||
plt.close()
|
||||
print(f"wrote {filename}")
|
||||
|
||||
|
||||
def main():
|
||||
# m=6 outer, k=4 inner, no chords (spoke-only), reproducible seed
|
||||
tire = random_tire(m=6, k=4, n_chords=0, seed=3)
|
||||
out = os.path.join(HERE, 'partial_tire_dual_example.png')
|
||||
draw_partial_tire_dual(tire, out)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 147 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 147 KiB |
@@ -8,18 +8,20 @@
|
||||
\newlabel{fig:tire-example}{{2}{3}}
|
||||
\newlabel{rem:tire-counts}{{1.6}{3}}
|
||||
\newlabel{def:partial-tire-dual}{{1.7}{3}}
|
||||
\@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}}
|
||||
\newlabel{prop:no-level-d-pinch}{{1.9}{4}}
|
||||
\citation{bauerfeld-pds}
|
||||
\newlabel{prop:no-level-d-pinch}{{1.9}{5}}
|
||||
\newlabel{lem:tire-component}{{1.10}{5}}
|
||||
\citation{bauerfeld-pds}
|
||||
\newlabel{rem:tire-component-degenerate}{{1.11}{6}}
|
||||
\newlabel{rem:tire-no-extra-hypotheses}{{1.12}{6}}
|
||||
\citation{bauerfeld-pds}
|
||||
\bibcite{bauerfeld-pds}{1}
|
||||
\newlabel{tocindent-1}{0pt}
|
||||
\newlabel{tocindent0}{12.7778pt}
|
||||
\newlabel{tocindent1}{17.77782pt}
|
||||
\newlabel{tocindent2}{0pt}
|
||||
\newlabel{tocindent3}{0pt}
|
||||
\newlabel{rem:tire-component-degenerate}{{1.11}{7}}
|
||||
\newlabel{rem:tire-no-extra-hypotheses}{{1.12}{7}}
|
||||
\@writefile{toc}{\contentsline {section}{\tocsection {}{}{References}}{7}{}\protected@file@percent }
|
||||
\gdef \@abspage@last{7}
|
||||
|
||||
@@ -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 17:59
|
||||
This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022) (preloaded format=pdflatex 2022.10.5) 25 MAY 2026 18:37
|
||||
entering extended mode
|
||||
restricted \write18 enabled.
|
||||
%&-line parsing enabled.
|
||||
@@ -207,36 +207,42 @@ File: fig_tire_example.png Graphic file (type png)
|
||||
<use fig_tire_example.png>
|
||||
Package pdftex.def Info: fig_tire_example.png used on input line 160.
|
||||
(pdftex.def) Requested size: 280.79956pt x 188.56097pt.
|
||||
[3 <./fig_tire_example.png>] [4] [5] [6] [7]
|
||||
(./paper.aux) )
|
||||
[3 <./fig_tire_example.png>]
|
||||
<fig_partial_tire_dual.png, id=30, 657.657pt x 546.54187pt>
|
||||
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] (./paper.aux) )
|
||||
Here is how much of TeX's memory you used:
|
||||
3010 strings out of 478268
|
||||
42095 string characters out of 5846347
|
||||
346199 words of memory out of 5000000
|
||||
21057 multiletter control sequences out of 15000+600000
|
||||
3018 strings out of 478268
|
||||
42332 string characters out of 5846347
|
||||
345207 words of memory out of 5000000
|
||||
21064 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,625b,316s stack positions out of 10000i,1000n,20000p,200000b,200000s
|
||||
</usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/
|
||||
cm/cmbx10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/c
|
||||
m/cmcsc10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/c
|
||||
m/cmex10.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/
|
||||
cmmi5.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cm
|
||||
mi7.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr1
|
||||
0.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr5.p
|
||||
fb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr7.pfb>
|
||||
</usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmr8.pfb></u
|
||||
sr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy10.pfb></us
|
||||
r/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy5.pfb></usr/
|
||||
local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmsy7.pfb></usr/lo
|
||||
cal/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmti10.pfb></usr/loc
|
||||
al/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmti8.pfb></usr/local
|
||||
/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/symbols/msam10.pfb>
|
||||
Output written on paper.pdf (7 pages, 499770 bytes).
|
||||
69i,8n,76p,687b,316s stack positions out of 10000i,1000n,20000p,200000b,200000s
|
||||
</usr/local/texli
|
||||
ve/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx10.pfb></usr/local/texliv
|
||||
e/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmcsc10.pfb></usr/local/texliv
|
||||
e/2022/texmf-dist/fonts/type1/public/amsfonts/cm/cmex10.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/cmmi5.pfb></usr/local/texlive/20
|
||||
22/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/2022/t
|
||||
exmf-dist/fonts/type1/public/amsfonts/cm/cmr5.pfb></usr/local/texlive/2022/texm
|
||||
f-dist/fonts/type1/public/amsfonts/cm/cmr7.pfb></usr/local/texlive/2022/texmf-d
|
||||
ist/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.pfb></usr/local/texlive/2022/texmf-dist/fo
|
||||
nts/type1/public/amsfonts/cm/cmsy7.pfb></usr/local/texlive/2022/texmf-dist/font
|
||||
s/type1/public/amsfonts/cm/cmti10.pfb></usr/local/texlive/2022/texmf-dist/fonts
|
||||
/type1/public/amsfonts/cm/cmti8.pfb></usr/local/texlive/2022/texmf-dist/fonts/t
|
||||
ype1/public/amsfonts/symbols/msam10.pfb>
|
||||
Output written on paper.pdf (7 pages, 616266 bytes).
|
||||
PDF statistics:
|
||||
113 PDF objects out of 1000 (max. 8388607)
|
||||
115 PDF objects out of 1000 (max. 8388607)
|
||||
67 compressed objects within 1 object stream
|
||||
0 named destinations out of 1000 (max. 500000)
|
||||
11 words of extra memory for PDF output out of 10000 (max. 10000000)
|
||||
16 words of extra memory for PDF output out of 10000 (max. 10000000)
|
||||
|
||||
|
||||
Binary file not shown.
@@ -220,6 +220,21 @@ tire dual} of $T$, written $D(T)$, is the graph defined as follows.
|
||||
\end{enumerate}
|
||||
\end{definition}
|
||||
|
||||
\begin{figure}[h]
|
||||
\centering
|
||||
\includegraphics[width=0.78\textwidth]{fig_partial_tire_dual.png}
|
||||
\caption{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~\ref{prop:partial-tire-dual-structure}.}
|
||||
\label{fig:partial-tire-dual-example}
|
||||
\end{figure}
|
||||
|
||||
\begin{proposition}[Structure of $D(T)$ when the annular triangulation
|
||||
is spoke-only]
|
||||
\label{prop:partial-tire-dual-structure}
|
||||
|
||||
Reference in New Issue
Block a user