diff --git a/papers/coloring_nested_tire_graphs/experiments/boundary_cut_tire.py b/papers/coloring_nested_tire_graphs/experiments/boundary_cut_tire.py new file mode 100644 index 0000000..552d998 --- /dev/null +++ b/papers/coloring_nested_tire_graphs/experiments/boundary_cut_tire.py @@ -0,0 +1,357 @@ +"""Boundary cut tire T_∂: identification + chain DP integration. + +T_∂^(i) on side i: + - Cycle = boundary walk of the unique low-side face of H_1 + (the face containing pendants). + - OUT pendants = depth-0 edges (pendants) inside f_∂. + - IN pendants = depth-2 edges in adjacent high-side H_1 faces + (= the "third edge" at boundary vertices when it's depth 2). + +Empirical test: extended chain DP including T_∂ should yield +non-empty R_i matching the ground-truth projection of G'_i's +3-edge colorings. +""" +import os +import sys +import itertools +from collections import defaultdict + +from sage.all import Graph, graphs + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, HERE) +from cut_depth_label import ( + parse_planar_code, HM_FILE, + apply_procedure, compute_nice_layout, +) +from cut_tire_tree import build_tree, compute_H_d_faces +from tree_structure_sweep import all_six_edge_cuts + + +def classify_h1_faces(H, edge_depth): + """Compute the faces of H_1, classify each as low-side or + high-side based on its interior content (depth-0 vs depth->=2). + Returns (low_face, high_faces) where low_face is the (unique) + low-side face's boundary walk.""" + faces, H1 = compute_H_d_faces(H, edge_depth, 1) + if not faces: + return None, [] + # For each face, examine the interior: pick an interior point and + # ask which depth edges of G'_i lie inside. Topologically: take + # face's interior as a connected region, find which non-H_1 edges + # lie strictly inside. + # Simpler combinatorial approach: a face f of H_1 is high-side iff + # every non-H_1 edge incident to a boundary vertex of f, on the + # f-side, has depth >= 2. Low-side iff at least one such has + # depth 0. + # Since we can't easily check "f-side", use the simpler test: + # face is low-side iff ANY pendant (depth-0 edge) is incident to + # a vertex of f. + pendant_verts = set() + for e, d in edge_depth.items(): + if d == 0: + for v in e: + pendant_verts.add(v) + classified = [] + for face in faces: + face_verts = set() + for u, v in face: + face_verts.add(u); face_verts.add(v) + is_low = bool(face_verts & pendant_verts) + classified.append((face, is_low)) + low_faces = [f for f, low in classified if low] + high_faces = [f for f, low in classified if not low] + if len(low_faces) > 1: + # Choose the one with the most pendant incidences + low_faces.sort(key=lambda f: -sum( + 1 for u, v in f + if u in pendant_verts or v in pendant_verts)) + low_face = low_faces[0] if low_faces else None + return low_face, high_faces + + +def boundary_tire_structure(H, edge_depth, low_face): + """Construct T_∂'s structural data: + - cycle_edges: depth-1 edges in low_face's boundary walk + (with multiplicity = how many times traversed + in the walk, but we use each edge once for + cycle_eids; the walk structure is implicit). + - out_pendants: pendant edges (depth 0) at boundary vertices. + - in_pendants: depth-2 edges incident to boundary vertices, + on the deeper side. + - edges_at_v: per-vertex incident edge IDs (for proper-coloring + constraint). + - all_edges: list of full edge tuples in T_∂'s order. + """ + if low_face is None: + return None + # Cycle edges: unique edges in low_face's boundary walk + cycle_e_set = set() + cycle_edges = [] + for u, v in low_face: + e = tuple(sorted((u, v))) + if e not in cycle_e_set: + cycle_e_set.add(e) + cycle_edges.append(e) + boundary_verts = set() + for a, b in cycle_edges: + boundary_verts.add(a); boundary_verts.add(b) + # Pendants at boundary vertices + out_pendants = [] # depth-0 edges incident + in_pendants = [] # depth-2 edges incident + for v in boundary_verts: + for nb in H.neighbors(v): + e = tuple(sorted((v, nb))) + if e in cycle_e_set: + continue + de = edge_depth.get(e) + if de == 0: + out_pendants.append(e) + elif de == 2: + in_pendants.append(e) + # Dedup + out_pendants = list(set(out_pendants)) + in_pendants = list(set(in_pendants)) + # Construct edge ID list + all_edges = cycle_edges + in_pendants + out_pendants + edge_id = {e: i for i, e in enumerate(all_edges)} + edges_at_v = defaultdict(list) + for a, b in cycle_edges: + edges_at_v[a].append(edge_id[(a, b)]) + edges_at_v[b].append(edge_id[(a, b)]) + for e in in_pendants + out_pendants: + for v in e: + if v in boundary_verts: + edges_at_v[v].append(edge_id[e]) + return { + 'all_edges': all_edges, + 'edge_id': edge_id, + 'edges_at_v': dict(edges_at_v), + 'cycle_eids': [edge_id[e] for e in cycle_edges], + 'in_eids': [edge_id[e] for e in in_pendants], + 'out_eids': [edge_id[e] for e in out_pendants], + 'low_face': low_face, + } + + +def enumerate_proper(struct, max_edges=18): + """Enumerate proper 3-edge-colorings of struct's edges, + respecting per-vertex distinct-color constraint.""" + n_e = len(struct['all_edges']) + if n_e > max_edges: + return None + out = [] + for assign in itertools.product([0, 1, 2], repeat=n_e): + ok = True + for v, eids in struct['edges_at_v'].items(): + cs = [assign[i] for i in eids] + if len(set(cs)) != len(cs): + ok = False; break + if ok: + out.append(assign) + return out + + +def proper_3_edge_colorings_full(G, max_n=60): + """Brute-force backtracking enum of all proper 3-edge-colorings.""" + edges = [tuple(sorted(e[:2])) for e in G.edges()] + n = len(edges) + if n > max_n: + return None + eav = defaultdict(list) + for i, (u, v) in enumerate(edges): + eav[u].append(i) + eav[v].append(i) + colors = [-1] * n + results = [] + def bt(i): + if i == n: + results.append(tuple(colors)) + return + u, v = edges[i] + used = set() + for j in eav[u]: + if colors[j] != -1: used.add(colors[j]) + for j in eav[v]: + if colors[j] != -1: used.add(colors[j]) + for c in range(3): + if c in used: continue + colors[i] = c + bt(i + 1) + colors[i] = -1 + bt(0) + return [{edges[i]: c for i, c in enumerate(r)} for r in results] + + +def project_to_pendants(colorings, pendant_edges): + """Project G'_i colorings to a fixed list of pendant edges. + Returns a set of color tuples (in the order of pendant_edges).""" + out = set() + for c in colorings: + try: + out.add(tuple(c[tuple(sorted(e[:2]))] for e in pendant_edges)) + except KeyError: + continue + return out + + +def s3_orbit(t): + return {tuple(p[c] for c in t) + for p in itertools.permutations([0, 1, 2])} + + +def has_full_s3(s): + if not s: return False + for t in s: + orb = s3_orbit(t) + if len(orb) == 6 and orb <= s: + return True + return False + + +def chain_dp_with_boundary(H, edge_depth): + """Compute the chain DP including the boundary cut tire T_∂. + + Algorithm: + 1. Build high-side forest as before; compute per-tire A(T). + 2. Build T_∂ structure from low-side H_1 face. + 3. Compute A(T_∂) = proper 3-edge-colorings of T_∂. + 4. Restrict A(T_∂) by edge-sharing with adjacent high-side + tires (depth-1 boundary edges, depth-2 in-pendants). + 5. Project to OUT pendants = R_i^DP. + """ + if not edge_depth: + return set(), {} + faces_by_depth, parent_of, _ = build_tree(H, edge_depth) + # Build per-tire structures (joint coloring DP) + from chain_dp_joint import tire_edges, enumerate_proper as ep, chain_dp_joint + A_high, tire_struct, _ = chain_dp_joint( + faces_by_depth, parent_of, H, edge_depth) + + # Boundary tire + low_face, high_faces = classify_h1_faces(H, edge_depth) + bdy_struct = boundary_tire_structure(H, edge_depth, low_face) + if bdy_struct is None: + return set(), {'reason': 'no low_face'} + + bdy_cs = enumerate_proper(bdy_struct, max_edges=18) + if bdy_cs is None: + return set(), {'reason': 'bdy too big', + 'n_edges': len(bdy_struct['all_edges'])} + + # Restrict A(T_∂) by sharing with high-side tires. + # For each adjacent high-side tire that shares any T_∂ edges, + # require T_∂ coloring to be compatible with some A(tire) coloring + # on shared edges. + bdy_eid = bdy_struct['edge_id'] + bdy_edges_set = set(bdy_struct['all_edges']) + kid_shared = [] + for node, struct in tire_struct.items(): + if A_high.get(node) is None or not A_high.get(node): + continue + node_edges = set(struct['all_edges']) + shared = bdy_edges_set & node_edges + if not shared: + continue + shared_pairs = [] # (bdy_eid, node_eid) + for e in shared: + shared_pairs.append((bdy_eid[e], struct['edge_id'][e])) + # Compute set of shared-coloring keys this node accepts + accepted = set() + for assign in A_high[node]: + key = tuple(assign[neid] for (_, neid) in shared_pairs) + accepted.add(key) + kid_shared.append((shared_pairs, accepted, node)) + # Filter bdy_cs + survivors = [] + for assign in bdy_cs: + ok = True + for shared_pairs, accepted, _ in kid_shared: + key = tuple(assign[beid] for (beid, _) in shared_pairs) + if key not in accepted: + ok = False; break + if ok: + survivors.append(assign) + # Project to OUT pendants + out_eids = bdy_struct['out_eids'] + R = set() + for assign in survivors: + R.add(tuple(assign[i] for i in out_eids)) + return R, { + 'bdy_n_edges': len(bdy_struct['all_edges']), + 'bdy_cycle_eids': len(bdy_struct['cycle_eids']), + 'bdy_out': len(bdy_struct['out_eids']), + 'bdy_in': len(bdy_struct['in_eids']), + 'bdy_valid_pre': len(bdy_cs), + 'bdy_valid_post': len(survivors), + 'high_neighbors': len(kid_shared), + } + + +def test_one_cut(G, cut_idx, cuts, base_pos, verbose=False): + S, cut_edges = cuts[cut_idx] + S0, S1 = S, frozenset(G.vertices()) - S + if len(S0) < 3 or len(S1) < 3: + return None + if verbose: + print(f' cut #{cut_idx}: |S0|={len(S0)}, |S1|={len(S1)}', + flush=True) + results = {'cut_idx': cut_idx} + for side, S_side in [('0', S0), ('1', S1)]: + try: + H, _, ed, _, _, _ = apply_procedure( + G, S_side, cut_edges, base_pos, side, + pendant_start_id=max(G.vertices()) + 1 + + (0 if side == '0' else 500)) + except Exception as e: + results[f'side_{side}'] = {'error': str(e)} + continue + if not ed: + continue + # Ground truth on G'_i + gi_cols = proper_3_edge_colorings_full(H, max_n=50) + if gi_cols is None: + R_ground = None + else: + # Project to pendants (depth-0) + pendant_edges = [e for e, d in ed.items() if d == 0] + R_ground = project_to_pendants(gi_cols, pendant_edges) + + R_dp, meta = chain_dp_with_boundary(H, ed) + results[f'side_{side}'] = { + 'R_ground_size': len(R_ground) if R_ground is not None else None, + 'R_ground_full_s3': has_full_s3(R_ground) + if R_ground is not None else None, + 'R_dp_size': len(R_dp), + 'R_dp_full_s3': has_full_s3(R_dp), + 'match': R_ground == R_dp if R_ground is not None else None, + 'meta': meta, + } + if verbose: + r = results[f'side_{side}'] + print(f' side {side}: |R_ground|={r["R_ground_size"]}, ' + f'|R_dp|={r["R_dp_size"]}, match={r["match"]}, ' + f'meta={r["meta"]}', + flush=True) + return results + + +def main(): + print('=== Dodecahedron ===', flush=True) + G = graphs.DodecahedralGraph() + G.is_planar(set_embedding=True) + base_pos = compute_nice_layout(G) + cuts = all_six_edge_cuts(G, max_cuts=5) + for i in range(min(5, len(cuts))): + test_one_cut(G, i, cuts, base_pos, verbose=True) + + print('\n=== HM_0 ===', flush=True) + gs = parse_planar_code(HM_FILE) + cuts = all_six_edge_cuts(gs[0], max_cuts=3) + base_pos = compute_nice_layout(gs[0]) + for i in range(min(3, len(cuts))): + test_one_cut(gs[0], i, cuts, base_pos, verbose=True) + + +if __name__ == '__main__': + main() diff --git a/papers/coloring_nested_tire_graphs/notes/boundary_cut_tire.aux b/papers/coloring_nested_tire_graphs/notes/boundary_cut_tire.aux new file mode 100644 index 0000000..9a38252 --- /dev/null +++ b/papers/coloring_nested_tire_graphs/notes/boundary_cut_tire.aux @@ -0,0 +1,12 @@ +\relax +\@writefile{toc}{\contentsline {paragraph}{The coverage gap.}{1}{}\protected@file@percent } +\@writefile{toc}{\contentsline {paragraph}{Resolution.}{1}{}\protected@file@percent } +\@writefile{toc}{\contentsline {paragraph}{Setup.}{1}{}\protected@file@percent } +\@writefile{toc}{\contentsline {paragraph}{The low-side face of $H_1$.}{1}{}\protected@file@percent } +\@writefile{toc}{\contentsline {paragraph}{What $T_\partial $ looks like in special cases.}{2}{}\protected@file@percent } +\@writefile{toc}{\contentsline {paragraph}{Role in the chain DP.}{2}{}\protected@file@percent } +\@writefile{toc}{\contentsline {paragraph}{What this closes.}{3}{}\protected@file@percent } +\@writefile{toc}{\contentsline {paragraph}{What it leaves open.}{3}{}\protected@file@percent } +\@writefile{toc}{\contentsline {paragraph}{Why the chain DP can still work.}{3}{}\protected@file@percent } +\@writefile{toc}{\contentsline {paragraph}{Logical status of the extended framework.}{3}{}\protected@file@percent } +\gdef \@abspage@last{3} diff --git a/papers/coloring_nested_tire_graphs/notes/boundary_cut_tire.log b/papers/coloring_nested_tire_graphs/notes/boundary_cut_tire.log new file mode 100644 index 0000000..39f0f52 --- /dev/null +++ b/papers/coloring_nested_tire_graphs/notes/boundary_cut_tire.log @@ -0,0 +1,299 @@ +This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022) (preloaded format=pdflatex 2022.10.5) 26 MAY 2026 23:17 +entering extended mode + restricted \write18 enabled. + %&-line parsing enabled. +**boundary_cut_tire.tex +(./boundary_cut_tire.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 +) +(./boundary_cut_tire.aux) +\openout1 = `boundary_cut_tire.aux'. + +LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 17. +LaTeX Font Info: ... okay on input line 17. +LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 17. +LaTeX Font Info: ... okay on input line 17. +LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 17. +LaTeX Font Info: ... okay on input line 17. +LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 17. +LaTeX Font Info: ... okay on input line 17. +LaTeX Font Info: Checking defaults for TS1/cmr/m/n on input line 17. +LaTeX Font Info: ... okay on input line 17. +LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 17. +LaTeX Font Info: ... okay on input line 17. +LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 17. +LaTeX Font Info: ... okay on input line 17. + +(/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 18. + +(/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 18. + + +(/usr/local/texlive/2022/texmf-dist/tex/latex/amsfonts/umsb.fd +File: umsb.fd 2013/01/14 v3.01 AMS symbols B +) [1 + +{/usr/local/texlive/2022/texmf-var/fonts/map/pdftex/updmap/pdftex.map}] [2] [3] + +(./boundary_cut_tire.aux) ) +Here is how much of TeX's memory you used: + 3262 strings out of 478268 + 48530 string characters out of 5846347 + 349592 words of memory out of 5000000 + 21449 multiletter control sequences out of 15000+600000 + 481768 words of font info for 76 fonts, out of 8000000 for 9000 + 1141 hyphenation exceptions out of 8191 + 55i,5n,62p,234b,241s stack positions out of 10000i,1000n,20000p,200000b,200000s +{/usr/local/texlive/2022/texmf-dist/fonts/enc/dvips/ +cm-super/cm-super-ts1.enc} +< +/usr/local/texlive/2022/texmf-dist/fonts/type1/public/cm-super/sfrm1095.pfb> +Output written on boundary_cut_tire.pdf (3 pages, 199769 bytes). +PDF statistics: + 100 PDF objects out of 1000 (max. 8388607) + 60 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/boundary_cut_tire.pdf b/papers/coloring_nested_tire_graphs/notes/boundary_cut_tire.pdf new file mode 100644 index 0000000..541f83a Binary files /dev/null and b/papers/coloring_nested_tire_graphs/notes/boundary_cut_tire.pdf differ diff --git a/papers/coloring_nested_tire_graphs/notes/boundary_cut_tire.tex b/papers/coloring_nested_tire_graphs/notes/boundary_cut_tire.tex new file mode 100644 index 0000000..471836c --- /dev/null +++ b/papers/coloring_nested_tire_graphs/notes/boundary_cut_tire.tex @@ -0,0 +1,196 @@ +\documentclass[11pt]{article} +\usepackage{amsmath,amssymb,amsthm} +\usepackage{graphicx} +\usepackage{geometry} +\usepackage{booktabs} +\geometry{margin=1in} + +\title{The boundary cut tire $T_\partial$: closing the coverage gap} +\author{} +\date{} + +\newtheorem*{defn}{Definition} +\newtheorem*{prop}{Proposition} +\newtheorem*{lem}{Lemma} +\newtheorem*{rem}{Remark} + +\begin{document} +\maketitle + +\section*{Motivation} + +The high-side cut tire forest (\texttt{cut\_tire\_tree\_structure.tex}) +omits the low-side face of $H_1$ --- the unique face containing the +pendants of $G'_i$. This omission is essential to prove the +forest's tree structure (low-side faces span multiple parent faces +of $H_{d-1}$, violating the uniqueness step in the proof). + +\paragraph{The coverage gap.} Empirically +(\texttt{chain\_dp\_joint.py} on the dodecahedron, cut $\#0$, side +$0$): when $|S_i|$ is small, $H_1$ on side $i$ can be a +\emph{tree} (no cycles). Its unique face is forced to be low-side +(contains pendants), so the high-side forest is \emph{empty}. The +chain DP, projecting through roots that don't exist, gives +$\mathcal{R}_i = \emptyset$ --- but $G$ may still be +$3$-edge-colourable, with non-empty $\mathcal{R}_i$. + +\paragraph{Resolution.} Introduce the \emph{boundary cut tire} +$T_\partial^{(i)}$ on each side $i$, representing the low-side face +of $H_1$ together with the depth-$0$ pendants. It is not a child of +any other tire (it sits at the framework's outer boundary), but the +chain DP can use it as a special root that interfaces between the +high-side forest interior and the cut. + +\section*{Definition} + +\paragraph{Setup.} Fix a side $i$ of a $6$-edge cut of $G$. Let +$G'_i = (G[S_i] \cup \text{pendants})$ with edge depths assigned by +BFS from pendants (depth $0$). $H_d = $ the subgraph of $G'_i$ +spanned by depth-$d$ edges. + +\paragraph{The low-side face of $H_1$.} By the level-set lemma, +each face of $H_1$ is entirely low-side (interior contains only +depth-$0$ edges = pendants) or entirely high-side (interior +contains only depth-$\ge 2$ edges). There is exactly one low-side +face: the unique face whose interior contains the pendants. Call +it $f_\partial^{(i)}$. + +\begin{defn}[Boundary cut tire $T_\partial^{(i)}$] +The \emph{boundary cut tire} on side $i$ is the labelled multigraph +$T_\partial^{(i)}$ obtained from: +\begin{itemize} +\item The boundary walk of $f_\partial^{(i)}$ in $H_1$ (the edges + of $H_1$ on the boundary of the low-side face), with each + depth-$1$ edge contributing one cycle edge. +\item For each boundary vertex $v$ of $f_\partial^{(i)}$ with + $\deg_{H_1}(v) = 2$: + \begin{itemize} + \item The pendant edge at $v$ (= depth-$0$ cut edge), labelled + ``OUT.'' + \item If the third edge at $v$ has depth $2$ (= edge of $H_2$ + in an adjacent high-side $H_1$ face), one labelled + ``IN'' pendant. + \end{itemize} +\end{itemize} +\end{defn} + +\paragraph{What $T_\partial$ looks like in special cases.} +\begin{itemize} +\item \emph{Side with thick BFS:} $H_1$ has multiple faces, one + low-side ($f_\partial$) and one or more high-side. + $T_\partial$ has cycle = boundary of $f_\partial$ + OUT + pendants (= cut edges incident to $f_\partial$'s boundary) + + IN pendants (= depth-$2$ edges in adjacent high-side faces). +\item \emph{Side with thin BFS} (e.g.\ $H_1$ a tree): The unique + $H_1$ face is $f_\partial$. $T_\partial$ has cycle = + boundary walk of this single face (each $H_1$ edge contributes + \emph{two} cycle-edge traversals, since the walk goes around + each edge on both sides) + OUT pendants at $V_{\deg = 2}$. + No IN pendants (no depth-$2$ edges exist). +\end{itemize} + +\section*{The extended forest} + +The high-side cut tire forest of $G'_i$ (proven in +\texttt{cut\_tire\_tree\_structure.tex}) has roots +$T_1^{(f_\text{high})}$ for the high-side faces of $H_1$. + +\begin{defn}[Extended cut tire structure] +The \emph{extended cut tire structure} on side $i$ is the +high-side forest with $T_\partial^{(i)}$ adjoined as a +\emph{boundary node}. $T_\partial$ is not a child or parent of any +high-side cut tire in the geometric containment sense, but it +\emph{shares edges} with adjacent high-side tires: +\begin{itemize} +\item $T_\partial$ shares depth-$1$ edges with each high-side + depth-$1$ tire $T_1^{(f_\text{high})}$ whose face $f_\text{high}$ + is adjacent to $f_\partial$ (= shares a boundary edge of $H_1$). +\item $T_\partial$'s IN pendants are cycle edges of depth-$2$ + cut tires $T_2^{(f')}$ in adjacent high-side $H_1$ faces. +\end{itemize} +\end{defn} + +\paragraph{Role in the chain DP.} In the joint-projection chain DP, +the per-tire state at $T_\partial$ is a set of valid edge +$3$-colorings of $T_\partial$'s structure (cycle + OUT + IN +pendants). Composition with adjacent tires is via shared edges +(same $G'_i$ edge tuple appearing in both), exactly as for the +high-side forest. The chain DP then has $T_\partial$ as its +\emph{boundary interface}: the OUT pendants project to the cut, and +the IN pendants + cycle edges propagate constraints to/from the +high-side forest. + +\section*{Chain DP with $T_\partial$, sketched} + +\begin{enumerate} +\item Process the high-side forest bottom-up as before, producing + per-tire valid coloring sets $A(T)$. +\item Compute the valid coloring set $A(T_\partial^{(i)})$ via + enumeration of proper $3$-edge-colorings on $T_\partial$'s + structure. +\item Restrict $A(T_\partial)$ by edge-sharing with adjacent + high-side tires: + \begin{itemize} + \item For each $T_1^{(f_\text{high})}$ sharing depth-$1$ edges + with $T_\partial$: keep $T_\partial$ colorings consistent + with some $A(T_1^{(f_\text{high})})$ coloring on shared + edges. + \item For each $T_2^{(f')}$ sharing a depth-$2$ edge with + $T_\partial$'s IN pendants: keep $T_\partial$ colorings + consistent with some $A(T_2^{(f')})$ coloring on the + shared edge. + \end{itemize} +\item Project $A(T_\partial^{(i)})$ to OUT pendants $=$ + $\mathcal{R}_i$. +\end{enumerate} + +\section*{Where things stand} + +\paragraph{What this closes.} The coverage gap (no high-side cut +tires on thin sides) is resolved: $T_\partial$ always exists and +provides the interface to the cut. + +\paragraph{What it leaves open.} $T_\partial$'s ``cycle'' is the +boundary walk of $f_\partial$, which is a closed walk in $H_1$ --- +\emph{not} necessarily a simple cycle when $H_1$ is a tree (the walk +traverses each edge twice). The per-tire half (Prop 1.13) does not +directly apply to such walks. This is a special case of the +``branched cut tires'' open problem in +\texttt{chain\_half\_analysis.tex}. + +\paragraph{Why the chain DP can still work.} Even without the +per-tire half guaranteeing $|\pi(T_\partial)| \ge 6$, we can +\emph{compute} the valid coloring set for $T_\partial$ directly +(brute-force or constraint-propagated enumeration). If this set +is non-empty after edge-sharing restrictions, the chain DP yields +a non-empty $\mathcal{R}_i$. + +\paragraph{Logical status of the extended framework.} +\begin{itemize} +\item Edge-sharing chain DP $S_3$-equivariance: still holds + (uniform $S_3$ action commutes with edge constraints). +\item Tree structure: the high-side forest still forms a forest; + $T_\partial$ adjoined is no longer a tree but a connected + structure (forest + boundary node). +\item Per-tire half for $T_\partial$: open, special case of + branched tires. +\item Non-emptiness of $\mathcal{R}_i$ via the DP: open; this is + the \emph{primary} chain-half claim, now testable with + $T_\partial$ included. +\end{itemize} + +\section*{Empirical next step} + +Re-run \texttt{chain\_dp\_joint.py} with $T_\partial$ added. +Compare with ground truth (brute-force $G'_i$ $3$-edge colorings). + +For the dodecahedron cut $\#0$ side $0$: +\begin{itemize} +\item Ground truth: $|\mathcal{R}_\text{ground}| = 36$. +\item Old high-side-only DP: $|\mathcal{R}_0| = 0$ (no high-side + tires). +\item New $T_\partial$-extended DP: should match ground truth (or + reveal another gap to investigate). +\end{itemize} + +\end{document}