"""Original exact fixed-margin2x2 enumeration, no clinical/customer data."""
from math import comb
from fractions import Fraction as F
from itertools import combinations,product
from collections import Counter
import json
def enumerate_tables(table):
 if type(table) is not list or len(table)!=2 or any(type(r) is not list or len(r)!=2 for r in table) or any(type(x) is not int or x<0 for r in table for x in r):raise ValueError('2x2 nonnegative integer counts, no bool')
 a,b=table[0];c,d=table[1];N=a+b+c+d
 if not 1<=N<=12:raise ValueError('total1..12')
 n=a+b;K=a+c;den=comb(N,n);rows=[]
 for x in range(max(0,n+K-N),min(n,K)+1):
  mass=F(comb(K,x)*comb(N-K,n-x),den);rows.append({'upper_left':x,'table':[[x,n-x],[K-x,N-n-K+x]],'mass':mass})
 observed=next(r['mass'] for r in rows if r['upper_left']==a);p=sum((r['mass'] for r in rows if r['mass']<=observed),F(0));assert sum(r['mass'] for r in rows)==1
 return rows,p,observed,(N,n,K)
def demo():
 table=[[1,4],[4,1]];rows,p,observed,(N,n,K)=enumerate_tables(table);assert p==F(13,63)
 # Directly enumerate all equally likely choices of row1 labels from N slots;
 # first K slots carry column1. This does not use the hypergeometric formula.
 counts=Counter(sum(i<K for i in selected) for selected in combinations(range(N),n));assert sum(counts.values())==252
 for r in rows:assert F(counts[r['upper_left']],252)==r['mass']
 fixtures=[]
 for t in [[[4,1],[1,4]],[[0,5],[5,0]],[[0,0],[3,2]],[[1,0],[0,0]]]:
  r,pp,_,_=enumerate_tables(t);fixtures.append({'table':t,'p_two_sided':str(pp),'masses_sum_one':sum(z['mass'] for z in r)==1})
 assert enumerate_tables([[4,1],[1,4]])[1]==p
 symmetry_checks=0
 for cells in product(range(3),repeat=4):
  if not sum(cells):continue
  a,b,c,d=cells;original=enumerate_tables([[a,b],[c,d]])[1]
  assert enumerate_tables([[c,d],[a,b]])[1]==original and enumerate_tables([[b,a],[d,c]])[1]==original;symmetry_checks+=1
 ar,ap,_,_=enumerate_tables([[1,0],[1,3]]);one=sum(r['mass'] for r in ar if r['upper_left']>=1);assert ap==F(2,5) and min(F(1),2*one)==F(4,5)
 rejected=[]
 for t in [[[-1,2],[3,4]],[[True,1],[2,3]],[[1.5,1],[2,3]],[[0,0],[0,0]],[[1,2,3],[4,5,6]]]:
  try:enumerate_tables(t)
  except ValueError:rejected.append(repr(t))
  else:raise AssertionError('expected rejection')
 return {'observed_table':table,'fixed_margins':{'N':N,'row1':n,'column1':K},'all_six_tables':[{**r,'mass':str(r['mass'])} for r in rows],'observed_mass':str(observed),'two_sided_definition':'sum masses <= observed mass, exact Fraction comparison','two_sided_p':str(p),'independent_252_labeled_allocations':dict(sorted(counts.items())),'swaps_and_zero_cell_cases':fixtures,'all_small_table_row_column_symmetry_checks':symmetry_checks,'not_generally_twice_one_sided':{'table':[[1,0],[1,3]],'two_sided_probability_ordering':str(ap),'one_sided_greater':str(one),'twice_one_sided_capped':str(min(F(1),2*one))},'invalid_cases_rejected':rejected,'limits':'hypothetical independent groups conditional on fixed margins, not paired McNemar, posterior probability, effect size, causality or medical guidance; SciPy not run'}
if __name__=='__main__':print(json.dumps(demo(),ensure_ascii=True,indent=2))
