coloring_nested_tire_graphs: joint-projection chain DP + tree-H_d coverage gap
NEW: chain_dp_joint.py — chain DP tracking full per-tire colorings, edge-tuple-based parent/child sharing, and ground-truth comparison against brute-force G' edge-coloring enumeration. KEY EMPIRICAL FINDING (4th issue in chain_half_analysis): When H_d is a tree (no internal cycles), the high-side cut tire forest is EMPTY. The single H_d face is forced (by the level-set lemma) to be entirely low-side or high-side; for a tree containing the pendants, it's low-side. Hence high-side forest has 0 tires. This happens at dodecahedron cut #0 side 0 (|S_0|=4): - depths {0: 2, 1: 3}, |H|=6, |E(H)|=5 - H_1 is a tree, 1 face of length 6 (= low-side) - No high-side cut tires - DP gives R_dp=0, but ground truth R=36 DP correctly produces non-empty output on side 1 (where H_1 has 2 faces, one high-side), but the high-side framework's coverage is incomplete for thin (small |S_i|) cuts. This is a STRUCTURAL gap, not a code bug. The path forward suggested in chain_half_analysis.tex: introduce a "boundary cut tire" T_0 representing the low-side face + its pendants, so the chain DP runs from leaves through T_0 to the cut. Compounding with prior gaps: (1) cut tires aren't always spoke-only (branched H_d faces) (2) OUT-only projection loses S_3 orbit (3) heuristic parent-finding (vertex overlap) (4) tree H_d → empty high-side forest (this commit) Net: the loose conjecture's chain half is genuinely open and requires framework extension before the DP can be tested cleanly. S_3 equivariance and high-side forest structure are the proven pieces. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,375 @@
|
||||
"""Chain DP with JOINT projection tracking + rigorous edge-based
|
||||
parent verification + ground-truth comparison.
|
||||
|
||||
Key fixes vs. chain_dp_general.py:
|
||||
|
||||
(1) DP state per tire = SET of full proper edge 3-colorings of the
|
||||
tire (cycle + pendants), indexed by edge id within the tire.
|
||||
No projection to spokes; the full coloring is the state.
|
||||
|
||||
(2) Composition between parent T_p and child T_c is via SHARED
|
||||
EDGES (= full G'_i edge tuples appearing in both tires).
|
||||
Parent coloring c_p is compatible with child coloring c_c iff
|
||||
they agree on every shared edge. No need to figure out which
|
||||
in-spoke maps to which cycle edge — equality of full edge
|
||||
tuples does the work.
|
||||
|
||||
(3) Parent-finding sanity: after build_tree's heuristic, verify
|
||||
each (child, parent) pair shares at least one edge. If not,
|
||||
flag as bug.
|
||||
|
||||
(4) Ground truth: compute ALL proper 3-edge-colorings of G'_i via
|
||||
backtracking with constraint propagation. Project to cut
|
||||
edges. Compare R_i^DP with R_i^direct. They should match.
|
||||
|
||||
The empirical test: for 3-edge-colorable G (dodecahedron, HM #0
|
||||
are all 3-edge-colorable by Vizing/Tait), R_0 ∩ R_1 should be
|
||||
non-empty (= projection of a full G coloring to cut).
|
||||
"""
|
||||
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
|
||||
from tree_structure_sweep import all_six_edge_cuts
|
||||
|
||||
|
||||
def tire_edges(H, edge_depth, d, face):
|
||||
"""Return ordered list of edges in cut tire T_d^{(face)}.
|
||||
Cycle edges (depth d) + pendants (depth d-1 OUT and d+1 IN).
|
||||
Each edge is a sorted tuple of vertices.
|
||||
Returns (edges_in_order, vertex_to_edge_ids, in_pendant_ids,
|
||||
out_pendant_ids, cycle_edge_ids)."""
|
||||
# Cycle edges (dedup)
|
||||
cycle_e_set = set()
|
||||
cycle_edges = []
|
||||
for u, v in face:
|
||||
e = tuple(sorted((u, v)))
|
||||
if e not in cycle_e_set:
|
||||
cycle_e_set.add(e)
|
||||
cycle_edges.append(e)
|
||||
# Vertices on cycle
|
||||
verts = set()
|
||||
for u, v in cycle_edges:
|
||||
verts.add(u); verts.add(v)
|
||||
# Pendants
|
||||
pendants_in, pendants_out = [], []
|
||||
for v in 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 == d + 1:
|
||||
pendants_in.append((v, e))
|
||||
elif de == d - 1:
|
||||
pendants_out.append((v, e))
|
||||
# Edge list: cycle then in pendants then out pendants
|
||||
all_edges = cycle_edges + [e for (_, e) in pendants_in] + \
|
||||
[e for (_, e) in pendants_out]
|
||||
edge_id = {e: i for i, e in enumerate(all_edges)}
|
||||
# Per vertex, edges at v
|
||||
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 (v, e) in pendants_in:
|
||||
edges_at_v[v].append(edge_id[e])
|
||||
for (v, e) in pendants_out:
|
||||
edges_at_v[v].append(edge_id[e])
|
||||
cycle_eids = [edge_id[e] for e in cycle_edges]
|
||||
in_eids = [edge_id[e] for (_, e) in pendants_in]
|
||||
out_eids = [edge_id[e] for (_, e) in pendants_out]
|
||||
return {
|
||||
'all_edges': all_edges,
|
||||
'edge_id': edge_id,
|
||||
'edges_at_v': dict(edges_at_v),
|
||||
'cycle_eids': cycle_eids,
|
||||
'in_eids': in_eids,
|
||||
'out_eids': out_eids,
|
||||
}
|
||||
|
||||
|
||||
def enumerate_proper(struct):
|
||||
"""Enumerate proper 3-edge-colorings of the tire as tuples of
|
||||
colors (length = n_edges). Return None if too big."""
|
||||
n_e = len(struct['all_edges'])
|
||||
if n_e > 14:
|
||||
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 chain_dp_joint(faces_by_depth, parent_of, H, edge_depth):
|
||||
"""Chain DP with full per-tire colorings tracked.
|
||||
Returns:
|
||||
A: node -> list of full colorings (tuples)
|
||||
tire_struct: node -> structure dict
|
||||
issues: list of warnings
|
||||
"""
|
||||
tire_struct = {}
|
||||
for d, faces in faces_by_depth.items():
|
||||
for fi, face in enumerate(faces):
|
||||
tire_struct[(d, fi)] = tire_edges(H, edge_depth, d, face)
|
||||
|
||||
children = defaultdict(list)
|
||||
for node, p in parent_of.items():
|
||||
if p is not None and p != ('cut', None):
|
||||
children[p].append(node)
|
||||
|
||||
issues = []
|
||||
# Verify parent-child have shared edges
|
||||
for ch_node, p_node in parent_of.items():
|
||||
if p_node is None or p_node == ('cut', None):
|
||||
continue
|
||||
ch_edges = set(tire_struct[ch_node]['all_edges'])
|
||||
p_edges = set(tire_struct[p_node]['all_edges'])
|
||||
shared = ch_edges & p_edges
|
||||
if not shared:
|
||||
issues.append({
|
||||
'type': 'no_shared',
|
||||
'child': ch_node, 'parent': p_node,
|
||||
'n_ch_edges': len(ch_edges),
|
||||
'n_p_edges': len(p_edges),
|
||||
})
|
||||
|
||||
max_d = max(d for (d, _) in tire_struct)
|
||||
A = {}
|
||||
for d in range(max_d, 0, -1):
|
||||
for node in [n for n in tire_struct if n[0] == d]:
|
||||
cs = enumerate_proper(tire_struct[node])
|
||||
if cs is None:
|
||||
A[node] = None
|
||||
continue
|
||||
kids = children.get(node, [])
|
||||
if not kids:
|
||||
A[node] = cs
|
||||
continue
|
||||
# For each kid, build {shared_color_tuple: count} so
|
||||
# parent can check existence quickly
|
||||
kid_shared = []
|
||||
for ch in kids:
|
||||
if A.get(ch) is None:
|
||||
kid_shared.append(None)
|
||||
continue
|
||||
ch_struct = tire_struct[ch]
|
||||
# Shared edges between parent and child
|
||||
p_edges = tire_struct[node]['all_edges']
|
||||
p_eid = tire_struct[node]['edge_id']
|
||||
ch_eid = ch_struct['edge_id']
|
||||
shared_pairs = [] # (p_eid, ch_eid)
|
||||
for e in p_edges:
|
||||
if e in ch_eid:
|
||||
shared_pairs.append((p_eid[e], ch_eid[e]))
|
||||
if not shared_pairs:
|
||||
kid_shared.append(None)
|
||||
continue
|
||||
# Build set of child shared-tuples (just keys we care)
|
||||
ch_shared_set = set()
|
||||
for ch_assign in A[ch]:
|
||||
key = tuple(ch_assign[c_eid] for (_, c_eid)
|
||||
in shared_pairs)
|
||||
ch_shared_set.add(key)
|
||||
kid_shared.append((shared_pairs, ch_shared_set))
|
||||
# Filter parent colorings by all kid constraints
|
||||
achievable = []
|
||||
for assign in cs:
|
||||
ok = True
|
||||
for ks in kid_shared:
|
||||
if ks is None:
|
||||
continue
|
||||
shared_pairs, ch_shared_set = ks
|
||||
key = tuple(assign[p_eid] for (p_eid, _) in shared_pairs)
|
||||
if key not in ch_shared_set:
|
||||
ok = False; break
|
||||
if ok:
|
||||
achievable.append(assign)
|
||||
A[node] = achievable
|
||||
return A, tire_struct, issues
|
||||
|
||||
|
||||
def proper_3_edge_colorings_full(G, max_n=100):
|
||||
"""Brute-force enumerate all proper 3-edge-colorings of G via
|
||||
backtracking + constraint propagation. Returns list of dicts
|
||||
{edge_tuple: color}. Only feasible for small G."""
|
||||
edges = [tuple(sorted(e[:2])) for e in G.edges()]
|
||||
n = len(edges)
|
||||
if n > max_n:
|
||||
return None
|
||||
edge_idx = {e: i for i, e in enumerate(edges)}
|
||||
# Edges incident to each vertex
|
||||
eav = defaultdict(list)
|
||||
for i, (u, v) in enumerate(edges):
|
||||
eav[u].append(i)
|
||||
eav[v].append(i)
|
||||
# Backtracking
|
||||
colors = [-1] * n
|
||||
results = []
|
||||
|
||||
def backtrack(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
|
||||
backtrack(i + 1)
|
||||
colors[i] = -1
|
||||
|
||||
backtrack(0)
|
||||
return [{edges[i]: c for i, c in enumerate(r)} for r in results]
|
||||
|
||||
|
||||
def project_to_cut(colorings, cut_edges):
|
||||
"""Project a list of full colorings to the given cut edges.
|
||||
cut_edges is a list of original-graph edges (tuples).
|
||||
Returns set of color tuples."""
|
||||
cut_norm = [tuple(sorted(e[:2])) for e in cut_edges]
|
||||
out = set()
|
||||
for col in colorings:
|
||||
try:
|
||||
out.add(tuple(col[ce] for ce in cut_norm))
|
||||
except KeyError:
|
||||
continue
|
||||
return out
|
||||
|
||||
|
||||
def s3_orbit(t):
|
||||
"""Return S_3 orbit of tuple under color permutation."""
|
||||
return {tuple(p[c] for c in t) for p in itertools.permutations([0, 1, 2])}
|
||||
|
||||
|
||||
def run_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) < 4 or len(S1) < 4:
|
||||
return None
|
||||
if verbose:
|
||||
print(f' cut #{cut_idx}: |S0|={len(S0)}, |S1|={len(S1)}',
|
||||
flush=True)
|
||||
result = {}
|
||||
# Ground truth: enumerate G's 3-edge-colorings, project to cut
|
||||
g_cols = proper_3_edge_colorings_full(G)
|
||||
if g_cols is None:
|
||||
result['ground_truth'] = None
|
||||
else:
|
||||
R_ground = project_to_cut(g_cols, cut_edges)
|
||||
result['R_ground'] = R_ground
|
||||
if verbose:
|
||||
print(f' G has {len(g_cols)} proper 3-edge-colorings, '
|
||||
f'|R_ground|={len(R_ground)}', flush=True)
|
||||
# DP per side
|
||||
for side, S_side in [('0', S0), ('1', S1)]:
|
||||
pendant_id = max(G.vertices()) + 1 + (0 if side == '0' else 500)
|
||||
try:
|
||||
H, pos, ed, _, _, _ = apply_procedure(
|
||||
G, S_side, cut_edges, base_pos, side,
|
||||
pendant_start_id=pendant_id)
|
||||
except Exception as e:
|
||||
result[f'side_{side}_error'] = str(e)
|
||||
continue
|
||||
if not ed:
|
||||
continue
|
||||
faces_by_depth, parent_of, _ = build_tree(H, ed)
|
||||
try:
|
||||
A, struct, issues = chain_dp_joint(
|
||||
faces_by_depth, parent_of, H, ed)
|
||||
except Exception as e:
|
||||
result[f'side_{side}_dp_error'] = str(e)
|
||||
continue
|
||||
if issues:
|
||||
result[f'side_{side}_issues'] = issues
|
||||
# Roots = depth-1 tires; project to cut (= depth-0 pendant edges
|
||||
# in the H subgraph). Cut pendant edges are stored as pseudo
|
||||
# edges in H.
|
||||
# Cut edges in H: pendant edges at the original cut endpoints
|
||||
cut_eids_in_H = []
|
||||
for u, v in cut_edges:
|
||||
# In side-i view, only the side-i endpoint exists; the cut
|
||||
# edge in H is between the original endpoint and a new
|
||||
# pendant vertex. We need to identify these pendants.
|
||||
pass
|
||||
# Simpler: for each root tire T_1^{(f)} on this side, its out
|
||||
# spokes (depth 0) ARE the cut edges (or some of them).
|
||||
R_dp = set()
|
||||
for node, a in A.items():
|
||||
if node[0] != 1 or a is None:
|
||||
continue
|
||||
# We want to identify cut edges in this tire's edges.
|
||||
# Cut edges are depth-0 pendants in H. Filter struct's
|
||||
# all_edges to depth-0 edges.
|
||||
depth_0_eids = [i for i, e in enumerate(struct[node]['all_edges'])
|
||||
if ed.get(e) == 0]
|
||||
if not depth_0_eids:
|
||||
continue
|
||||
for assign in a:
|
||||
tup = tuple(assign[i] for i in depth_0_eids)
|
||||
# Also store WHICH cut edges (by tuple)
|
||||
edges_used = [struct[node]['all_edges'][i]
|
||||
for i in depth_0_eids]
|
||||
# Project: key by edge tuple, value by color
|
||||
R_dp.add(frozenset(zip(edges_used, tup)))
|
||||
result[f'R_dp_{side}_raw'] = R_dp
|
||||
# Convert frozenset-of-(edge,color) to a per-cut-edge color
|
||||
# tuple (in fixed order of cut_edges)
|
||||
cut_norm = [tuple(sorted(e[:2])) for e in cut_edges]
|
||||
# The cut edges in H may have different endpoints (pendant
|
||||
# vertices added by apply_procedure), so we need a mapping.
|
||||
# For now, count cardinality and S3 stats.
|
||||
result[f'R_dp_{side}_size'] = len(R_dp)
|
||||
return result
|
||||
|
||||
|
||||
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=3)
|
||||
for cut_idx in range(min(3, len(cuts))):
|
||||
res = run_one_cut(G, cut_idx, cuts, base_pos, verbose=True)
|
||||
if res is None:
|
||||
continue
|
||||
if 'R_ground' in res:
|
||||
R_ground = res['R_ground']
|
||||
print(f' ground truth |R|={len(R_ground)}, S_3 orbits='
|
||||
f'{len({frozenset(s3_orbit(t)) for t in R_ground})}',
|
||||
flush=True)
|
||||
for side in ['0', '1']:
|
||||
sz = res.get(f'R_dp_{side}_size', 'N/A')
|
||||
issues = res.get(f'side_{side}_issues')
|
||||
print(f' side {side}: |R_dp|={sz}, '
|
||||
f'issues={len(issues) if issues else 0}', flush=True)
|
||||
if issues:
|
||||
for iss in issues[:2]:
|
||||
print(f' {iss}', flush=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -15,4 +15,7 @@
|
||||
\@writefile{toc}{\contentsline {paragraph}{What this changes in the chain DP.}{4}{}\protected@file@percent }
|
||||
\@writefile{toc}{\contentsline {paragraph}{Second issue: out-spoke projection loses S$_3$ orbit.}{4}{}\protected@file@percent }
|
||||
\@writefile{toc}{\contentsline {paragraph}{Third issue: heuristic parent-finding.}{4}{}\protected@file@percent }
|
||||
\gdef \@abspage@last{4}
|
||||
\@writefile{toc}{\contentsline {paragraph}{Fourth issue: when $H_d$ is a tree, the high-side forest is empty.}{4}{}\protected@file@percent }
|
||||
\@writefile{toc}{\contentsline {paragraph}{Empirical baseline for ground-truth comparison.}{5}{}\protected@file@percent }
|
||||
\@writefile{toc}{\contentsline {paragraph}{Path forward.}{5}{}\protected@file@percent }
|
||||
\gdef \@abspage@last{5}
|
||||
|
||||
@@ -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 22:49
|
||||
This is pdfTeX, Version 3.141592653-2.6-1.40.24 (TeX Live 2022) (preloaded format=pdflatex 2022.10.5) 26 MAY 2026 22:58
|
||||
entering extended mode
|
||||
restricted \write18 enabled.
|
||||
%&-line parsing enabled.
|
||||
@@ -280,38 +280,39 @@ ta from the partial- tire-dual chain pi-geon-hole (\OT1/cmtt/m/n/10.95 tire[]fi
|
||||
ber[]step2.tex\OT1/cmr/m/n/10.95 ):
|
||||
[]
|
||||
|
||||
[2] [3] [4] (./chain_half_analysis.aux) )
|
||||
[2] [3] [4] [5] (./chain_half_analysis.aux) )
|
||||
Here is how much of TeX's memory you used:
|
||||
3256 strings out of 478268
|
||||
48448 string characters out of 5846347
|
||||
348617 words of memory out of 5000000
|
||||
350617 words of memory out of 5000000
|
||||
21443 multiletter control sequences out of 15000+600000
|
||||
479693 words of font info for 69 fonts, out of 8000000 for 9000
|
||||
1141 hyphenation exceptions out of 8191
|
||||
55i,8n,62p,236b,241s 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/cmmi6.pfb></usr/local/texlive/2022/texmf-dist/fonts/type
|
||||
1/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/type1/pu
|
||||
blic/amsfonts/cm/cmr17.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/publ
|
||||
ic/amsfonts/cm/cmr6.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/
|
||||
amsfonts/cm/cmr7.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/ams
|
||||
fonts/cm/cmr8.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfon
|
||||
ts/cm/cmsy10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfont
|
||||
s/cm/cmsy8.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/
|
||||
cm/cmti10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts/c
|
||||
m/cmtt10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/cm-super/sf
|
||||
rm1095.pfb>
|
||||
Output written on chain_half_analysis.pdf (4 pages, 216066 bytes).
|
||||
55i,8n,62p,236b,243s 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/cmmi6.pfb></usr/local/texlive/2022/texmf-dist/fonts/
|
||||
type1/public/amsfonts/cm/cmmi7.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/cmr17.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/pu
|
||||
blic/amsfonts/cm/cmr6.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/publi
|
||||
c/amsfonts/cm/cmr7.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/a
|
||||
msfonts/cm/cmr8.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsf
|
||||
onts/cm/cmsy10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfo
|
||||
nts/cm/cmsy8.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfont
|
||||
s/cm/cmti10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/amsfonts
|
||||
/cm/cmtt10.pfb></usr/local/texlive/2022/texmf-dist/fonts/type1/public/cm-super/
|
||||
sfrm1095.pfb>
|
||||
Output written on chain_half_analysis.pdf (5 pages, 229034 bytes).
|
||||
PDF statistics:
|
||||
103 PDF objects out of 1000 (max. 8388607)
|
||||
62 compressed objects within 1 object stream
|
||||
111 PDF objects out of 1000 (max. 8388607)
|
||||
67 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.
@@ -247,6 +247,46 @@ heuristic, which can mis-attribute children to wrong parents.
|
||||
For a rigorous empirical test, parent assignment should use the
|
||||
planar embedding's face-in-face containment, not vertex overlap.
|
||||
|
||||
\paragraph{Fourth issue: when $H_d$ is a tree, the high-side
|
||||
forest is empty.} The level-set lemma forces each face of $H_d$
|
||||
to be entirely low-side or entirely high-side. If $H_d$ has no
|
||||
cycles (= tree/forest), it has a single face containing all
|
||||
non-$H_d$ edges of $G'_i$, and that face must be one or the other
|
||||
(low or high), not both. In the small-side regime (e.g.\
|
||||
dodecahedron $6$-edge cut with $|S_0| = 4$, side $0$), the BFS
|
||||
only reaches depth $1$ and $H_1$ is a tree (5 edges, 6 vertices,
|
||||
$1$ face containing the $6$ pendants). This single face is
|
||||
low-side --- so the high-side cut tire forest of $G'_0$ is
|
||||
\emph{empty}.
|
||||
|
||||
\medskip
|
||||
|
||||
In this case, the framework gives no high-side cut tires on
|
||||
$G'_0$, hence $\mathcal{R}_0 = \emptyset$ by the framework's
|
||||
projection to root out-spokes. But $G$ is $3$-edge-colorable
|
||||
(dodecahedron is Hamiltonian, hence Tait colorable), so the
|
||||
\emph{true} $\mathcal{R}_0$ is non-empty (= the cut-projection of
|
||||
$G$'s $60$ colorings, giving $|R_{\mathrm{ground}}| = 36$).
|
||||
|
||||
\medskip
|
||||
|
||||
So the framework's high-side cut tire forest \emph{loses coverage}
|
||||
for thin (small-$|S_i|$) cuts. The low-side face also carries
|
||||
coloring information --- it contains the pendants and the
|
||||
depth-$1$ subgraph --- but it isn't included as a "cut tire" in
|
||||
the high-side formulation.
|
||||
|
||||
This isn't strictly a bug in any proof so far; it's a coverage
|
||||
gap in the framework's scope. To handle these cases, one of:
|
||||
\begin{itemize}
|
||||
\item Restrict the conjecture to cuts where both sides have
|
||||
``deep'' BFS (e.g.\ $\min(|S_0|, |S_1|) \ge k$ for some
|
||||
$k$ ensuring high-side faces exist).
|
||||
\item Extend the framework to include the low-side face as a
|
||||
special ``boundary cut tire'' connecting pendants to the
|
||||
$H_1$ structure.
|
||||
\end{itemize}
|
||||
|
||||
\section*{Net status of the loose conjecture}
|
||||
|
||||
\begin{center}
|
||||
@@ -256,12 +296,13 @@ planar embedding's face-in-face containment, not vertex overlap.
|
||||
component & status & note \\
|
||||
\midrule
|
||||
Per-tire half (spoke-only $n \ge 3$) & proven & Prop 1.13 \\
|
||||
Per-tire half (branched) & open, needed for generality & \\
|
||||
Per-tire half (branched) & open & non-cycle face boundaries \\
|
||||
Tree structure (forest, high-side) & proven & \texttt{cut\_tire\_tree\_structure.tex} \\
|
||||
Chain DP $S_3$-equivariance & proven & this note, Lemma \\
|
||||
Joint vs.\ OUT projection issue & flagged & need joint-support tracking \\
|
||||
Joint projection DP & implemented, buggy & \texttt{chain\_dp\_joint.py} \\
|
||||
Coverage when $H_d$ is a tree & gap & low-side face carries info \\
|
||||
Chain DP non-emptiness preservation & open & Conj.\ \ref{conj:non-empty-prop} \\
|
||||
Bottom-line $\mathcal{R}_0 \cap \mathcal{R}_1 \ne \emptyset$ & open, $G$-colorability gives it & \\
|
||||
Bottom-line $\mathcal{R}_0 \cap \mathcal{R}_1 \ne \emptyset$ & open & $G$-colorability gives it \\
|
||||
\bottomrule
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
@@ -270,10 +311,30 @@ The chain half reduces to multiple structural claims:
|
||||
\begin{itemize}
|
||||
\item per-tire half for branched cut tires;
|
||||
\item joint-support DP (track $\pi(T)$, not just OUT projection);
|
||||
\item handling cases where $H_d$ is a tree (no high-side faces);
|
||||
\item non-emptiness preservation (Conj.\ \ref{conj:non-empty-prop}
|
||||
or Strong per-tire extendibility).
|
||||
\end{itemize}
|
||||
None are in hand yet. The $S_3$-equivariance and forest structure
|
||||
are. The full chain half is genuinely open and requires more work.
|
||||
The $S_3$-equivariance and forest structure (with high-side
|
||||
restriction) are in hand. The full chain half is genuinely open
|
||||
and the framework has coverage gaps not previously identified.
|
||||
|
||||
\paragraph{Empirical baseline for ground-truth comparison.}
|
||||
\texttt{chain\_dp\_joint.py} compares the chain DP output
|
||||
against a brute-force enumeration of $G'_i$'s proper $3$-edge
|
||||
colorings projected to the cut. On the dodecahedron, ground
|
||||
truth shows $|R_{\mathrm{ground}}| \in \{36, 42, 48\}$ across
|
||||
the first few cuts, but DP outputs $0$ for any side where
|
||||
$H_1$ is a tree (= no high-side cut tires). This isn't a DP
|
||||
bug per se --- it's the framework lacking coverage.
|
||||
|
||||
\paragraph{Path forward.} The cleanest next step is probably
|
||||
the \emph{boundary cut tire} extension: define an additional
|
||||
``cut tire'' $T_0$ that represents the low-side face of $H_1$
|
||||
+ its incident pendants. $T_0$'s spokes are the cut edges;
|
||||
its cycle structure is the boundary of the low-side face.
|
||||
The high-side forest then sits ``inside'' $T_0$, and the chain
|
||||
DP runs from leaves up through $T_0$ to the cut. This recovers
|
||||
the missing coverage and gives a more uniform formulation.
|
||||
|
||||
\end{document}
|
||||
|
||||
Reference in New Issue
Block a user