diff --git a/papers/coloring_nested_tire_graphs/experiments/cut_tire_tree.py b/papers/coloring_nested_tire_graphs/experiments/cut_tire_tree.py new file mode 100644 index 0000000..1cd1036 --- /dev/null +++ b/papers/coloring_nested_tire_graphs/experiments/cut_tire_tree.py @@ -0,0 +1,215 @@ +"""Demonstrate that the cut tires of G'_i form a tree (or forest) +under the parent-child relation "face f of H_{d+1} is contained in +face g of H_d in the planar embedding." + +For each cut tire T_{d+1}^{(f)}, identify its parent T_d^{(g)} (if +any). Each face f of H_{d+1} is geometrically inside exactly one +face g of H_d (since H_d's faces partition the plane around +H_d's edges). This gives a unique parent → child relation, hence +a forest. + +Empirical test on G'_1 of Holton-McKay #0: + - List all (d, face) pairs. + - For each (d+1, face_child), find (d, face_parent) such that + face_child lies inside face_parent in the planar embedding. + - Verify uniqueness (counterexample: a face inside multiple). + - Print the tree. +""" +import os +import sys +from collections import defaultdict + +import matplotlib.pyplot as plt +import matplotlib.patches as patches +from sage.all import Graph + +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, +) +from cut_tire import cut_tire_at + + +def compute_H_d_faces(G_i, edge_depth, d): + """Return faces of H_d (subgraph of G_i with depth-d edges), + each face represented as a sorted tuple of edges.""" + H_edges = [e for e, ed in edge_depth.items() if ed == d] + if not H_edges: + return [], None + H = Graph([(u, v) for (u, v) in H_edges], + multiedges=False, loops=False) + if not H.is_planar(set_embedding=True): + return [], None + return H.faces(), H + + +def edge_in_face(edge_uv, face_walk, H_graph): + """Check if the edge edge_uv = (u, v) is on the boundary walk of + face_walk (a list of (u, v) pairs).""" + e_norm = (min(edge_uv), max(edge_uv)) + for (a, b) in face_walk: + if (min(a, b), max(a, b)) == e_norm: + return True + return False + + +def find_parent_face(child_face_walk, H_parent, parent_faces, parent_H_graph): + """For a face of H_{d+1} (child), determine which face of H_d + (parent) it lies inside. + + Approach: pick a vertex v of child_face_walk that's also a vertex + of H_parent (= parent_H_graph). Find which face of H_parent has + v on its boundary AND that the child's edges are "inside" the + parent's face. + + For now, use a simpler heuristic: pick a vertex of the child + face; among parent faces having this vertex on their boundary, + pick the one whose face boundary walk has "small" length (= the + immediate enclosing face). + """ + child_vertices = set(u for (u, _) in child_face_walk) | \ + set(v for (_, v) in child_face_walk) + # For each parent face, check if it contains some child vertex + candidates = [] + for p_idx, p_face in enumerate(parent_faces): + p_vertices = set(u for (u, _) in p_face) | \ + set(v for (_, v) in p_face) + overlap = child_vertices & p_vertices + if overlap: + candidates.append((p_idx, len(p_face), overlap)) + if not candidates: + return None, set() + # Among candidates, pick the one with the SMALLEST face length + # (= the most "tight" enclosing face) + candidates.sort(key=lambda c: c[1]) + return candidates[0][0], candidates[0][2] + + +def build_tree(G_i, edge_depth): + """Build the tree of cut tires on G_i, indexed by (d, face_idx).""" + max_d = max(edge_depth.values()) + faces_by_depth = {} # d -> list of faces (each a list of edges) + H_graphs = {} # d -> H_d graph + for d in range(1, max_d + 1): + faces, H_d = compute_H_d_faces(G_i, edge_depth, d) + faces_by_depth[d] = faces + H_graphs[d] = H_d + # For each (d+1, face_child), find parent (d, face_parent) + parent_of = {} # (d, face_idx) -> (d_parent, p_idx) or None + for d in range(2, max_d + 1): + if not faces_by_depth.get(d): + continue + if not faces_by_depth.get(d - 1): + for f_idx in range(len(faces_by_depth[d])): + parent_of[(d, f_idx)] = None + continue + for f_idx, child_face in enumerate(faces_by_depth[d]): + p_idx, overlap = find_parent_face( + child_face, H_graphs[d - 1], + faces_by_depth[d - 1], H_graphs[d - 1]) + parent_of[(d, f_idx)] = (d - 1, p_idx) if p_idx is not None else None + # Depth-1 cut tires are "root" tires (parent = the cut) + if 1 in faces_by_depth: + for f_idx in range(len(faces_by_depth[1])): + parent_of[(1, f_idx)] = ('cut', None) + return faces_by_depth, parent_of, H_graphs + + +def print_tree(faces_by_depth, parent_of): + """Print tree of cut tires with stats.""" + # Build child list + children = defaultdict(list) + for node, parent in parent_of.items(): + if parent is not None: + children[parent].append(node) + print('\nCut tire tree:') + # Print depth-1 cut tires (roots) + for f_idx in range(len(faces_by_depth.get(1, []))): + node = (1, f_idx) + depth, fi = node + face_len = len(faces_by_depth[depth][fi]) + print(f' Root: {node} (|f|={face_len})') + _print_subtree(children, node, faces_by_depth, indent=4) + + +def _print_subtree(children, node, faces_by_depth, indent): + for child in sorted(children.get(node, [])): + d, fi = child + face_len = len(faces_by_depth[d][fi]) + print(f'{" " * indent}└─ {child} (|f|={face_len})') + _print_subtree(children, child, faces_by_depth, indent + 4) + + +def check_unique_parent(faces_by_depth, edge_depth, H_graphs, G_i): + """Stronger check: for each face of H_{d+1}, count how many faces + of H_d contain it in the planar embedding. The user's claim is + that this count is exactly 1.""" + max_d = max(edge_depth.values()) + violations = [] + for d in range(2, max_d + 1): + if not faces_by_depth.get(d) or not faces_by_depth.get(d - 1): + continue + for f_idx, child_face in enumerate(faces_by_depth[d]): + child_vertices = set(u for (u, _) in child_face) | \ + set(v for (_, v) in child_face) + matching_parents = [] + for p_idx, p_face in enumerate(faces_by_depth[d - 1]): + p_vertices = set(u for (u, _) in p_face) | \ + set(v for (_, v) in p_face) + if child_vertices & p_vertices: + matching_parents.append(p_idx) + if len(matching_parents) > 1: + violations.append({ + 'child': (d, f_idx), + 'candidate_parents': matching_parents, + 'overlap_sizes': [ + len(child_vertices & set(u for (u, _) in + faces_by_depth[d-1][p_idx]) + | set(v for (_, v) in + faces_by_depth[d-1][p_idx])) + for p_idx in matching_parents + ], + }) + return violations + + +def main(): + gs = parse_planar_code(HM_FILE) + G = gs[0] + S, cut = find_six_edge_cut(G) + base_pos = compute_nice_layout(G) + S1 = frozenset(G.vertices()) - frozenset(S) + H1, pos1, ed1, _, _, _ = apply_procedure( + G, S1, cut, base_pos, '1', + pendant_start_id=max(G.vertices()) + 1 + 6) + + print(f"G'_1 of Holton-McKay #0, depths 0 to {max(ed1.values())}") + + faces_by_depth, parent_of, H_graphs = build_tree(H1, ed1) + print_tree(faces_by_depth, parent_of) + + # Check for ambiguous parents + print('\nChecking for ambiguous parents...') + violations = check_unique_parent(faces_by_depth, ed1, H_graphs, H1) + if violations: + print(f' {len(violations)} children have multiple candidate parents') + for v in violations[:5]: + print(f' {v}') + else: + print(' No ambiguity: every child has exactly one parent candidate ' + '(based on vertex sharing).') + + # Now do G'_0 as well + S0 = frozenset(S) + H0, pos0, ed0, _, _, _ = apply_procedure( + G, S0, cut, base_pos, '0', + pendant_start_id=max(G.vertices()) + 1) + print(f"\n\nG'_0 of Holton-McKay #0, depths 0 to {max(ed0.values())}") + faces_by_depth_0, parent_of_0, _ = build_tree(H0, ed0) + print_tree(faces_by_depth_0, parent_of_0) + + +if __name__ == '__main__': + main() diff --git a/papers/coloring_nested_tire_graphs/notes/cut_tire_tree_structure.aux b/papers/coloring_nested_tire_graphs/notes/cut_tire_tree_structure.aux new file mode 100644 index 0000000..4206050 --- /dev/null +++ b/papers/coloring_nested_tire_graphs/notes/cut_tire_tree_structure.aux @@ -0,0 +1,4 @@ +\relax +\newlabel{prop:tree}{{}{1}} +\@writefile{toc}{\contentsline {paragraph}{Reformulated chain half (tree DP form).}{3}{}\protected@file@percent } +\gdef \@abspage@last{3} diff --git a/papers/coloring_nested_tire_graphs/notes/cut_tire_tree_structure.log b/papers/coloring_nested_tire_graphs/notes/cut_tire_tree_structure.log new file mode 100644 index 0000000..8fb08e5 --- /dev/null +++ b/papers/coloring_nested_tire_graphs/notes/cut_tire_tree_structure.log @@ -0,0 +1,305 @@ +This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022) (preloaded format=pdflatex 2022.10.5) 26 MAY 2026 18:17 +entering extended mode + restricted \write18 enabled. + %&-line parsing enabled. +**cut_tire_tree_structure.tex +(./cut_tire_tree_structure.tex +LaTeX2e <2021-11-15> patch level 1 +L3 programming layer <2022-02-24> +(/usr/local/texlive/2022/texmf-dist/tex/latex/base/article.cls +Document Class: article 2021/10/04 v1.4n Standard LaTeX document class +(/usr/local/texlive/2022/texmf-dist/tex/latex/base/size11.clo +File: size11.clo 2021/10/04 v1.4n Standard LaTeX file (size option) +) +\c@part=\count185 +\c@section=\count186 +\c@subsection=\count187 +\c@subsubsection=\count188 +\c@paragraph=\count189 +\c@subparagraph=\count190 +\c@figure=\count191 +\c@table=\count192 +\abovecaptionskip=\skip47 +\belowcaptionskip=\skip48 +\bibindent=\dimen138 +) +(/usr/local/texlive/2022/texmf-dist/tex/latex/amsmath/amsmath.sty +Package: amsmath 2021/10/15 v2.17l AMS math features +\@mathmargin=\skip49 + +For additional information on amsmath, use the `?' option. +(/usr/local/texlive/2022/texmf-dist/tex/latex/amsmath/amstext.sty +Package: amstext 2021/08/26 v2.01 AMS text + +(/usr/local/texlive/2022/texmf-dist/tex/latex/amsmath/amsgen.sty +File: amsgen.sty 1999/11/30 v2.0 generic functions +\@emptytoks=\toks16 +\ex@=\dimen139 +)) +(/usr/local/texlive/2022/texmf-dist/tex/latex/amsmath/amsbsy.sty +Package: amsbsy 1999/11/29 v1.2d Bold Symbols +\pmbraise@=\dimen140 +) +(/usr/local/texlive/2022/texmf-dist/tex/latex/amsmath/amsopn.sty +Package: amsopn 2021/08/26 v2.02 operator names +) +\inf@bad=\count193 +LaTeX Info: Redefining \frac on input line 234. +\uproot@=\count194 +\leftroot@=\count195 +LaTeX Info: Redefining \overline on input line 399. +\classnum@=\count196 +\DOTSCASE@=\count197 +LaTeX Info: Redefining \ldots on input line 496. +LaTeX Info: Redefining \dots on input line 499. +LaTeX Info: Redefining \cdots on input line 620. +\Mathstrutbox@=\box50 +\strutbox@=\box51 +\big@size=\dimen141 +LaTeX Font Info: Redeclaring font encoding OML on input line 743. +LaTeX Font Info: Redeclaring font encoding OMS on input line 744. +\macc@depth=\count198 +\c@MaxMatrixCols=\count199 +\dotsspace@=\muskip16 +\c@parentequation=\count266 +\dspbrk@lvl=\count267 +\tag@help=\toks17 +\row@=\count268 +\column@=\count269 +\maxfields@=\count270 +\andhelp@=\toks18 +\eqnshift@=\dimen142 +\alignsep@=\dimen143 +\tagshift@=\dimen144 +\tagwidth@=\dimen145 +\totwidth@=\dimen146 +\lineht@=\dimen147 +\@envbody=\toks19 +\multlinegap=\skip50 +\multlinetaggap=\skip51 +\mathdisplay@stack=\toks20 +LaTeX Info: Redefining \[ on input line 2938. +LaTeX Info: Redefining \] on input line 2939. +) +(/usr/local/texlive/2022/texmf-dist/tex/latex/amsfonts/amssymb.sty +Package: amssymb 2013/01/14 v3.01 AMS font symbols + +(/usr/local/texlive/2022/texmf-dist/tex/latex/amsfonts/amsfonts.sty +Package: amsfonts 2013/01/14 v3.01 Basic AMSFonts support +\symAMSa=\mathgroup4 +\symAMSb=\mathgroup5 +LaTeX Font Info: Redeclaring math symbol \hbar on input line 98. +LaTeX Font Info: Overwriting math alphabet `\mathfrak' in version `bold' +(Font) U/euf/m/n --> U/euf/b/n on input line 106. +)) +(/usr/local/texlive/2022/texmf-dist/tex/latex/amscls/amsthm.sty +Package: amsthm 2020/05/29 v2.20.6 +\thm@style=\toks21 +\thm@bodyfont=\toks22 +\thm@headfont=\toks23 +\thm@notefont=\toks24 +\thm@headpunct=\toks25 +\thm@preskip=\skip52 +\thm@postskip=\skip53 +\thm@headsep=\skip54 +\dth@everypar=\toks26 +) +(/usr/local/texlive/2022/texmf-dist/tex/latex/graphics/graphicx.sty +Package: graphicx 2021/09/16 v1.2d Enhanced LaTeX Graphics (DPC,SPQR) + +(/usr/local/texlive/2022/texmf-dist/tex/latex/graphics/keyval.sty +Package: keyval 2014/10/28 v1.15 key=value parser (DPC) +\KV@toks@=\toks27 +) +(/usr/local/texlive/2022/texmf-dist/tex/latex/graphics/graphics.sty +Package: graphics 2021/03/04 v1.4d Standard LaTeX Graphics (DPC,SPQR) + +(/usr/local/texlive/2022/texmf-dist/tex/latex/graphics/trig.sty +Package: trig 2021/08/11 v1.11 sin cos tan (DPC) +) +(/usr/local/texlive/2022/texmf-dist/tex/latex/graphics-cfg/graphics.cfg +File: graphics.cfg 2016/06/04 v1.11 sample graphics configuration +) +Package graphics Info: Driver file: pdftex.def on input line 107. + +(/usr/local/texlive/2022/texmf-dist/tex/latex/graphics-def/pdftex.def +File: pdftex.def 2020/10/05 v1.2a Graphics/color driver for pdftex +)) +\Gin@req@height=\dimen148 +\Gin@req@width=\dimen149 +) +(/usr/local/texlive/2022/texmf-dist/tex/latex/geometry/geometry.sty +Package: geometry 2020/01/02 v5.9 Page Geometry + +(/usr/local/texlive/2022/texmf-dist/tex/generic/iftex/ifvtex.sty +Package: ifvtex 2019/10/25 v1.7 ifvtex legacy package. Use iftex instead. + +(/usr/local/texlive/2022/texmf-dist/tex/generic/iftex/iftex.sty +Package: iftex 2022/02/03 v1.0f TeX engine tests +)) +\Gm@cnth=\count271 +\Gm@cntv=\count272 +\c@Gm@tempcnt=\count273 +\Gm@bindingoffset=\dimen150 +\Gm@wd@mp=\dimen151 +\Gm@odd@mp=\dimen152 +\Gm@even@mp=\dimen153 +\Gm@layoutwidth=\dimen154 +\Gm@layoutheight=\dimen155 +\Gm@layouthoffset=\dimen156 +\Gm@layoutvoffset=\dimen157 +\Gm@dimlist=\toks28 +) +(/usr/local/texlive/2022/texmf-dist/tex/latex/booktabs/booktabs.sty +Package: booktabs 2020/01/12 v1.61803398 Publication quality tables +\heavyrulewidth=\dimen158 +\lightrulewidth=\dimen159 +\cmidrulewidth=\dimen160 +\belowrulesep=\dimen161 +\belowbottomsep=\dimen162 +\aboverulesep=\dimen163 +\abovetopsep=\dimen164 +\cmidrulesep=\dimen165 +\cmidrulekern=\dimen166 +\defaultaddspace=\dimen167 +\@cmidla=\count274 +\@cmidlb=\count275 +\@aboverulesep=\dimen168 +\@belowrulesep=\dimen169 +\@thisruleclass=\count276 +\@lastruleclass=\count277 +\@thisrulewidth=\dimen170 +) +(/usr/local/texlive/2022/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def +File: l3backend-pdftex.def 2022-02-07 L3 backend support: PDF output (pdfTeX) +\l__color_backend_stack_int=\count278 +\l__pdf_internal_box=\box52 +) +(./cut_tire_tree_structure.aux) +\openout1 = `cut_tire_tree_structure.aux'. + +LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 15. +LaTeX Font Info: ... okay on input line 15. +LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 15. +LaTeX Font Info: ... okay on input line 15. +LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 15. +LaTeX Font Info: ... okay on input line 15. +LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 15. +LaTeX Font Info: ... okay on input line 15. +LaTeX Font Info: Checking defaults for TS1/cmr/m/n on input line 15. +LaTeX Font Info: ... okay on input line 15. +LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 15. +LaTeX Font Info: ... okay on input line 15. +LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 15. +LaTeX Font Info: ... okay on input line 15. + +(/usr/local/texlive/2022/texmf-dist/tex/context/base/mkii/supp-pdf.mkii +[Loading MPS to PDF converter (version 2006.09.02).] +\scratchcounter=\count279 +\scratchdimen=\dimen171 +\scratchbox=\box53 +\nofMPsegments=\count280 +\nofMParguments=\count281 +\everyMPshowfont=\toks29 +\MPscratchCnt=\count282 +\MPscratchDim=\dimen172 +\MPnumerator=\count283 +\makeMPintoPDFobject=\count284 +\everyMPtoPDFconversion=\toks30 +) (/usr/local/texlive/2022/texmf-dist/tex/latex/epstopdf-pkg/epstopdf-base.sty +Package: epstopdf-base 2020-01-24 v2.11 Base part for package epstopdf +Package epstopdf-base Info: Redefining graphics rule for `.eps' on input line 4 +85. + +(/usr/local/texlive/2022/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg +File: epstopdf-sys.cfg 2010/07/13 v1.3 Configuration of (r)epstopdf for TeX Liv +e +)) +*geometry* driver: auto-detecting +*geometry* detected driver: pdftex +*geometry* verbose mode - [ preamble ] result: +* driver: pdftex +* paper: +* layout: +* layoutoffset:(h,v)=(0.0pt,0.0pt) +* modes: +* h-part:(L,W,R)=(72.26999pt, 469.75502pt, 72.26999pt) +* v-part:(T,H,B)=(72.26999pt, 650.43001pt, 72.26999pt) +* \paperwidth=614.295pt +* \paperheight=794.96999pt +* \textwidth=469.75502pt +* \textheight=650.43001pt +* \oddsidemargin=0.0pt +* \evensidemargin=0.0pt +* \topmargin=-37.0pt +* \headheight=12.0pt +* \headsep=25.0pt +* \topskip=11.0pt +* \footskip=30.0pt +* \marginparwidth=59.0pt +* \marginparsep=10.0pt +* \columnsep=10.0pt +* \skip\footins=10.0pt plus 4.0pt minus 2.0pt +* \hoffset=0.0pt +* \voffset=0.0pt +* \mag=1000 +* \@twocolumnfalse +* \@twosidefalse +* \@mparswitchfalse +* \@reversemarginfalse +* (1in=72.27pt=25.4mm, 1cm=28.453pt) + +LaTeX Font Info: Trying to load font information for U+msa on input line 16. + +(/usr/local/texlive/2022/texmf-dist/tex/latex/amsfonts/umsa.fd +File: umsa.fd 2013/01/14 v3.01 AMS symbols A +) +LaTeX Font Info: Trying to load font information for U+msb on input line 16. + + +(/usr/local/texlive/2022/texmf-dist/tex/latex/amsfonts/umsb.fd +File: umsb.fd 2013/01/14 v3.01 AMS symbols B +) +Overfull \hbox (83.47609pt too wide) in paragraph at lines 66--70 +[]\OT1/cmr/m/n/10.95 Compatibility with each child $\OML/cmm/m/it/10.95 T[]$ \O +T1/cmr/m/n/10.95 via the bi-jec-tion $\OMS/cmsy/m/n/10.95 f[]\OML/cmm/m/it/10.9 +5 T[]\OMS/cmsy/m/n/10.95 g $ f[]\OML/cmm/m/it/10.95 T[]\OMS/cmsy/m/n/10.95 g$\O +T1/cmr/m/n/10.95 . + [] + +[1 + +{/usr/local/texlive/2022/texmf-var/fonts/map/pdftex/updmap/pdftex.map}] +[2] [3] (./cut_tire_tree_structure.aux) ) +Here is how much of TeX's memory you used: + 3238 strings out of 478268 + 48314 string characters out of 5846347 + 348571 words of memory out of 5000000 + 21428 multiletter control sequences out of 15000+600000 + 477658 words of font info for 59 fonts, out of 8000000 for 9000 + 1141 hyphenation exceptions out of 8191 + 55i,6n,62p,240b,226s stack positions out of 10000i,1000n,20000p,200000b,200000s +{/usr/local/texlive/2022/texmf-dist/fo +nts/enc/dvips/cm-super/cm-super-ts1.enc} +Output written on cut_tire_tree_structure.pdf (3 pages, 177377 bytes). +PDF statistics: + 90 PDF objects out of 1000 (max. 8388607) + 54 compressed objects within 1 object stream + 0 named destinations out of 1000 (max. 500000) + 1 words of extra memory for PDF output out of 10000 (max. 10000000) + diff --git a/papers/coloring_nested_tire_graphs/notes/cut_tire_tree_structure.pdf b/papers/coloring_nested_tire_graphs/notes/cut_tire_tree_structure.pdf new file mode 100644 index 0000000..59075f6 Binary files /dev/null and b/papers/coloring_nested_tire_graphs/notes/cut_tire_tree_structure.pdf differ diff --git a/papers/coloring_nested_tire_graphs/notes/cut_tire_tree_structure.tex b/papers/coloring_nested_tire_graphs/notes/cut_tire_tree_structure.tex new file mode 100644 index 0000000..dc6b8bd --- /dev/null +++ b/papers/coloring_nested_tire_graphs/notes/cut_tire_tree_structure.tex @@ -0,0 +1,179 @@ +\documentclass[11pt]{article} +\usepackage{amsmath,amssymb,amsthm} +\usepackage{graphicx} +\usepackage{geometry} +\usepackage{booktabs} +\geometry{margin=1in} + +\title{Cut tires form a tree (under depth nesting)} +\author{} +\date{} + +\newtheorem*{obs}{Observation} +\newtheorem*{prop}{Proposition} + +\begin{document} +\maketitle + +\section*{The claim} + +\begin{prop}[Cut tires form a forest] +\label{prop:tree} +For each side $i$ of a $6$-edge cut of $G'$, the cut tires of $G'_i$, +parameterised by pairs $(d, f)$ with $d \ge 1$ and $f$ a face of +$H_d$, form a \emph{forest} under the parent--child relation +\[ + \mathrm{parent}\bigl(T_{d+1}^{(f')}\bigr) := T_d^{(f)} +\] +where $f$ is the unique face of $H_d$ in whose planar interior $f'$ +lies in the inherited embedding of $G'_i$. + +The forest's roots are the cut tires at depth $1$ (one per face of +$H_1$); their ``virtual parent'' is the cut $C$ itself. +\end{prop} + +\begin{proof}[Sketch] +$H_{d+1}$ is a subgraph of $G'_i$ with the inherited planar +embedding. Each face of $H_{d+1}$ is a maximal connected open +region of $|\Pi| \setminus E(H_{d+1})$ in the plane. + +In particular, every face of $H_{d+1}$ lies inside some face of $H_d$ +(since $H_d$ has fewer edges and so larger faces). ``Lies inside'' +means: the open face region of $H_{d+1}$ is a subset of an open face +region of $H_d$. This containment is unique because the faces of +$H_d$ partition $|\Pi| \setminus E(H_d)$. + +Hence parent is well-defined and unique. No face of $H_{d+1}$ is +its own parent (because $d+1 > d$). The relation defines a forest. + +The roots are the depth-$1$ cut tires. Their ``virtual parent'' is +the depth-$0$ pendant configuration, i.e.\ the cut $C$ itself. +\end{proof} + +\section*{Why this matters for the chain half} + +Chain pigeonhole asks whether the per-tire $S_3$-orbit structure +composes coherently through the chain. With a tree structure on +the cut tires, this becomes a \textbf{tree dynamic-programming +problem}, not a general graph compatibility problem: +\begin{itemize} + \item Process tires from leaves to root. + \item At each leaf: $\pi(T_{\mathrm{leaf}})$ has known structure + (e.g.\ $S_3$-orbits) from the per-tire half. + \item Internal node $T_d^{(f)}$ combines: + \begin{itemize} + \item Its own internal $\pi(T)$ structure. + \item Compatibility with each child $T_{d+1}^{(f')}$ + via the bijection $\{\text{in spokes of } T_d^{(f)}\} + \leftrightarrow \{\text{face boundary edges of } + T_{d+1}^{(f')}\}$. + \end{itemize} + \item Root: $T_1^{(\cdot)}$ projects its out-spoke colours to + $\sigma_i \in \mathcal{R}_i$. +\end{itemize} + +Tree DP is well-understood: $|\mathcal{R}_i|$ can be computed +exactly in linear time in the tree size (with size-$|\pi|$ tables +at each node). Whether the resulting $\mathcal{R}_0$ and +$\mathcal{R}_1$ intersect is a finite check at the cut. + +The tree structure is also a \textbf{strong topological constraint} +on the chain pigeonhole obstruction: any counterexample to +chain pigeonhole at the cut must come from a tree-DP failure, +which is much narrower than a general-graph obstruction. + +\section*{Empirical demonstration on Holton-McKay \#0} + +\subsection*{$G'_1$ side ($|S| = 28$, depths $0$ to $7$)} + +Two depth-$1$ roots: +\begin{itemize} + \item Root $(1, 0)$: face length $12$, no children + (the outer ``shell'' of $H_1$). + \item Root $(1, 1)$: face length $4$, with substantial subtree: + \begin{itemize} + \item $(2, 0)$ \hfill $|f| = 7$ + \begin{itemize} + \item $(3, 0)$ \hfill $|f| = 2$ + $\Rightarrow$ $(4, 0)$ \hfill $|f| = 4$ + $\Rightarrow$ $(5, 0)$ \hfill $|f| = 14$ + \item $(3, 1)$ \hfill $|f| = 2$ + $\Rightarrow$ $(4, 1)$ \hfill $|f| = 8$ + $\Rightarrow$ $(5, 1)$ \hfill $|f| = 2$ + $\Rightarrow$ $(6, 0)$ \hfill $|f| = 12$ + $\Rightarrow$ $(7, 0)$ \hfill $|f| = 2$ + \item $(3, 2)$ \hfill $|f| = 2$ + \end{itemize} + \item $(2, 1)$ \hfill $|f| = 7$ + \end{itemize} +\end{itemize} + +\subsection*{$G'_0$ side ($|S| = 10$, depths $0$ to $2$)} + +Two depth-$1$ roots: +\begin{itemize} + \item Root $(1, 0)$: face length $9$, with one child $(2, 0)$ + ($|f| = 6$). + \item Root $(1, 1)$: face length $9$, no children. +\end{itemize} + +\section*{Caveats on the empirical parent identification} + +The empirical demonstration used a vertex-sharing heuristic to +identify parents: a face $f'$ of $H_{d+1}$ shares vertices with a +face $f$ of $H_d$, and we picked the parent as the one with smallest +face length. This gives ambiguous candidates in some cases ($8$ +ambiguous cases observed in $G'_1$) because vertex sharing does not +fully determine geometric containment. + +A rigorous parent test would use \emph{point-in-region} containment: +pick a point in the open face of $H_{d+1}$ (e.g., the centroid of +its boundary walk), determine which face of $H_d$ that point lies +in (via the planar embedding's face structure). This always gives +a unique answer. + +The ambiguity in our empirical run doesn't reflect a violation of +the proposition --- it's an artifact of the heuristic. Despite the +ambiguity, the resulting tree structure looked sensible in both +$G'_0$ and $G'_1$. + +\section*{Consequence: the chain half becomes tractable} + +With the tree structure established (or assumed), the chain half of +the loose chain pigeonhole conjecture reduces to: + +\paragraph{Reformulated chain half (tree DP form).} +For each leaf cut tire $T_{\mathrm{leaf}}$, $\pi(T_{\mathrm{leaf}})$ +is non-empty and $S_3$-closed. Propagating bottom-up through the +parent--child relation preserves $S_3$-closure and non-emptiness. +At the root depth-$1$ tires, $\mathcal{R}_i$ is the join of the +root tires' out-spoke projections. If $\mathcal{R}_i$ is +$S_3$-closed and contains a full $S_3$-orbit on each side, then +$\mathcal{R}_0 \cap \mathcal{R}_1 \neq \emptyset$ (containing a +common orbit by $S_3$-equivariance). + +The remaining questions: +\begin{enumerate} + \item Is non-emptiness preserved through parent-child propagation? + \item Is $S_3$-closure preserved? (Yes, by $S_3$-equivariance of + the proper edge $3$-colouring constraint.) + \item Does the join of root projections contain a full $S_3$-orbit? +\end{enumerate} + +Each of these is now a finite tree DP claim, much more tractable +than the original ``compose through the chain'' formulation. + +\section*{Next step} + +\begin{enumerate} + \item Prove Proposition~\ref{prop:tree} rigorously using the + point-in-region containment definition of parent. + \item Implement the tree DP empirically on the Holton-McKay graphs + and confirm $\mathcal{R}_0 \cap \mathcal{R}_1 \neq \emptyset$ + at the cut. + \item Attempt an analytical bound: $|\mathcal{R}_i| \ge \mathrm{some + function of tree size}$, ensuring $\mathcal{R}_0 \cap + \mathcal{R}_1 \neq \emptyset$ in general. +\end{enumerate} + +\end{document}