"""Exact prospective power of an authored one-sided one-sample binomial rejection rule; not a two-arm experiment."""
from fractions import Fraction as F
import math,json
def tail(n,p,k):return sum((F(math.comb(n,j))*p**j*(1-p)**(n-j) for j in range(k,n+1)),F(0))
def demo():
    p0=F(1,2);alpha=F(1,20);p1=F(7,10);goal=F(4,5);rows=[]
    for n in [20,40,80]:
        critical=next(k for k in range(n+1) if tail(n,p0,k)<=alpha)
        null_rejection=tail(n,p0,critical);power=tail(n,p1,critical)
        assert null_rejection<=alpha and (critical==0 or tail(n,p0,critical-1)>alpha)
        grid=[F(j,100) for j in range(51,101)];detected=next(p for p in grid if tail(n,p,critical)>=goal)
        assert tail(n,detected,critical)>=goal
        previous=detected-F(1,100)
        if previous>p0:assert tail(n,previous,critical)<goal
        rows.append({'n_independent_Bernoulli_trials':n,'reject_if_success_count_at_least':critical,'actual_null_rejection_probability':str(null_rejection),'actual_null_rejection_decimal':float(null_rejection),'power_at_p_0_7':str(power),'power_at_p_0_7_decimal':float(power),'minimum_p_on_author_grid_reaching_power_0_8':str(detected),'minimum_effect_on_that_grid_vs_p0':str(detected-p0),'power_at_grid_minimum':str(tail(n,detected,critical))})
    return {'hypothesized_p0':str(p0),'one_sided_alternative':'p>p0; rule selected before observing data','nominal_alpha':str(alpha),'fixed_alternative_for_power':str(p1),'target_power_for_grid':str(goal),'search_grid':'p=0.51,0.52,...,1.00; discrete grid MDE, not continuous optimum','rows':rows,'exact_fraction_calculation_not_normal_approximation':True,'actual_observations_or_experiment_conducted':False,'two_arm_or_paired_model_sample_size_claimed':False,'independent_identically_distributed_Bernoulli_model_assumed_not_verified':True,'scipy_executed':False}
if __name__=='__main__':print(json.dumps(demo(),ensure_ascii=False,indent=2))
