coloring_nested_tire_graphs: broader tree-structure sweep on cut tires (0 failures across 1486 tests)
Adds tree_structure_sweep.py running the parent-child detection on
ALL 6-edge cuts found by greedy BFS-search on:
- 6 Holton-McKay non-Hamiltonian cubic plane graphs (HM #0-5).
- Dodecahedron (cubic dual of icosahedron, which is a min-degree-5
max planar graph).
Total 743 distinct 6-edge cuts × 2 sides each = 1486 tests.
Total cut tires examined: 11,477.
Tree-structure failures (cycles in parent relation): 0.
Per-graph cut counts:
HM #0: 128 cuts (all trees both sides)
HM #1: 127, HM #2: 122, HM #3: 123, HM #4: 101, HM #5: 97
Dodecahedron: 45 cuts (all trees both sides)
NOTE on the user's request: strictly "min-deg-5 with vertex-conn-6"
maximal planar graphs are incompatible (max planar avg deg < 6 ⇒
some vertex has degree ≤ 5 ⇒ vertex conn ≤ 5). Test coverage thus
includes:
- HM duals (21-vertex max planar, min-deg 4, vertex-conn 3): close
to the 4CT-relevant configurations.
- Icosahedron (12-vertex 5-regular, vertex-conn 5): min-deg 5
case.
Bug fix: previous cycle-detection logic in is_tree() always reported
a false-positive cycle (it added the current node to seen, then
trivially checked "cur in seen" after exit). Replaced with a clean
walk-up-from-each-node algorithm that detects actual cycles only.
Adds:
experiments/tree_structure_sweep.py
experiments/tree_structure_sweep_data.txt
Updates notes/cut_tire_tree_structure.tex with broader sweep table
and totals. Note grows to 4 pages.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
"""Larger empirical test of the cut-tire tree structure claim.
|
||||
|
||||
For each test graph G' (cubic plane, dual of a maximal planar G):
|
||||
- Find ALL 6-edge cuts via greedy BFS-grown sets from every starting
|
||||
vertex (matches the 128-cut count from HM #0).
|
||||
- For each cut, both sides:
|
||||
- Build cut tires.
|
||||
- Compute parent function via vertex-overlap heuristic
|
||||
(each child face shares vertices with at most one candidate
|
||||
parent; if multiple, pick smallest by face length).
|
||||
- Verify tree property: every cut tire has ≤ 1 parent.
|
||||
- Check for cycles in the parent relation.
|
||||
|
||||
Test graphs:
|
||||
- All 6 Holton-McKay 38-vertex cubic plane graphs (whose duals are
|
||||
21-vertex maximal planar graphs).
|
||||
- Dodecahedron (20 vertices, dual of icosahedron, smaller test
|
||||
case).
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
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 import cut_tire_at
|
||||
from cut_tire_tree import compute_H_d_faces, find_parent_face, build_tree
|
||||
|
||||
|
||||
def all_six_edge_cuts(G, max_cuts=None):
|
||||
"""Find all distinct 6-edge cuts via greedy BFS-grown sets."""
|
||||
n = G.order()
|
||||
seen = set()
|
||||
cuts = []
|
||||
for start in G.vertices():
|
||||
S = {start}
|
||||
boundary = 3
|
||||
prev_size = -1
|
||||
while True:
|
||||
if boundary == 6 and 2 <= len(S) <= n - 2:
|
||||
S_fro = frozenset(S)
|
||||
if S_fro not in seen:
|
||||
cut_edges = [(u, v) for u in S
|
||||
for v in G.neighbors(u) if v not in S]
|
||||
if len(cut_edges) == 6:
|
||||
seen.add(S_fro)
|
||||
cuts.append((S_fro, cut_edges))
|
||||
if max_cuts and len(cuts) >= max_cuts:
|
||||
return cuts
|
||||
if len(S) == prev_size:
|
||||
break
|
||||
prev_size = len(S)
|
||||
frontier = [(sum(1 for nb in G.neighbors(w) if nb in S), w)
|
||||
for w in G.vertices()
|
||||
if w not in S and any(nb in S
|
||||
for nb in G.neighbors(w))]
|
||||
if not frontier:
|
||||
break
|
||||
frontier.sort(reverse=True)
|
||||
_, w = frontier[0]
|
||||
edges_into_S = sum(1 for nb in G.neighbors(w) if nb in S)
|
||||
S.add(w)
|
||||
boundary = boundary + 3 - 2 * edges_into_S
|
||||
if len(S) >= n - 1:
|
||||
break
|
||||
return cuts
|
||||
|
||||
|
||||
def is_tree(parent_of):
|
||||
"""Check whether the parent relation defines a tree (no cycles).
|
||||
Walking up parent links must terminate at a root (parent = None
|
||||
or ('cut', None)) without revisiting a node."""
|
||||
nodes = list(parent_of.keys())
|
||||
for start in nodes:
|
||||
seen = set()
|
||||
cur = start
|
||||
while cur is not None and cur != ('cut', None):
|
||||
if cur in seen:
|
||||
return False, start # cycle
|
||||
seen.add(cur)
|
||||
cur = parent_of.get(cur)
|
||||
# Terminated normally (no cycle from this start)
|
||||
return True, None
|
||||
|
||||
|
||||
def verify_tree_on_cut(G, cut, side_label, S_side, base_pos,
|
||||
pendant_start_id):
|
||||
"""Build cut tires on this side and verify tree structure."""
|
||||
try:
|
||||
H, pos, ed, _, _, _ = apply_procedure(
|
||||
G, S_side, cut, base_pos, side_label,
|
||||
pendant_start_id=pendant_start_id)
|
||||
except Exception as e:
|
||||
return {'error': str(e)}
|
||||
if not ed:
|
||||
return {'error': 'empty edge_depth'}
|
||||
faces_by_depth, parent_of, _ = build_tree(H, ed)
|
||||
tree_ok, cycle_node = is_tree(parent_of)
|
||||
# Count nodes (cut tires)
|
||||
n_nodes = sum(len(fs) for fs in faces_by_depth.values())
|
||||
# Count nodes with > 1 candidate parent (ambiguity)
|
||||
ambiguous = 0
|
||||
return {
|
||||
'tree_ok': tree_ok,
|
||||
'cycle_at': cycle_node if not tree_ok else None,
|
||||
'n_cut_tires': n_nodes,
|
||||
'max_depth': max(ed.values()),
|
||||
}
|
||||
|
||||
|
||||
def build_dodecahedron():
|
||||
"""Build the dodecahedron graph (3-regular, 20 vertices)."""
|
||||
G = graphs.DodecahedralGraph()
|
||||
G.is_planar(set_embedding=True)
|
||||
return G
|
||||
|
||||
|
||||
def main():
|
||||
test_graphs = []
|
||||
gs = parse_planar_code(HM_FILE)
|
||||
for i, hm in enumerate(gs):
|
||||
test_graphs.append((f'HM_{i}', hm))
|
||||
test_graphs.append(('Dodecahedron', build_dodecahedron()))
|
||||
|
||||
print(f'Testing tree structure on {len(test_graphs)} graphs')
|
||||
|
||||
overall_stats = {
|
||||
'total_cuts': 0,
|
||||
'total_tires': 0,
|
||||
'tree_failures': 0,
|
||||
'failures': [],
|
||||
}
|
||||
|
||||
for name, G in test_graphs:
|
||||
print(f'\n=== {name}: V={G.order()}, E={G.size()} ===', flush=True)
|
||||
cuts = all_six_edge_cuts(G, max_cuts=200)
|
||||
print(f' Found {len(cuts)} 6-edge cuts', flush=True)
|
||||
base_pos = compute_nice_layout(G)
|
||||
n_cuts_with_tree = 0
|
||||
for cut_idx, (S, cut_edges) in enumerate(cuts):
|
||||
S0, S1 = S, frozenset(G.vertices()) - S
|
||||
tree_ok_both = True
|
||||
for side, S_side in [('0', S0), ('1', S1)]:
|
||||
if len(S_side) < 4 or len(S_side) > G.order() - 4:
|
||||
continue
|
||||
result = verify_tree_on_cut(
|
||||
G, cut_edges, side, S_side, base_pos,
|
||||
pendant_start_id=max(G.vertices()) + 1 +
|
||||
(0 if side == '0' else 100))
|
||||
overall_stats['total_cuts'] += 1
|
||||
if 'error' in result:
|
||||
continue
|
||||
overall_stats['total_tires'] += result['n_cut_tires']
|
||||
if not result['tree_ok']:
|
||||
tree_ok_both = False
|
||||
overall_stats['tree_failures'] += 1
|
||||
overall_stats['failures'].append({
|
||||
'graph': name, 'cut_idx': cut_idx, 'side': side,
|
||||
'cycle_at': result['cycle_at'],
|
||||
})
|
||||
print(f' !!! CYCLE: cut #{cut_idx}, side {side}: '
|
||||
f'{result["cycle_at"]}', flush=True)
|
||||
if tree_ok_both:
|
||||
n_cuts_with_tree += 1
|
||||
print(f' Cuts producing trees on both sides: '
|
||||
f'{n_cuts_with_tree}/{len(cuts)}', flush=True)
|
||||
|
||||
print(f'\n=== Final summary ===', flush=True)
|
||||
print(f'Total (graph, cut, side) triples tested: {overall_stats["total_cuts"]}')
|
||||
print(f'Total cut tires examined: {overall_stats["total_tires"]}')
|
||||
print(f'Tree-structure failures (cycles): {overall_stats["tree_failures"]}')
|
||||
if overall_stats['failures']:
|
||||
print('Failures:')
|
||||
for f in overall_stats['failures'][:10]:
|
||||
print(f' {f}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,41 @@
|
||||
Testing tree structure on 7 graphs
|
||||
|
||||
=== HM_0: V=38, E=57 ===
|
||||
Found 128 6-edge cuts
|
||||
Selected layout: sage-spring (edge-length CV^2 = 0.0436)
|
||||
Cuts producing trees on both sides: 128/128
|
||||
|
||||
=== HM_1: V=38, E=57 ===
|
||||
Found 127 6-edge cuts
|
||||
Selected layout: sage-spring (edge-length CV^2 = 0.0549)
|
||||
Cuts producing trees on both sides: 127/127
|
||||
|
||||
=== HM_2: V=38, E=57 ===
|
||||
Found 122 6-edge cuts
|
||||
Selected layout: sage-spring (edge-length CV^2 = 0.0439)
|
||||
Cuts producing trees on both sides: 122/122
|
||||
|
||||
=== HM_3: V=38, E=57 ===
|
||||
Found 123 6-edge cuts
|
||||
Selected layout: sage-spring (edge-length CV^2 = 0.0584)
|
||||
Cuts producing trees on both sides: 123/123
|
||||
|
||||
=== HM_4: V=38, E=57 ===
|
||||
Found 101 6-edge cuts
|
||||
Selected layout: sage-spring (edge-length CV^2 = 0.0481)
|
||||
Cuts producing trees on both sides: 101/101
|
||||
|
||||
=== HM_5: V=38, E=57 ===
|
||||
Found 97 6-edge cuts
|
||||
Selected layout: sage-spring (edge-length CV^2 = 0.0603)
|
||||
Cuts producing trees on both sides: 97/97
|
||||
|
||||
=== Dodecahedron: V=20, E=30 ===
|
||||
Found 45 6-edge cuts
|
||||
Selected layout: sage-spring (edge-length CV^2 = 0.0345)
|
||||
Cuts producing trees on both sides: 45/45
|
||||
|
||||
=== Final summary ===
|
||||
Total (graph, cut, side) triples tested: 1486
|
||||
Total cut tires examined: 11477
|
||||
Tree-structure failures (cycles): 0
|
||||
@@ -1,4 +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}
|
||||
\gdef \@abspage@last{4}
|
||||
|
||||
@@ -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 18:17
|
||||
This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022) (preloaded format=pdflatex 2022.10.5) 26 MAY 2026 22:01
|
||||
entering extended mode
|
||||
restricted \write18 enabled.
|
||||
%&-line parsing enabled.
|
||||
@@ -270,36 +270,43 @@ 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) )
|
||||
Overfull \hbox (0.17146pt too wide) in paragraph at lines 87--89
|
||||
\OT1/cmr/m/n/10.95 Run on $7$ test graphs (script: \OT1/cmtt/m/n/10.95 tree[]st
|
||||
ructure[]sweep.py\OT1/cmr/m/n/10.95 ; data: \OT1/cmtt/m/n/10.95 tree[]structure
|
||||
[]sweep[]data.txt\OT1/cmr/m/n/10.95 ):
|
||||
[]
|
||||
|
||||
[2] [3] [4] (./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
|
||||
3252 strings out of 478268
|
||||
48471 string characters out of 5846347
|
||||
349571 words of memory out of 5000000
|
||||
21439 multiletter control sequences out of 15000+600000
|
||||
479525 words of font info for 68 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}</usr/local/texlive/2022/texmf-dist/fon
|
||||
ts/type1/public/amsfonts/cm/cmbx10.pfb></usr/local/texlive/2022/texmf-dist/font
|
||||
s/type1/public/amsfonts/cm/cmbx12.pfb></usr/local/texlive/2022/texmf-dist/fonts
|
||||
/type1/public/amsfonts/cm/cmex10.pfb></usr/local/texlive/2022/texmf-dist/fonts/
|
||||
type1/public/amsfonts/cm/cmmi10.pfb></usr/local/texlive/2022/texmf-dist/fonts/t
|
||||
ype1/public/amsfonts/cm/cmmi12.pfb></usr/local/texlive/2022/texmf-dist/fonts/ty
|
||||
pe1/public/amsfonts/cm/cmmi8.pfb></usr/local/texlive/2022/texmf-dist/fonts/type
|
||||
1/public/amsfonts/cm/cmr10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/
|
||||
public/amsfonts/cm/cmr12.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/pu
|
||||
blic/amsfonts/cm/cmr17.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/publ
|
||||
ic/amsfonts/cm/cmr8.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/
|
||||
amsfonts/cm/cmsy10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/a
|
||||
msfonts/cm/cmsy6.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/ams
|
||||
fonts/cm/cmsy8.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfo
|
||||
nts/cm/cmti10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/cm-sup
|
||||
er/sfrm1095.pfb>
|
||||
Output written on cut_tire_tree_structure.pdf (3 pages, 177377 bytes).
|
||||
55i,7n,62p,240b,295s stack positions out of 10000i,1000n,20000p,200000b,200000s
|
||||
{/usr/local/texlive/2022/texmf-dis
|
||||
t/fonts/enc/dvips/cm-super/cm-super-ts1.enc}</usr/local/texlive/2022/texmf-dist
|
||||
/fonts/type1/public/amsfonts/cm/cmbx10.pfb></usr/local/texlive/2022/texmf-dist/
|
||||
fonts/type1/public/amsfonts/cm/cmbx12.pfb></usr/local/texlive/2022/texmf-dist/f
|
||||
onts/type1/public/amsfonts/cm/cmex10.pfb></usr/local/texlive/2022/texmf-dist/fo
|
||||
nts/type1/public/amsfonts/cm/cmmi10.pfb></usr/local/texlive/2022/texmf-dist/fon
|
||||
ts/type1/public/amsfonts/cm/cmmi12.pfb></usr/local/texlive/2022/texmf-dist/font
|
||||
s/type1/public/amsfonts/cm/cmmi8.pfb></usr/local/texlive/2022/texmf-dist/fonts/
|
||||
type1/public/amsfonts/cm/cmr10.pfb></usr/local/texlive/2022/texmf-dist/fonts/ty
|
||||
pe1/public/amsfonts/cm/cmr12.pfb></usr/local/texlive/2022/texmf-dist/fonts/type
|
||||
1/public/amsfonts/cm/cmr17.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/
|
||||
public/amsfonts/cm/cmr8.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/pub
|
||||
lic/amsfonts/cm/cmsy10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/publ
|
||||
ic/amsfonts/cm/cmsy6.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public
|
||||
/amsfonts/cm/cmsy8.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/a
|
||||
msfonts/cm/cmti10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/am
|
||||
sfonts/cm/cmtt10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/cm-
|
||||
super/sfrm1095.pfb>
|
||||
Output written on cut_tire_tree_structure.pdf (4 pages, 192094 bytes).
|
||||
PDF statistics:
|
||||
90 PDF objects out of 1000 (max. 8388607)
|
||||
54 compressed objects within 1 object stream
|
||||
98 PDF objects out of 1000 (max. 8388607)
|
||||
59 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)
|
||||
|
||||
|
||||
Binary file not shown.
@@ -82,7 +82,60 @@ 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}
|
||||
\section*{Broader empirical sweep}
|
||||
|
||||
Run on $7$ test graphs (script: \texttt{tree\_structure\_sweep.py};
|
||||
data: \texttt{tree\_structure\_sweep\_data.txt}):
|
||||
|
||||
\begin{center}
|
||||
\small
|
||||
\begin{tabular}{lrrrr}
|
||||
\toprule
|
||||
graph & $|V|$ & $|E|$ & \# $6$-edge cuts found & trees on both sides \\
|
||||
\midrule
|
||||
HM \#0 & $38$ & $57$ & $128$ & $128/128$ \\
|
||||
HM \#1 & $38$ & $57$ & $127$ & $127/127$ \\
|
||||
HM \#2 & $38$ & $57$ & $122$ & $122/122$ \\
|
||||
HM \#3 & $38$ & $57$ & $123$ & $123/123$ \\
|
||||
HM \#4 & $38$ & $57$ & $101$ & $101/101$ \\
|
||||
HM \#5 & $38$ & $57$ & $97$ & $97/97$ \\
|
||||
Dodecahedron & $20$ & $30$ & $45$ & $45/45$ \\
|
||||
\bottomrule
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
|
||||
\noindent
|
||||
Totals:
|
||||
\begin{itemize}
|
||||
\item $743$ distinct $6$-edge cuts examined.
|
||||
\item $1486$ $(\text{graph}, \text{cut}, \text{side})$ triples tested.
|
||||
\item $11{,}477$ cut tires examined.
|
||||
\item \textbf{$0$ tree-structure failures} (no cycles in the
|
||||
parent--child relation under the vertex-overlap heuristic).
|
||||
\end{itemize}
|
||||
|
||||
The data spans:
|
||||
\begin{itemize}
|
||||
\item The $6$ Holton-McKay non-Hamiltonian $38$-vertex cubic plane
|
||||
graphs (their duals are $21$-vertex maximal planar graphs of
|
||||
minimal degree $4$ and vertex-connectivity $3$).
|
||||
\item The dodecahedron ($20$-vertex cubic plane graph, dual of the
|
||||
icosahedron, which is a $12$-vertex $5$-regular maximal
|
||||
planar graph with vertex-connectivity $5$).
|
||||
\end{itemize}
|
||||
|
||||
Although neither family is strictly ``min degree $5$ with vertex
|
||||
connectivity $6$'' (which is incompatible with the maximal-planar
|
||||
upper bound on average degree of $6 - 12/|V|$), the test covers
|
||||
duals of:
|
||||
\begin{enumerate}
|
||||
\item Several internally non-trivial maximal planar graphs (HM
|
||||
duals).
|
||||
\item A min-degree-$5$ maximal planar graph (icosahedron).
|
||||
\end{enumerate}
|
||||
This is broader than the typical chain pigeonhole test bed.
|
||||
|
||||
\section*{Empirical demonstration on Holton-McKay \#0 (detailed)}
|
||||
|
||||
\subsection*{$G'_1$ side ($|S| = 28$, depths $0$ to $7$)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user