diff --git a/papers/coloring_nested_tire_graphs/experiments/complete_tire_dual_example.png b/papers/coloring_nested_tire_graphs/experiments/complete_tire_dual_example.png new file mode 100644 index 0000000..4aa8af4 Binary files /dev/null and b/papers/coloring_nested_tire_graphs/experiments/complete_tire_dual_example.png differ diff --git a/papers/coloring_nested_tire_graphs/experiments/draw_complete_tire_dual.py b/papers/coloring_nested_tire_graphs/experiments/draw_complete_tire_dual.py new file mode 100644 index 0000000..13c8226 --- /dev/null +++ b/papers/coloring_nested_tire_graphs/experiments/draw_complete_tire_dual.py @@ -0,0 +1,199 @@ +"""Draw the complete tire dual D*(T) on top of a small tire graph. + +For a spoke-only tire with 2-connected O = C_k (no chords), D*(T) is +obtained from D(T) by merging: + - all B_out-leaves into a single outer-face vertex v_out (degree n); + - the B_in-leaves into a single inner-face vertex v_in (degree k), + because O has exactly one bounded interior face. + +Equivalently, D*(T) is the planar dual of T. +""" +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_complete_tire_dual(tire, filename): + m, k = tire['m'], tire['k'] + outer, inner = tire['outer'], tire['inner'] + triangles = tire['triangles'] + + 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) + + n_tri = len(triangles) + 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)) + + # Identify which triangles are incident to a B_out edge (O-move type) + # vs incident to a B_in edge (I-move type). + 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)} + + bout_incident = [] # triangles incident to a B_out edge + bin_incident = [] # triangles incident to a B_in edge + for t_idx, tri in enumerate(triangles): + tri_edges = {frozenset({tri[0], tri[1]}), + frozenset({tri[1], tri[2]}), + frozenset({tri[0], tri[2]})} + if tri_edges & bout_edges: + bout_incident.append(t_idx) + if tri_edges & bin_edges: + bin_incident.append(t_idx) + + print(f"O-move triangles (B_out incident): {bout_incident}") + print(f"I-move triangles (B_in incident): {bin_incident}") + + # Place v_out outside the outer cycle (far to the upper right) + # and v_in at the origin (centroid of inner cycle). + v_out_pos = (1.55, 0.0) # well outside the outer cycle + v_in_pos = (0.0, 0.0) # center of inner cycle + + # Identify dual cycle (interior dual edges) + 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) + + 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 complete tire dual === + DUAL_COLOR = '#7d3c98' # purple + OUT_COLOR = '#1f77b4' # blue (for v_out edges) + IN_COLOR = '#d62728' # red (for v_in edges) + + # Interior dual edges (d_f to d_f) + 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, + zorder=4) + + # v_out edges (to all O-move d_f's) + for t_idx in bout_incident: + cx, cy = centroids[t_idx] + ax.plot([cx, v_out_pos[0]], [cy, v_out_pos[1]], + color=OUT_COLOR, linewidth=1.6, linestyle='--', zorder=4) + + # v_in edges (to all I-move d_f's) + for t_idx in bin_incident: + cx, cy = centroids[t_idx] + ax.plot([cx, v_in_pos[0]], [cy, v_in_pos[1]], + color=IN_COLOR, linewidth=1.6, linestyle='--', zorder=4) + + # Interior dual vertices d_f + 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) + + # v_out (outer-face vertex) + ax.plot(v_out_pos[0], v_out_pos[1], 'h', color=OUT_COLOR, + markersize=20, zorder=5) + ax.annotate("$v_{\\mathrm{out}}$", v_out_pos, color='white', + ha='center', va='center', fontsize=9, fontweight='bold', + zorder=6) + + # v_in (inner-face vertex) + ax.plot(v_in_pos[0], v_in_pos[1], 'h', color=IN_COLOR, + markersize=18, zorder=5) + ax.annotate("$v_{\\mathrm{in}}$", v_in_pos, color='white', + ha='center', va='center', fontsize=8, 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$ (annular face dual vertex)'), + plt.Line2D([], [], marker='h', color='w', markerfacecolor=OUT_COLOR, + markersize=14, + label='$v_{\\mathrm{out}}$ (outer-face vertex, deg ${%d}$)' % m), + plt.Line2D([], [], marker='h', color='w', markerfacecolor=IN_COLOR, + markersize=13, + label='$v_{\\mathrm{in}}$ (inner-face vertex, deg ${%d}$)' % k), + plt.Line2D([], [], color=DUAL_COLOR, linewidth=2.0, + label='interior dual edge ($d_f$–$d_{f^\\prime}$)'), + plt.Line2D([], [], color=OUT_COLOR, linewidth=1.6, linestyle='--', + label='dual edge to $v_{\\mathrm{out}}$'), + plt.Line2D([], [], color=IN_COLOR, linewidth=1.6, linestyle='--', + label='dual edge to $v_{\\mathrm{in}}$'), + ] + ax.legend(handles=legend_items, loc='upper left', + bbox_to_anchor=(1.02, 1.0), fontsize=9, frameon=False) + + ax.set_xlim(-1.35, 2.05) + ax.set_ylim(-1.35, 1.35) + ax.set_aspect('equal') + ax.axis('off') + ax.set_title( + f'Complete tire dual $D^{{*}}(T)$ (m={m}, k={k}, spoke-only)\n' + f'underlying tire faint; $|V| = {n_tri + 2}$, $|E| = {2*n_tri}$', + fontsize=12) + + plt.savefig(filename, dpi=160, bbox_inches='tight') + plt.close() + print(f"wrote {filename}") + + +def main(): + tire = random_tire(m=6, k=4, n_chords=0, seed=3) + out = os.path.join(HERE, 'complete_tire_dual_example.png') + draw_complete_tire_dual(tire, out) + + +if __name__ == '__main__': + main() diff --git a/papers/coloring_nested_tire_graphs/fig_complete_tire_dual.png b/papers/coloring_nested_tire_graphs/fig_complete_tire_dual.png new file mode 100644 index 0000000..4aa8af4 Binary files /dev/null and b/papers/coloring_nested_tire_graphs/fig_complete_tire_dual.png differ diff --git a/papers/coloring_nested_tire_graphs/paper.aux b/papers/coloring_nested_tire_graphs/paper.aux index c091793..4ba641a 100644 --- a/papers/coloring_nested_tire_graphs/paper.aux +++ b/papers/coloring_nested_tire_graphs/paper.aux @@ -19,6 +19,11 @@ \newlabel{rem:tire-no-extra-hypotheses}{{1.12}{7}} \newlabel{def:complete-tire-dual}{{1.13}{7}} \citation{Tait1880} +\@writefile{lof}{\contentsline {figure}{\numberline {4}{\ignorespaces The complete tire dual $D^{\ast }(T)$ (purple squares + face hexagons) drawn on top of the same $m = 6$, $k = 4$ spoke-only tire graph as Figure\nonbreakingspace 3\hbox {}. The ten annular-face vertices $d_f$ form a $10$-cycle (solid purple); the $n$ outer leaves of $D(T)$ have been merged into a single outer-face vertex $v_{\mathrm {out}}$ (blue hexagon, drawn outside the tire) of degree $n = 6$, and the $m$ inner leaves into a single inner-face vertex $v_{\mathrm {in}}$ (red hexagon, at the centre of the inner cycle) of degree $m = 4$. Total $|V(D^{\ast }(T))| = 12$ and $|E(D^{\ast }(T))| = 20$.}}{8}{}\protected@file@percent } +\newlabel{fig:complete-tire-dual-example}{{4}{8}} +\newlabel{prop:tait-tire-complete}{{1.14}{8}} +\newlabel{rem:tait-construction}{{1.15}{8}} +\newlabel{rem:tait-octahedron}{{1.16}{8}} \bibcite{Tait1880}{1} \bibcite{bauerfeld-pds}{2} \newlabel{tocindent-1}{0pt} @@ -26,8 +31,5 @@ \newlabel{tocindent1}{17.77782pt} \newlabel{tocindent2}{0pt} \newlabel{tocindent3}{0pt} -\newlabel{prop:tait-tire-complete}{{1.14}{8}} -\newlabel{rem:tait-construction}{{1.15}{8}} -\newlabel{rem:tait-octahedron}{{1.16}{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} diff --git a/papers/coloring_nested_tire_graphs/paper.log b/papers/coloring_nested_tire_graphs/paper.log index 93cd840..cb19ea6 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 18:59 +This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022) (preloaded format=pdflatex 2022.10.5) 25 MAY 2026 19:28 entering extended mode restricted \write18 enabled. %&-line parsing enabled. @@ -213,37 +213,43 @@ 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] [8] (./paper.aux) ) + [4 <./fig_partial_tire_dual.png>] [5] [6] [7] + +File: fig_complete_tire_dual.png Graphic file (type png) + +Package pdftex.def Info: fig_complete_tire_dual.png used on input line 513. +(pdftex.def) Requested size: 295.20264pt x 188.55899pt. + [8 <./fig_complete_tire_dual.png>] [9] (./paper.aux) ) Here is how much of TeX's memory you used: - 3023 strings out of 478268 - 42435 string characters out of 5846347 - 345254 words of memory out of 5000000 - 21069 multiletter control sequences out of 15000+600000 + 3031 strings out of 478268 + 42680 string characters out of 5846347 + 345262 words of memory out of 5000000 + 21076 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 - -Output written on paper.pdf (8 pages, 628165 bytes). + 69i,8n,76p,742b,316s stack positions out of 10000i,1000n,20000p,200000b,200000s + +Output written on paper.pdf (9 pages, 748601 bytes). PDF statistics: - 123 PDF objects out of 1000 (max. 8388607) - 72 compressed objects within 1 object stream + 128 PDF objects out of 1000 (max. 8388607) + 74 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) diff --git a/papers/coloring_nested_tire_graphs/paper.pdf b/papers/coloring_nested_tire_graphs/paper.pdf index 96fbc61..e6e8503 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 03a9ef6..93ea759 100644 --- a/papers/coloring_nested_tire_graphs/paper.tex +++ b/papers/coloring_nested_tire_graphs/paper.tex @@ -508,6 +508,22 @@ vertex per face of $T$ (annular triangle, outer face, or bounded interior face of $O$), one dual edge per edge of $T$. \end{definition} +\begin{figure}[h] +\centering +\includegraphics[width=0.82\textwidth]{fig_complete_tire_dual.png} +\caption{The complete tire dual $D^{\ast}(T)$ (purple squares + face +hexagons) drawn on top of the same $m = 6$, $k = 4$ spoke-only tire +graph as Figure~\ref{fig:partial-tire-dual-example}. The ten +annular-face vertices $d_f$ form a $10$-cycle (solid purple); the +$n$ outer leaves of $D(T)$ have been merged into a single outer-face +vertex $v_{\mathrm{out}}$ (blue hexagon, drawn outside the tire) of +degree $n = 6$, and the $m$ inner leaves into a single inner-face +vertex $v_{\mathrm{in}}$ (red hexagon, at the centre of the inner +cycle) of degree $m = 4$. Total $|V(D^{\ast}(T))| = 12$ and +$|E(D^{\ast}(T))| = 20$.} +\label{fig:complete-tire-dual-example} +\end{figure} + \begin{proposition}[Tait correspondence on the complete tire dual] \label{prop:tait-tire-complete} Let $T$ be a tire graph. Then the number of non-equivalent proper