"""Original finite rejection conditional law plus bounded seeded sampling, not MH/importance."""
from fractions import Fraction as F
from itertools import product
import random,json

def validate(p,q,m,bins):
 if any(type(a) is not list or not 1<=len(a)<=4 or any(type(v) not in [int,F] or not 0<=v<=1 or F(v).denominator>10000 for v in a) or sum(a)!=1 for a in [p,q]) or len(p)!=len(q) or any(v<=0 for v in q) or type(m) not in [int,F] or not 0<m<=10 or any(F(a)>m*b for a,b in zip(p,q)) or type(bins) is not int or not 1<=bins<=24:raise ValueError('bounded normalized masses, positive proposal and valid global envelope/bins')

def law(p,q,m,bins):
 validate(p,q,m,bins);rows=[];accepted=[F(0)]*len(p)
 for i,j in product(range(len(p)),range(bins)):
  u=F(2*j+1,2*bins);threshold=F(p[i])/(m*q[i]);mass=F(q[i],bins);ok=u<=threshold
  if ok:accepted[i]+=mass
  rows.append({'proposal':i,'u':str(u),'threshold':str(threshold),'joint_mass':str(mass),'accept':ok})
 rate=sum(accepted);conditional=[v/rate for v in accepted] if rate else None
 return {'rows':rows,'accepted_mass':[str(v) for v in accepted],'accept_probability':str(rate),'conditional':[str(v) for v in conditional] if conditional else None}

def sample(p,q,m,bins,seed,attempts):
 validate(p,q,m,bins)
 if q!=[F(1,len(q))]*len(q) or type(seed) is not int or type(attempts) is not int or not 1<=attempts<=16:raise ValueError('uniform proposal sampler, integer seed and attempts1..16')
 rng=random.Random(seed);trace=[]
 for step in range(attempts):
  i=rng.randrange(len(q));j=rng.randrange(bins);u=F(2*j+1,2*bins);threshold=F(p[i])/(m*q[i]);accept=u<=threshold;trace.append({'attempt':step,'proposal':i,'coin_index':j,'u':str(u),'accept':accept})
  if accept:return {'status':'accepted','value':i,'trace':trace}
 return {'status':'budget_exhausted_without_acceptance','value':None,'trace':trace}

def demo():
 p=[F(1,2),F(1,3),F(1,6)];q=[F(1,3)]*3;m=F(3,2);main=law(p,q,m,6);assert main['conditional']==[str(v) for v in p] and main['accept_probability']=='2/3';counts=[sum(r['accept'] for r in main['rows'] if r['proposal']==i) for i in range(3)];assert counts==[6,4,2]
 looser=law(p,q,2,12);assert looser['conditional']==[str(v) for v in p] and looser['accept_probability']=='1/2'
 wrong_counts=[sum(F(2*j+1,12)<=min(F(1),p[i]/q[i]) for j in range(6)) for i in range(3)];wrong=[F(v,sum(wrong_counts)) for v in wrong_counts];assert wrong_counts==[6,6,3] and wrong==[F(2,5),F(2,5),F(1,5)]
 samples=[sample(p,q,m,6,seed,16) for seed in range(4)];assert samples==[sample(p,q,m,6,seed,16) for seed in range(4)]
 exhausted=next(sample(p,q,m,6,seed,1) for seed in range(100) if sample(p,q,m,6,seed,1)['status'].startswith('budget'))
 rejected=[]
 for label,fn in [('envelope_too_small',lambda:law(p,q,1,6)),('not_normalized',lambda:law([F(1,2)]*3,q,m,6)),('negative_probability',lambda:law([-1,1,1],q,m,6)),('bool_probability',lambda:law([True,0,0],q,m,6)),('nonfinite',lambda:law([float('inf')],q,m,6)),('proposal_zero_target_positive',lambda:law(p,[0,F(1,2),F(1,2)],m,6)),('attempt_budget',lambda:sample(p,q,m,6,1,0))]:
  try:fn()
  except ValueError:rejected.append(label)
  else:raise AssertionError('expected rejection')
 return {'target':[str(v) for v in p],'proposal':[str(v) for v in q],'M':'3/2','finite18_worlds':main,'accepted_counts':counts,'looser_M2_12_coin_bins':looser,'wrong_M1_clipped':{'counts':wrong_counts,'conditional':[str(v) for v in wrong]},'bounded_seeded_sampler_runs':samples,'bounded_no_acceptance_witness':exhausted,'invalid_cases_rejected':rejected,'scope':'finite midpoint-coin adaptation gives exact target only where thresholds align with declared grid; continuous-U theorem is separate. Original bounded uniform-proposal sampler, seeded trace not a proof of IID. No MH previous-state kernel, importance weights, model, network or Opera claim'}
if __name__=='__main__':print(json.dumps(demo(),ensure_ascii=True,indent=2))
