diff --git a/papers/coloring_nested_tire_graphs/experiments/cut_tire.py b/papers/coloring_nested_tire_graphs/experiments/cut_tire.py new file mode 100644 index 0000000..3b339fd --- /dev/null +++ b/papers/coloring_nested_tire_graphs/experiments/cut_tire.py @@ -0,0 +1,247 @@ +"""Define and visualise a cut tire: a structure built from a face of +the depth-d subgraph of a cut half G'_i, together with adjacent edges +at depths d-1 and d+1. + +Procedure for a chosen d > 0: + 1. Build H_d := subgraph of G'_i on edges of depth d. + 2. Find the faces of H_d in the inherited planar embedding. + 3. Pick one face f. + 4. The cut tire at (d, f) is the subgraph of G'_i consisting of: + - The boundary edges of f (all depth d in H_d), AND + - All edges of G'_i with at least one endpoint on the boundary + walk of f whose depth is d-1 or d+1. +""" +import os +import sys +import math +from collections import deque, defaultdict + +import matplotlib.pyplot as plt +import matplotlib.patches as patches + +from sage.all import Graph + +# Reuse the cut-and-depth-label infrastructure. +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, HERE) +from cut_depth_label import ( + parse_planar_code, HM_FILE, find_six_edge_cut, + apply_procedure, compute_nice_layout, +) + + +def faces_of_subgraph(H, pos): + """Find faces of H using its planar embedding inherited from pos. + Uses Sage's planar embedding facility. Returns list of faces, each + a list of vertices in cyclic order on the face boundary.""" + if not H.is_planar(set_embedding=True): + return [] + return H.faces() + + +def cut_tire_at(G_i, edge_depth, d): + """Build cut tires at depth d for each face of the depth-d subgraph. + Returns list of (face_vertices, tire_subgraph_edges_by_role) where: + tire_subgraph_edges_by_role is a dict with keys + 'face' (boundary at depth d), 'inner' (adjacent at d-1), + 'outer' (adjacent at d+1). + """ + # Build H_d + H_d_edges = [e for e, ed in edge_depth.items() if ed == d] + H_d = Graph([(u, v) for (u, v) in H_d_edges], + multiedges=False, loops=False) + if H_d.size() == 0: + return [] + if not H_d.is_planar(set_embedding=True): + return [] + faces_h_d = H_d.faces() + results = [] + for face in faces_h_d: + # face is a list of (u, v) edge-pairs going around the boundary + # in Sage; convert to vertex sequence + vertices_on_face = [] + for (u, v) in face: + vertices_on_face.append(u) + face_vertex_set = set(vertices_on_face) + # Boundary edges of the face (in H_d): they're the face edges + face_edges = [(min(u, v), max(u, v)) for (u, v) in face] + # Find adjacent edges at d-1 and d+1 from G'_i + inner_edges = [] # depth d-1 + outer_edges = [] # depth d+1 + for e_full, ed in edge_depth.items(): + if ed not in (d - 1, d + 1): + continue + u, v = e_full + if u in face_vertex_set or v in face_vertex_set: + if ed == d - 1: + inner_edges.append(e_full) + else: + outer_edges.append(e_full) + results.append({ + 'face_vertices': vertices_on_face, + 'face_edges': face_edges, + 'inner_edges': inner_edges, + 'outer_edges': outer_edges, + 'face_length': len(face), + }) + return results + + +def draw_cut_tire(ax, G_i, pos, edge_depth, tire, d, title): + """Draw G_i faded with a single cut tire highlighted.""" + face_set = set(tire['face_edges']) + inner_set = set(tire['inner_edges']) + outer_set = set(tire['outer_edges']) + face_vertex_set = set(tire['face_vertices']) + + # Fade all G_i edges + for e in G_i.edges(labels=False): + u, v = e + e_norm = (min(u, v), max(u, v)) + if e_norm in face_set or e_norm in inner_set or e_norm in outer_set: + continue + x1, y1 = pos[u]; x2, y2 = pos[v] + ax.plot([x1, x2], [y1, y2], color='#dddddd', linewidth=0.9, + zorder=1) + + # Highlight the tire + for e in face_set: + u, v = e + x1, y1 = pos[u]; x2, y2 = pos[v] + ax.plot([x1, x2], [y1, y2], color='#1f77b4', linewidth=3.0, + zorder=3, label=None) + for e in inner_set: + u, v = e + x1, y1 = pos[u]; x2, y2 = pos[v] + ax.plot([x1, x2], [y1, y2], color='#d62728', linewidth=2.4, + linestyle='--', zorder=2) + for e in outer_set: + u, v = e + x1, y1 = pos[u]; x2, y2 = pos[v] + ax.plot([x1, x2], [y1, y2], color='#2ca02c', linewidth=2.4, + linestyle='--', zorder=2) + + # Draw vertices: face vertices highlighted, others faded + for v in G_i.vertices(): + x, y = pos[v] + if v in face_vertex_set: + ax.plot(x, y, 'o', color='#1f77b4', markersize=10, + zorder=4, markeredgecolor='#0a3b5f', + markeredgewidth=1.0) + else: + ax.plot(x, y, 'o', color='#bbbbbb', markersize=5, zorder=2) + + legend = [ + plt.Line2D([], [], color='#1f77b4', linewidth=3, + label=f'face boundary (depth {d})'), + plt.Line2D([], [], color='#d62728', linewidth=2.4, + linestyle='--', label=f'inner spokes (depth {d - 1})'), + plt.Line2D([], [], color='#2ca02c', linewidth=2.4, + linestyle='--', label=f'outer spokes (depth {d + 1})'), + ] + ax.legend(handles=legend, loc='upper left', + bbox_to_anchor=(1.02, 1.0), fontsize=9, frameon=False) + ax.set_aspect('equal'); ax.axis('off') + ax.set_title(title, fontsize=10) + + +def main(): + out_fig = os.path.normpath(os.path.join(HERE, '..', 'notes', + 'fig_cut_tire.png')) + gs = parse_planar_code(HM_FILE) + G = gs[0] + S, cut = find_six_edge_cut(G) + base_pos = compute_nice_layout(G) + S0 = frozenset(S) + S1 = frozenset(G.vertices()) - S0 + H0, pos0, ed0, _, _, _ = apply_procedure( + G, S0, cut, base_pos, '0', + pendant_start_id=max(G.vertices()) + 1) + H1, pos1, ed1, _, _, _ = apply_procedure( + G, S1, cut, base_pos, '1', + pendant_start_id=max(G.vertices()) + 1 + 6) + + # Try several depths in G'_1 (which has depths 0-7) and pick a + # decent example. + print(f"G'_1 depths range: 0 to {max(ed1.values())}") + chosen_d = None + chosen_tire = None + for d in range(1, max(ed1.values())): + tires = cut_tire_at(H1, ed1, d) + print(f' depth {d}: {len(tires)} faces in depth-{d} subgraph') + for tire in tires: + print(f' face length {tire["face_length"]}, ' + f'inner spokes: {len(tire["inner_edges"])}, ' + f'outer spokes: {len(tire["outer_edges"])}') + # Pick the largest "interesting" face: try to find one with + # > 3 face edges AND inner/outer spokes both > 0. + candidates = [t for t in tires + if t['face_length'] >= 4 + and t['inner_edges'] and t['outer_edges']] + if candidates and chosen_tire is None: + chosen_d = d + # Pick the face with the most spokes total (most "informative") + candidates.sort(key=lambda t: -(len(t['inner_edges']) + + len(t['outer_edges']))) + chosen_tire = candidates[0] + + if chosen_tire is None: + print('No suitable cut tire found.') + return + + print(f"\nChosen cut tire at depth d = {chosen_d}") + print(f" face length: {chosen_tire['face_length']}") + print(f" inner spokes (depth {chosen_d - 1}): " + f"{len(chosen_tire['inner_edges'])}") + print(f" outer spokes (depth {chosen_d + 1}): " + f"{len(chosen_tire['outer_edges'])}") + + # Collect "best" cut tires at multiple depths + selected = [] + for d in range(1, max(ed1.values())): + tires = cut_tire_at(H1, ed1, d) + candidates = [t for t in tires + if t['face_length'] >= 4 + and t['inner_edges'] and t['outer_edges']] + if candidates: + candidates.sort(key=lambda t: -(len(t['inner_edges']) + + len(t['outer_edges']))) + selected.append((d, candidates[0])) + print(f"\nCut tires selected for visualization at depths: " + f"{[d for d, _ in selected]}") + + # Multi-panel figure + n = len(selected) + cols = 2 + rows = (n + cols - 1) // cols + xs = [p[0] for p in base_pos.values()] + ys = [p[1] for p in base_pos.values()] + fig, axes = plt.subplots(rows, cols, figsize=(13, 5 * rows)) + if rows == 1: + axes = [axes] + axes_flat = [ax for row in axes for ax in (row if hasattr(row, '__iter__') else [row])] + for idx, (d, tire) in enumerate(selected): + ax = axes_flat[idx] + draw_cut_tire(ax, H1, pos1, ed1, tire, d, + title=(f"$d = {d}$: face length " + f"{tire['face_length']}, " + f"{len(tire['inner_edges'])} inner + " + f"{len(tire['outer_edges'])} outer spokes")) + ax.set_xlim(min(xs) - 0.5, max(xs) + 0.5) + ax.set_ylim(min(ys) - 0.5, max(ys) + 0.5) + for idx in range(n, len(axes_flat)): + axes_flat[idx].axis('off') + fig.suptitle(r"Cut tires on $G'_1$ (Holton-McKay #0, V\S half) at " + r"several depths $d$" + "\n" + r"Each panel: blue face boundary at depth $d$ " + r"+ inner spokes (depth $d-1$, red dashed) " + r"+ outer spokes (depth $d+1$, green dashed)", + fontsize=11, y=1.00) + plt.tight_layout() + plt.savefig(out_fig, dpi=160, bbox_inches='tight') + plt.close() + print(f'Wrote {out_fig}') + + +if __name__ == '__main__': + main() diff --git a/papers/coloring_nested_tire_graphs/notes/cut_depth_label.aux b/papers/coloring_nested_tire_graphs/notes/cut_depth_label.aux index c99ea83..3179681 100644 --- a/papers/coloring_nested_tire_graphs/notes/cut_depth_label.aux +++ b/papers/coloring_nested_tire_graphs/notes/cut_depth_label.aux @@ -1,8 +1,12 @@ \relax \@writefile{toc}{\contentsline {paragraph}{The chosen 6-edge cut.}{1}{}\protected@file@percent } \@writefile{toc}{\contentsline {paragraph}{Resulting half-graphs.}{2}{}\protected@file@percent } -\@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces Cut-and-depth-label procedure on Holton-McKay graph \#0 ($38$ vertices, $57$ edges, cubic planar non-Hamiltonian). The $6$-edge matching cut splits $G'$ into a $10$-vertex piece $G'_0$ (left) and a $28$-vertex piece $G'_1$ (right). Pendant edges (dashed, dark purple) are at depth $0$; the colour gradient encodes depth $0$ through max depth via BFS in the line-graph sense. Orange squares are the new pendant vertices; red circles are the boundary vertices in $V_i$; gray circles are interior vertices.\relax }}{2}{}\protected@file@percent } -\providecommand*\caption@xref[2]{\@setref\relax\@undefined{#1}} -\newlabel{fig:cut-depth-label}{{1}{2}} \@writefile{toc}{\contentsline {paragraph}{Visualization.}{2}{}\protected@file@percent } -\gdef \@abspage@last{3} +\@writefile{toc}{\contentsline {paragraph}{Relation to the existing tire framework.}{2}{}\protected@file@percent } +\@writefile{toc}{\contentsline {paragraph}{Example on $G'_1$ (Holton-McKay \#0, $V \setminus S$ half).}{3}{}\protected@file@percent } +\@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces Cut-and-depth-label procedure on Holton-McKay graph \#0 ($38$ vertices, $57$ edges, cubic planar non-Hamiltonian). The $6$-edge matching cut splits $G'$ into a $10$-vertex piece $G'_0$ (left) and a $28$-vertex piece $G'_1$ (right). Pendant edges (dashed, dark purple) are at depth $0$; the colour gradient encodes depth $0$ through max depth via BFS in the line-graph sense. Orange squares are the new pendant vertices; red circles are the boundary vertices in $V_i$; gray circles are interior vertices.\relax }}{4}{}\protected@file@percent } +\providecommand*\caption@xref[2]{\@setref\relax\@undefined{#1}} +\newlabel{fig:cut-depth-label}{{1}{4}} +\@writefile{lof}{\contentsline {figure}{\numberline {2}{\ignorespaces Cut tires on $G'_1$ at depths $d = 1, 2, 4, 5, 6$. In each panel, blue solid edges form the face boundary at depth $d$; red dashed edges are inner spokes (depth $d - 1$); green dashed edges are outer spokes (depth $d + 1$). Vertices on the face boundary are highlighted; the rest of $G'_1$ is faded.\relax }}{5}{}\protected@file@percent } +\newlabel{fig:cut-tire}{{2}{5}} +\gdef \@abspage@last{5} diff --git a/papers/coloring_nested_tire_graphs/notes/cut_depth_label.log b/papers/coloring_nested_tire_graphs/notes/cut_depth_label.log index 4f3b049..c3455a9 100644 --- a/papers/coloring_nested_tire_graphs/notes/cut_depth_label.log +++ b/papers/coloring_nested_tire_graphs/notes/cut_depth_label.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) 26 MAY 2026 15:00 +This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022) (preloaded format=pdflatex 2022.10.5) 26 MAY 2026 15:32 entering extended mode restricted \write18 enabled. %&-line parsing enabled. @@ -288,45 +288,89 @@ n[]level[]graph[]generators/experiments/nonham38m4.pc\OT1/cmr/m/n/10.95 ). [1 {/usr/local/texlive/2022/texmf-var/fonts/map/pdftex/updmap/pdftex.map}] - + File: fig_cut_depth_label.png Graphic file (type png) Package pdftex.def Info: fig_cut_depth_label.png used on input line 108. -(pdftex.def) Requested size: 469.75502pt x 230.7281pt. +(pdftex.def) Requested size: 469.75502pt x 1231.6049pt. -Overfull \hbox (46.78696pt too wide) in paragraph at lines 123--130 + +LaTeX Warning: Float too large for page by 659.17491pt on input line 119. + + +LaTeX Warning: `h' float specifier changed to `ht'. + + +! LaTeX Error: Environment definition undefined. + +See the LaTeX manual or LaTeX Companion for explanation. +Type H for immediate help. + ... + +l.129 \begin{definition} + [Cut tire] +Your command was ignored. +Type I to replace it with another command, +or to continue without it. + + +! LaTeX Error: \begin{document} ended by \end{definition}. + +See the LaTeX manual or LaTeX Companion for explanation. +Type H for immediate help. + ... + +l.149 \end{definition} + +Your command was ignored. +Type I to replace it with another command, +or to continue without it. + + +File: fig_cut_tire.png Graphic file (type png) + +Package pdftex.def Info: fig_cut_tire.png used on input line 171. +(pdftex.def) Requested size: 469.75502pt x 590.68202pt. + +LaTeX Warning: `h' float specifier changed to `ht'. + +[2] +Overfull \hbox (46.78696pt too wide) in paragraph at lines 195--202 \OT1/cmr/m/n/10.95 The pro-ce-dure mir-rors the $4$CT cut-and-reglue scheme (\O T1/cmtt/m/n/10.95 rainbow[]proof.tex\OT1/cmr/m/n/10.95 , \OT1/cmtt/m/n/10.95 wo rst[]case[]proof[]sketch.tex\OT1/cmr/m/n/10.95 , [] -[2 <./fig_cut_depth_label.png>] [3] (./cut_depth_label.aux) ) +[3] [4 <./fig_cut_depth_label.png>] [5 <./fig_cut_tire.png>] +(./cut_depth_label.aux) ) Here is how much of TeX's memory you used: - 4579 strings out of 478268 - 74295 string characters out of 5846347 - 370409 words of memory out of 5000000 - 22760 multiletter control sequences out of 15000+600000 + 4588 strings out of 478268 + 74465 string characters out of 5846347 + 375417 words of memory out of 5000000 + 22768 multiletter control sequences out of 15000+600000 479174 words of font info for 66 fonts, out of 8000000 for 9000 1141 hyphenation exceptions out of 8191 55i,8n,63p,656b,312s stack positions out of 10000i,1000n,20000p,200000b,200000s -{/usr/local/texliv -e/2022/texmf-dist/fonts/enc/dvips/cm-super/cm-super-ts1.enc} -Output written on cut_depth_label.pdf (3 pages, 357384 bytes). +{/usr/local/texlive/2022/texmf-dist/fonts/enc/dvips/cm +-super/cm-super-ts1.enc} +Output written on cut_depth_label.pdf (5 pages, 500070 bytes). PDF statistics: - 78 PDF objects out of 1000 (max. 8388607) - 46 compressed objects within 1 object stream + 96 PDF objects out of 1000 (max. 8388607) + 56 compressed objects within 1 object stream 0 named destinations out of 1000 (max. 500000) - 6 words of extra memory for PDF output out of 10000 (max. 10000000) + 11 words of extra memory for PDF output out of 10000 (max. 10000000) diff --git a/papers/coloring_nested_tire_graphs/notes/cut_depth_label.pdf b/papers/coloring_nested_tire_graphs/notes/cut_depth_label.pdf index fd06d14..ab54d77 100644 Binary files a/papers/coloring_nested_tire_graphs/notes/cut_depth_label.pdf and b/papers/coloring_nested_tire_graphs/notes/cut_depth_label.pdf differ diff --git a/papers/coloring_nested_tire_graphs/notes/cut_depth_label.tex b/papers/coloring_nested_tire_graphs/notes/cut_depth_label.tex index d07e1c5..2eb5f0b 100644 --- a/papers/coloring_nested_tire_graphs/notes/cut_depth_label.tex +++ b/papers/coloring_nested_tire_graphs/notes/cut_depth_label.tex @@ -118,6 +118,78 @@ vertices.} \label{fig:cut-depth-label} \end{figure} +\section*{Cut tires} + +The depth labelling on $G'_i$ organises its edges into layers indexed +by distance to the cut. Each layer gives rise to a family of +``cut tires'' that play the same structural role as the tires of +\texttt{paper.tex} but are derived from the cut rather than from a +level source in the primal $G$. + +\begin{definition}[Cut tire] +Let $G'_i$ be a cut half (Step~3 above) with edge depth labelling +$\mathrm{depth} : E(G'_i) \to \mathbb{Z}_{\ge 0}$. Fix $d > 0$ and +let $H_d \subseteq G'_i$ be the subgraph induced on the edges of +depth $d$ (vertex set $=$ endpoints of depth-$d$ edges, edges $=$ +depth-$d$ edges). Equip $H_d$ with the planar embedding inherited +from $G'_i$. + +For each face $f$ of $H_d$, the \emph{cut tire at $(d, f)$} is the +subgraph of $G'_i$ consisting of: +\begin{itemize} + \item every edge on the boundary walk of $f$ (all of depth $d$ in + $H_d$), and + \item every edge of $G'_i$ with at least one endpoint on the + boundary walk of $f$ whose depth is $d - 1$ or $d + 1$. +\end{itemize} +The first set forms the \emph{face boundary at depth $d$}; the second +splits into \emph{inner spokes} (depth $d - 1$, pointing toward the +cut) and \emph{outer spokes} (depth $d + 1$, pointing away from the +cut). +\end{definition} + +\paragraph{Relation to the existing tire framework.} Under the +correspondence between primal level structure (paper.tex) and dual +depth labelling, a cut tire on $G'_i$ at $(d, f)$ corresponds to: +\begin{itemize} + \item face boundary at depth $d$ $\longleftrightarrow$ the tire + annular subgraph $T'_{\mathrm{ann}}$ at depth $d$ from the + cut (cf.\ Def.~1.15 of paper.tex); + \item the cut tire itself $\longleftrightarrow$ the tire annular + face connector $T'_{f'}$ (cf.\ Def.~1.16); + \item inner / outer spokes $\longleftrightarrow$ the inner and + outer spokes of $T'_{f'}$ (cf.\ Def.~1.17). +\end{itemize} +So the cut tire is the dual-side analogue of the +``tire annular face connector,'' parametrised by depth from the cut +rather than depth from a primal level source. + +\paragraph{Example on $G'_1$ (Holton-McKay \#0, $V \setminus S$ half).} + +\begin{figure}[h] +\centering +\includegraphics[width=\textwidth]{fig_cut_tire.png} +\caption{Cut tires on $G'_1$ at depths $d = 1, 2, 4, 5, 6$. In each +panel, blue solid edges form the face boundary at depth $d$; red +dashed edges are inner spokes (depth $d - 1$); green dashed edges +are outer spokes (depth $d + 1$). Vertices on the face boundary are +highlighted; the rest of $G'_1$ is faded.} +\label{fig:cut-tire} +\end{figure} + +In this example: +\begin{itemize} + \item $d = 1$: face length $12$, $5$ inner spokes (to depth-$0$ + pendants) $+$ $4$ outer spokes. This is the outermost cut + tire, immediately adjacent to the cut. + \item $d = 2$: face length $7$ (one of two symmetric faces in + $H_2$), $4 + 3$ spokes. + \item $d = 4$: face length $8$, $2 + 5$ spokes. + \item $d = 5$: face length $14$, $4 + 6$ spokes. + \item $d = 6$: face length $12$, $7 + 1$ spokes. This is the + innermost cut tire (one face left, almost no outer spokes). +\end{itemize} + \section*{Connection to chain pigeonhole / 4CT reducibility} The procedure mirrors the $4$CT cut-and-reglue scheme diff --git a/papers/coloring_nested_tire_graphs/notes/fig_cut_tire.png b/papers/coloring_nested_tire_graphs/notes/fig_cut_tire.png new file mode 100644 index 0000000..b4a2bd2 Binary files /dev/null and b/papers/coloring_nested_tire_graphs/notes/fig_cut_tire.png differ