diff --git a/papers/coloring_nested_tire_graphs/experiments/draw_partial_tire_dual.py b/papers/coloring_nested_tire_graphs/experiments/draw_partial_tire_dual.py new file mode 100644 index 0000000..8de88ab --- /dev/null +++ b/papers/coloring_nested_tire_graphs/experiments/draw_partial_tire_dual.py @@ -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() diff --git a/papers/coloring_nested_tire_graphs/experiments/partial_tire_dual_example.png b/papers/coloring_nested_tire_graphs/experiments/partial_tire_dual_example.png new file mode 100644 index 0000000..3130934 Binary files /dev/null and b/papers/coloring_nested_tire_graphs/experiments/partial_tire_dual_example.png differ diff --git a/papers/coloring_nested_tire_graphs/fig_partial_tire_dual.png b/papers/coloring_nested_tire_graphs/fig_partial_tire_dual.png new file mode 100644 index 0000000..3130934 Binary files /dev/null and b/papers/coloring_nested_tire_graphs/fig_partial_tire_dual.png differ diff --git a/papers/coloring_nested_tire_graphs/paper.aux b/papers/coloring_nested_tire_graphs/paper.aux index 25d708b..1fdda1a 100644 --- a/papers/coloring_nested_tire_graphs/paper.aux +++ b/papers/coloring_nested_tire_graphs/paper.aux @@ -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} diff --git a/papers/coloring_nested_tire_graphs/paper.log b/papers/coloring_nested_tire_graphs/paper.log index 93cecae..d4d81eb 100644 --- a/papers/coloring_nested_tire_graphs/paper.log +++ b/papers/coloring_nested_tire_graphs/paper.log @@ -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) 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>] + +File: fig_partial_tire_dual.png Graphic file (type 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 - - -Output written on paper.pdf (7 pages, 499770 bytes). + 69i,8n,76p,687b,316s stack positions out of 10000i,1000n,20000p,200000b,200000s + +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) diff --git a/papers/coloring_nested_tire_graphs/paper.pdf b/papers/coloring_nested_tire_graphs/paper.pdf index 4aecf0d..d1e2ddb 100644 Binary files a/papers/coloring_nested_tire_graphs/paper.pdf and b/papers/coloring_nested_tire_graphs/paper.pdf differ diff --git a/papers/coloring_nested_tire_graphs/paper.tex b/papers/coloring_nested_tire_graphs/paper.tex index f01ecb9..1de12bc 100644 --- a/papers/coloring_nested_tire_graphs/paper.tex +++ b/papers/coloring_nested_tire_graphs/paper.tex @@ -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}