"""Authored paired correctness table and exact two-sided conditional binomial McNemar calculation."""
from fractions import Fraction as F
import math,json
def exact_p(b,c):
    if type(b) is not int or type(c) is not int or min(b,c)<0 or b+c>1000:raise ValueError('integer discordances, sum at most1000 in this exercise')
    n=b+c
    return min(F(1),2*sum((F(math.comb(n,k),2**n) for k in range(min(b,c)+1)),F(0)))
def demo():
    rows=[]
    for i in range(20):
        y=i%2;acorrect=i<10 or i==17;bcorrect=i<17
        rows.append({'pair_id':'P'+str(i+1),'reference':y,'A_prediction':y if acorrect else 1-y,'B_prediction':y if bcorrect else 1-y})
    counts={'both_correct':0,'A_wrong_B_correct':0,'A_correct_B_wrong':0,'both_wrong':0}
    for r in rows:
        a=r['A_prediction']==r['reference'];b=r['B_prediction']==r['reference']
        key='both_correct' if a and b else 'A_wrong_B_correct' if b else 'A_correct_B_wrong' if a else 'both_wrong';counts[key]+=1
    assert counts=={'both_correct':10,'A_wrong_B_correct':7,'A_correct_B_wrong':1,'both_wrong':2}
    b,c=counts['A_wrong_B_correct'],counts['A_correct_B_wrong'];p=exact_p(b,c)
    assert p==F(9,128) and p==exact_p(c,b);assert exact_p(0,0)==exact_p(4,4)==1
    assert F(counts['both_correct']+b,20)-F(counts['both_correct']+c,20)==F(3,10)
    return {'authored_prediction_pairs':rows,'correctness_table':counts,'discordant_pairs':b+c,'conditional_null':'among discordant independent pairs, each direction has probability1/2','exact_tail_terms':[str(F(math.comb(b+c,k),2**(b+c))) for k in range(min(b,c)+1)],'two_sided_rule':'min(1,2*BinomialCDF(min(b,c),b+c,1/2))','p_exact_fraction':str(p),'p_exact_decimal':float(p),'A_correct_fraction':'11/20','B_correct_fraction':'17/20','observed_accuracy_difference':'3/10','illustrative_prespecified_alpha':.05,'reject_under_that_rule':p<F(1,20),'no_discordance_p':str(exact_p(0,0)),'independent_pairs_or_sampling_not_proven_by_fixture':True,'statsmodels_or_scipy_executed':False}
if __name__=='__main__':print(json.dumps(demo(),ensure_ascii=False,indent=2))
