"""Authored finite Bernoulli hypothesis posterior, exact total variance and non-identifiable uncertainty splits."""
from fractions import Fraction as F
import json
def summarize(ps,weights):
    assert sum(weights,F(0))==1
    mean=sum((w*p for w,p in zip(weights,ps)),F(0))
    within=sum((w*p*(1-p) for w,p in zip(weights,ps)),F(0))
    between=sum((w*(p-mean)**2 for w,p in zip(weights,ps)),F(0))
    joint=[{'hypothesis':i,'y':y,'mass':str(w*(p if y else 1-p))} for i,(w,p) in enumerate(zip(weights,ps)) for y in [0,1]]
    variance=sum((F(r['mass'])*(F(r['y'])-mean)**2 for r in joint),F(0))
    assert variance==within+between==mean*(1-mean)
    return {'weights':[str(w) for w in weights],'mean_predictive_probability':str(mean),'expected_conditional_variance':str(within),'variance_of_conditional_means':str(between),'predictive_variance_direct_joint':str(variance),'joint_distribution':joint}
def demo():
    ps=[F(1,4),F(3,4)];weights=[F(1,2),F(1,2)];trace=[{'observations':[],**summarize(ps,weights)}];observed=[]
    for y in [1,1,0,0]:
        likelihood=[p if y else 1-p for p in ps];unnormalized=[w*l for w,l in zip(weights,likelihood)];evidence=sum(unnormalized,F(0))
        weights=[v/evidence for v in unnormalized];observed.append(y)
        trace.append({'observations':observed.copy(),'likelihoods':[str(v) for v in likelihood],'evidence_probability':str(evidence),**summarize(ps,weights)})
    assert trace[0]['expected_conditional_variance']=='3/16' and trace[0]['variance_of_conditional_means']=='1/16'
    assert [r['weights'] for r in trace]==[['1/2','1/2'],['1/4','3/4'],['1/10','9/10'],['1/4','3/4'],['1/2','1/2']]
    alternatives={'single_known_half':summarize([F(1,2)],[F(1)]),'two_deterministic_hypotheses':summarize([F(0),F(1)],[F(1,2),F(1,2)])}
    assert all(r['mean_predictive_probability']=='1/2' and r['predictive_variance_direct_joint']=='1/4' for r in alternatives.values())
    return {'hypothesis_bernoulli_probabilities':[str(v) for v in ps],'assumptions':['finite authored hypothesis set','prior weights supplied by author','observations conditionally iid Bernoulli under the fixed latent hypothesis','same hypothesis for successive observations'],'trace':trace,'same_predictive_Bernoulli_half_different_splits':alternatives,'weights_are_actual_Bayes_updates_not_model_training':True,'decomposition_not_identifiable_without_model_assumptions':True,'empirical_ensemble_disagreement_or_BNN_training_or_real_data':False}
if __name__=='__main__':print(json.dumps(demo(),ensure_ascii=False,indent=2))
