face_monochromatic_pairs: strengthen Conj 5.5 to face-length ≥ 5, find 28-vertex counterexample
- Paper: Conjecture 5.5 restated with the hypothesis that every face
of H has length ≥ 5 (= the cubic plane analogue of "no triangles
or quadrilaterals as faces"). This kills K_4 and the n=8 trivial
counterexamples (girth 3) and the ad-hoc n=40 counterexample
(which has 2 triangles and 4 quadrilaterals). A new remark catalogues
these excluded counterexamples and the smallest cubic plane graphs
satisfying the hypothesis (dodecahedron at |V| = 20).
- search_smaller_counterexample.py: --min-face=N option to filter
cubic planar graphs by minimum face length.
- search_min_face5_counterexample.py: enumerates triangulations T
with min degree ≥ 5 via graphs.triangulations(n, minimum_degree=5),
takes planar dual (= cubic plane with all faces ≥ 5), and runs the
Heawood-constancy check.
- Result: smallest counterexample at triangulation order n_T = 16,
whose dual is a 28-vertex cubic plane graph (graph6
[kG[A?_A?_?_?K?D?@_CO?o?@_??A??@C??O??AG?C????`???a???W???A_???F).
Faces: 12 pentagons + 4 hexagons (a C28 fullerene). Both
K_{red, blue} and K_{red, green} are 12-cycles sharing the
colour-red edge (0, 1) and both have h_φ ≡ -1. 8 of 28 vertices
lie outside V(K_0) ∪ V(K_1).
- verify_28_vertex_counterexample.py: reproduces the counterexample,
verifies all properties, and renders figures/min-face-5-counterexample.png.
Note on the boundary: face-length ≥ 6 is impossible for cubic plane
graphs by Euler (6F = 6(V/2 + 2) > 3V = sum face lengths for V > 4).
So face-length ≥ 5 is the strongest face-length restriction admitting
any cubic plane graphs at all.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
"""Search for counterexamples to the strengthened Conjecture 5.5:
|
||||
|
||||
Let H be a cubic plane graph in which every face has length ≥ 5,
|
||||
with a proper 3-edge-colouring φ. If K_0 = {a,b}-Kempe cycle and
|
||||
K_1 = {a,c}-Kempe cycle share a colour-a edge, then h_φ cannot be
|
||||
constant on both V(K_0) and V(K_1).
|
||||
|
||||
The graphs H satisfying the face-length-≥-5 hypothesis are exactly
|
||||
the duals of triangulations of the sphere with minimum degree ≥ 5.
|
||||
We enumerate these via plantri (through Sage's
|
||||
`graphs.triangulations(n, minimum_degree=5)`), take the planar dual,
|
||||
and run the same Heawood-constancy check as
|
||||
`search_smaller_counterexample.py`.
|
||||
|
||||
For each triangulation order n, the dual has 2n - 4 cubic vertices.
|
||||
The smallest case n = 12 is the icosahedron, whose dual is the
|
||||
dodecahedron (20 vertices, all faces pentagonal).
|
||||
|
||||
Run with:
|
||||
sage experiments/search_min_face5_counterexample.py # default max_n=14
|
||||
sage experiments/search_min_face5_counterexample.py 16
|
||||
sage experiments/search_min_face5_counterexample.py 16 --all
|
||||
"""
|
||||
import sys
|
||||
import time
|
||||
|
||||
from sage.all import Graph
|
||||
from sage.graphs.graph_generators import graphs
|
||||
|
||||
# Reuse the verification machinery from the cubic-search script.
|
||||
import os
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, HERE)
|
||||
from search_smaller_counterexample import (
|
||||
check_graph,
|
||||
min_face_length,
|
||||
)
|
||||
|
||||
|
||||
def planar_dual(G):
|
||||
"""Build the planar dual of a planar graph G with its embedding
|
||||
already set via G.is_planar(set_embedding=True)."""
|
||||
faces = G.faces()
|
||||
D = Graph(multiedges=False, loops=False)
|
||||
n_faces = len(faces)
|
||||
D.add_vertices(range(n_faces))
|
||||
# Map each (undirected) edge of G to the indices of the two faces
|
||||
# that contain it.
|
||||
edge_to_faces = {}
|
||||
for i, face in enumerate(faces):
|
||||
for e in face:
|
||||
key = frozenset(e[:2])
|
||||
edge_to_faces.setdefault(key, []).append(i)
|
||||
for key, fs in edge_to_faces.items():
|
||||
if len(fs) == 2 and fs[0] != fs[1]:
|
||||
D.add_edge(fs[0], fs[1])
|
||||
return D
|
||||
|
||||
|
||||
def main():
|
||||
args = [a for a in sys.argv[1:] if not a.startswith('--')]
|
||||
max_n = int(args[0]) if args else 14
|
||||
flag_all = '--all' in sys.argv[1:]
|
||||
|
||||
print(f"Searching for counterexamples to the face-length-≥-5 form "
|
||||
f"of Conjecture 5.5.\n"
|
||||
f"Iterating over triangulations with min degree ≥ 5 for "
|
||||
f"n_T in [12, {max_n}].\n"
|
||||
f"Each dual is cubic with all faces of length ≥ 5; the dual "
|
||||
f"has 2n_T - 4 vertices.\n"
|
||||
f"{'Continuing past first hit.' if flag_all else 'Stopping at first hit.'}\n")
|
||||
|
||||
first_found = None
|
||||
for n_T in range(12, max_n + 1):
|
||||
start = time.time()
|
||||
count = 0
|
||||
found = None
|
||||
try:
|
||||
gen = graphs.triangulations(n_T, minimum_degree=5)
|
||||
except Exception as ex:
|
||||
print(f"n_T={n_T:>3}: cannot enumerate ({ex})")
|
||||
continue
|
||||
for T in gen:
|
||||
T.is_planar(set_embedding=True)
|
||||
H = planar_dual(T)
|
||||
n_H = H.order()
|
||||
# Sanity: H should be cubic and planar; faces length ≥ 5.
|
||||
if max(H.degree()) != 3 or min(H.degree()) != 3:
|
||||
continue
|
||||
if not H.is_planar(set_embedding=True):
|
||||
continue
|
||||
if min_face_length(H) < 5:
|
||||
continue
|
||||
count += 1
|
||||
res = check_graph(H)
|
||||
if res is not None:
|
||||
found = (T.copy(), H.copy(), res, n_H)
|
||||
if not flag_all:
|
||||
break
|
||||
elapsed = time.time() - start
|
||||
n_H_min = 2 * n_T - 4
|
||||
if found is None:
|
||||
print(f"n_T={n_T:>3}: checked {count} triangulation duals "
|
||||
f"(each with {n_H_min} cubic vertices), no counterexample "
|
||||
f"[{elapsed:.1f}s]")
|
||||
else:
|
||||
T, H, (col, K0, K1, h0, h1, a, b, c, e), n_H = found
|
||||
colour_name = {0: 'red', 1: 'blue', 2: 'green'}
|
||||
print(f"n_T={n_T:>3}: COUNTEREXAMPLE in dual #{count} "
|
||||
f"(|V(H)| = {n_H}) [{elapsed:.1f}s]")
|
||||
print(f" triangulation canonical graph6 = "
|
||||
f"{T.canonical_label().graph6_string()}")
|
||||
print(f" dual (cubic) canonical graph6 = "
|
||||
f"{H.canonical_label().graph6_string()}")
|
||||
print(f" dual edges = {sorted(H.edges(labels=False))}")
|
||||
print(f" colouring = {col}")
|
||||
print(f" shared colour = {colour_name[a]} ({a}), edge {e}")
|
||||
print(f" K_{{a,b}} = K_{{{colour_name[a]},{colour_name[b]}}} "
|
||||
f"= {K0} (h={h0:+d}, |V|={len(K0)})")
|
||||
print(f" K_{{a,c}} = K_{{{colour_name[a]},{colour_name[c]}}} "
|
||||
f"= {K1} (h={h1:+d}, |V|={len(K1)})")
|
||||
if first_found is None:
|
||||
first_found = n_T
|
||||
if not flag_all:
|
||||
break
|
||||
sys.stdout.flush()
|
||||
|
||||
if first_found is not None:
|
||||
print(f"\nSmallest counterexample at triangulation order n_T "
|
||||
f"= {first_found} (dual has {2 * first_found - 4} vertices).")
|
||||
else:
|
||||
print(f"\nNo counterexample found for triangulation orders ≤ "
|
||||
f"{max_n} (dual orders ≤ {2 * max_n - 4}).")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user