b72c38b8ce
constancy on V(K_b) U V(K_c))
Three empirical checks on all chord-apex+Kempe colourings up to
n = 20 (142,812 colourings):
1. check_heawood_on_kempe.py
- Sum_v h_phi(v): not zero in general; 17.6% of colourings have
sum 0, the rest range in {+-4, +-8, +-12, +-16, +-20, +-24}.
So the global "Heawood sum = 0" identity fails.
- h_phi constant on V(K_b) U V(K_c): NEVER (0/142,812). This is
the central empirical result -- by Lemma 5.3's contrapositive
it gives an empirical proof of Conjecture 5.1 on these
surrogates.
2. check_heawood_per_kempe_cycle.py
- Sum_{V(K_b)} h_phi and sum_{V(K_c)} h_phi range widely (-20 to
+20), with only ~23% zero. So the "Heawood sum on each Kempe
cycle = 0" identity also fails -- the per-cycle sum is not the
right invariant.
3. check_heawood_pair_mismatch.py
- For each of 16 named-vertex pairs (v_n with each A_j, A_j with
A_k for j, k in {i, ..., i+4}), counts how often h_phi differs.
No pair is *always* differing -- the closest are consecutive
pairs (A_j, A_{j+1}) at ~75% diff. So the Heawood mismatch
enforcing non-constancy on V(K_b) U V(K_c) is diffuse, not at
a fixed pair.
Together these results confirm Path 4 (Conjecture 5.1 reduces via
Lemma 5.3 to showing h_phi non-constant on V(K_b) U V(K_c)) but
rule out the simplest single-pair-identity proof; the structural
obstruction lives elsewhere (likely a topological/cycle-winding
argument or a chord-apex/Kempe-spike colour cascade).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
153 lines
5.7 KiB
Python
153 lines
5.7 KiB
Python
"""For every chord-apex+Kempe colouring, record whether each of a set of
|
|
named-vertex pairs has differing Heawood numbers. If a pair *always*
|
|
disagrees, that gives a structural identity h_phi(u) != h_phi(v) that
|
|
can be plugged into Lemma 5.3 to prove Conjecture 5.1.
|
|
|
|
Pairs we track (all lie in V(K_b) cap V(K_c)):
|
|
(v_n, A_i), (v_n, A_{i+1}), (v_n, A_{i+2}),
|
|
(v_n, A_{i+3}), (v_n, A_{i+4}),
|
|
(A_i, A_{i+1}), (A_{i+1}, A_{i+2}),
|
|
(A_{i+2}, A_{i+3}), (A_{i+3}, A_{i+4}), (A_{i+4}, A_i),
|
|
(A_i, A_{i+2}), (A_i, A_{i+3}), (A_i, A_{i+4}),
|
|
(A_{i+1}, A_{i+3}), (A_{i+1}, A_{i+4}), (A_{i+2}, A_{i+4})
|
|
|
|
Run with: sage experiments/check_heawood_pair_mismatch.py
|
|
"""
|
|
import os
|
|
import sys
|
|
import time
|
|
|
|
from sage.all import Graph
|
|
from sage.graphs.graph_generators import graphs
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
sys.path.insert(0, HERE)
|
|
|
|
from check_conj_3_8_scaled import (
|
|
apply_reduction,
|
|
proper_3_edge_colorings,
|
|
matches_chord_apex_kempe,
|
|
)
|
|
from check_heawood_on_kempe import dual_of, heawood_numbers
|
|
|
|
|
|
def extract_named_vertices(named, v_n_label=9999):
|
|
"""Pull the labels A_i ... A_{i+4} out of the named-edge dict.
|
|
|
|
named['side_0'] = frozenset((v_n, A_i))
|
|
named['spike'] = frozenset((v_n, A_{i+1}))
|
|
named['side_1'] = frozenset((v_n, A_{i+2}))
|
|
named['merged'] = frozenset((A_{i+3}, A_{i+4}))
|
|
"""
|
|
def other(edge_fs, v):
|
|
return next(iter(edge_fs - {v}))
|
|
A_i = other(named['side_0'], v_n_label)
|
|
A_i1 = other(named['spike'], v_n_label)
|
|
A_i2 = other(named['side_1'], v_n_label)
|
|
merged_set = named['merged']
|
|
# A_{i+3}, A_{i+4} are the two endpoints of merged; we can't tell them
|
|
# apart from the named dict alone, so we just pick an ordering.
|
|
a, b = sorted(merged_set)
|
|
A_i3, A_i4 = a, b
|
|
return v_n_label, A_i, A_i1, A_i2, A_i3, A_i4
|
|
|
|
|
|
def test_one(D):
|
|
"""Tally pair-mismatches over all chord-apex+Kempe colourings of D."""
|
|
D.is_planar(set_embedding=True)
|
|
n_col = 0
|
|
pair_diff = {} # pair_label -> count of colourings where h differs
|
|
pair_same = {}
|
|
for face in D.faces():
|
|
if len(face) != 5: continue
|
|
for i_red in range(5):
|
|
res = apply_reduction(D, face, i_red, 9999)
|
|
if res is None: continue
|
|
H = res['H']; named = res['named']
|
|
H.is_planar(set_embedding=True)
|
|
edges, colorings = proper_3_edge_colorings(H)
|
|
cand = [c for c in colorings
|
|
if matches_chord_apex_kempe(edges, c, named)]
|
|
v_n, A_i, A_i1, A_i2, A_i3, A_i4 = extract_named_vertices(named)
|
|
named_pairs = [
|
|
('v_n, A_i', v_n, A_i ),
|
|
('v_n, A_{i+1}', v_n, A_i1),
|
|
('v_n, A_{i+2}', v_n, A_i2),
|
|
('v_n, A_{i+3}', v_n, A_i3),
|
|
('v_n, A_{i+4}', v_n, A_i4),
|
|
('A_i, A_{i+1}', A_i, A_i1),
|
|
('A_{i+1}, A_{i+2}', A_i1, A_i2),
|
|
('A_{i+2}, A_{i+3}', A_i2, A_i3),
|
|
('A_{i+3}, A_{i+4}', A_i3, A_i4),
|
|
('A_{i+4}, A_i', A_i4, A_i ),
|
|
('A_i, A_{i+2}', A_i, A_i2),
|
|
('A_i, A_{i+3}', A_i, A_i3),
|
|
('A_i, A_{i+4}', A_i, A_i4),
|
|
('A_{i+1}, A_{i+3}', A_i1, A_i3),
|
|
('A_{i+1}, A_{i+4}', A_i1, A_i4),
|
|
('A_{i+2}, A_{i+4}', A_i2, A_i4),
|
|
]
|
|
for col in cand:
|
|
n_col += 1
|
|
try:
|
|
h = heawood_numbers(H, edges, col)
|
|
except RuntimeError:
|
|
continue
|
|
for label, u, w in named_pairs:
|
|
if h[u] != h[w]:
|
|
pair_diff[label] = pair_diff.get(label, 0) + 1
|
|
else:
|
|
pair_same[label] = pair_same.get(label, 0) + 1
|
|
return n_col, pair_diff, pair_same
|
|
|
|
|
|
def main(max_n=18, time_budget_per_n=1800):
|
|
print(f"Pair-mismatch check on chord-apex+Kempe colourings, "
|
|
f"n in [12, {max_n}]\n")
|
|
grand_col = 0
|
|
grand_diff = {}
|
|
grand_same = {}
|
|
for n in range(12, max_n + 1):
|
|
start = time.time()
|
|
try:
|
|
triangulations = list(graphs.triangulations(n, minimum_degree=5))
|
|
except Exception as ex:
|
|
print(f"n={n}: cannot enumerate ({ex})")
|
|
continue
|
|
n_col_n = 0
|
|
diff_n = {}; same_n = {}
|
|
for tri_idx, G in enumerate(triangulations):
|
|
if time.time() - start > time_budget_per_n:
|
|
print(f" n={n}: timeout at tri {tri_idx}/{len(triangulations)}")
|
|
break
|
|
G.is_planar(set_embedding=True)
|
|
D = dual_of(G)
|
|
n_col_i, diff_i, same_i = test_one(D)
|
|
n_col_n += n_col_i
|
|
for k, v in diff_i.items(): diff_n[k] = diff_n.get(k, 0) + v
|
|
for k, v in same_i.items(): same_n[k] = same_n.get(k, 0) + v
|
|
elapsed = time.time() - start
|
|
print(f"n={n}: {n_col_n} colourings [{elapsed:.0f}s]")
|
|
sys.stdout.flush()
|
|
grand_col += n_col_n
|
|
for k, v in diff_n.items(): grand_diff[k] = grand_diff.get(k, 0) + v
|
|
for k, v in same_n.items(): grand_same[k] = grand_same.get(k, 0) + v
|
|
|
|
print()
|
|
print("=" * 78)
|
|
print(f"Grand totals (n in [12, {max_n}], {grand_col} colourings)")
|
|
print("-" * 78)
|
|
print(f"{'pair':<22} {'#diff':>10} {'#same':>10} {'always diff?':>14}")
|
|
print("-" * 78)
|
|
# Stable order: track all keys seen.
|
|
all_keys = sorted(set(list(grand_diff.keys()) + list(grand_same.keys())))
|
|
for k in all_keys:
|
|
d = grand_diff.get(k, 0); s = grand_same.get(k, 0)
|
|
always_diff = (s == 0 and d > 0)
|
|
marker = ' YES <==' if always_diff else ''
|
|
print(f"{k:<22} {d:>10} {s:>10} {marker:>14}")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|