import json,math,itertools
from fractions import Fraction
from functools import reduce
from pathlib import Path
r=json.load(open('data/published.json'));Path('results').mkdir(exist_ok=True)
def parts(n,m=None):
 if n==0:yield ();return
 for a in range(min(n,m or n),0,-1):
  for z in parts(n-a,a):yield (a,)+z
checks={}
for n in [10,25,50]:
 counts={};nf=math.factorial(n)
 for part in parts(n):
  k=len(part);v=[a+k-i-1 for i,a in enumerate(part)]
  num=nf*math.prod(v[i]-v[j] for i in range(k) for j in range(i+1,k));den=math.prod(math.factorial(x) for x in v)
  assert num%den==0;f=num//den
  counts[part[0]]=counts.get(part[0],0)+f*f
 assert counts=={int(k):v for k,v in r['table'][str(n)]['distribution'].items()};checks[str(n)]=True
allbound=True
for sn,t in r['table'].items():
 n=int(sn);fact=math.factorial(n);S=sum(int(k)*v for k,v in t['distribution'].items());assert sum(t['distribution'].values())==fact
 assert S*S<4*n*fact*fact
exact50=Fraction(sum(int(k)*v for k,v in r['table']['50']['distribution'].items()),math.factorial(50))
# A quadratic dynamic program shares neither RSK nor patience-sorting logic.
dp_checked=0
for n in range(1,9):
 counts={}
 for p in itertools.permutations(range(n)):
  lengths=[]
  for i,v in enumerate(p):lengths.append(1+max([lengths[j] for j in range(i) if p[j]<v],default=0))
  k=max(lengths);counts[k]=counts.get(k,0)+1;dp_checked+=1
 assert counts=={int(k):v for k,v in r['table'][str(n)]['distribution'].items()}
out={'independent_vandermonde_dimension_distributions_match':checks,'strict_expectation_bound_integer_certificates':50,'exact_mean50_fraction':str(exact50),'exact_mean50_decimal':float(exact50),'quadratic_dp_permutations_checked':dp_checked,'counts_exceed_json_safe_integer':any(v>2**53 for t in r['table'].values() for v in t['distribution'].values())}
Path('results/adversarial.json').write_text(json.dumps(out,indent=2));print(json.dumps(out))
