"""For each chord-apex+Kempe colouring, walk K_b and record: - The Heawood-flip count along K_b (= # consecutive (v_k, v_{k+1}) pairs with h_phi(v_k) != h_phi(v_{k+1})). - The Heawood-flip count is at least 4 empirically (n >= 14). For colourings achieving the minimum flip count on K_b, dump the sequence of (Heawood, edge-position-on-cycle) so we can see *where* the flips fall. Are they at the merged edge? At spike? At specific structural locations? Or spread out? Run with: sage experiments/check_min_flip_structure.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_final_scaled import ( apply_reduction, proper_3_edge_colorings, matches_chord_apex_kempe, trace_kempe_cycle, edge_idx, ) from check_heawood_on_kempe import dual_of, heawood_numbers def test_one(D): D.is_planar(set_embedding=True) n_col = 0 # For each Kempe cycle (K_b, K_c), record (flip_count, length). flips_kb = {} # flip_count -> count # For minimum-flip colourings, record the Heawood pattern + edge colours. min_patterns = [] # tuples (flip_count, length, pattern, colours) cur_min = None 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)] for col in cand: n_col += 1 try: h = heawood_numbers(H, edges, col) except RuntimeError: continue merged_idx = edge_idx(edges, named['merged']) a = col[merged_idx] bs = [c for c in range(3) if c != a] # Only check K_b for this script walk_b = trace_kempe_cycle(edges, col, merged_idx, (a, bs[0])) L = len(walk_b) h_seq = [h[walk_b[k][1]] for k in range(L)] # edge sequence: walk_b[k][0] is the edge index of the K_b # edge ENTERING walk_b[k][1]. e_colors = [col[walk_b[k][0]] for k in range(L)] # Flip count: pairs (h_seq[k], h_seq[(k+1) % L]) that differ. flips = sum(1 for k in range(L) if h_seq[k] != h_seq[(k+1) % L]) flips_kb[flips] = flips_kb.get(flips, 0) + 1 if cur_min is None or flips < cur_min: cur_min = flips min_patterns = [(flips, L, tuple(h_seq), tuple(e_colors))] elif flips == cur_min and len(min_patterns) < 5: min_patterns.append((flips, L, tuple(h_seq), tuple(e_colors))) return n_col, flips_kb, cur_min, min_patterns def main(max_n=18, time_budget_per_n=1800): print(f"Min-flip Heawood pattern on K_b, n in [12, {max_n}]\n") overall_min = None overall_min_examples = [] 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 flips_n = {} n_min = None min_examples = [] 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) ni, fi, cm, exs = test_one(D) n_col_n += ni for k, v in fi.items(): flips_n[k] = flips_n.get(k, 0) + v if cm is not None: if n_min is None or cm < n_min: n_min = cm min_examples = list(exs) elif cm == n_min and len(min_examples) < 5: min_examples.extend(exs[:5 - len(min_examples)]) elapsed = time.time() - start print(f"n={n}: {n_col_n} col., flip_dist on K_b: " f"{sorted(flips_n.items())}, min flip: {n_min} [{elapsed:.0f}s]") if min_examples: print(f" Examples of min-flip K_b (flip count = {n_min}):") for ex in min_examples[:3]: flips_x, L, h_pat, e_cols = ex print(f" L={L}, flips={flips_x}") print(f" h sequence : {h_pat}") print(f" colour seq : {e_cols}") sys.stdout.flush() if overall_min is None or (n_min is not None and n_min < overall_min): overall_min = n_min overall_min_examples = min_examples print() print(f"Overall minimum flip count on K_b across all tested: {overall_min}") if __name__ == '__main__': main()