from pathlib import Path
from itertools import permutations
import json,hashlib

OUT=Path(__file__).resolve().parent
p=json.loads((OUT/'selection_constraints_inputs.json').read_text());rows=p['ordered_nine_rows'];state=p['held_state']
names=[r['name'] for r in rows];b=[r['SP_b_effective'] for r in rows];L=[r['MT_L'] for r in rows];X=[r['main_LXX_L'] for r in rows];SP=[r['SP_L'] for r in rows];B=[r['SP_birth'] for r in rows];N=state['Noah_primary_birth'];F=state['Flood_start'];k=N-F+1
suffix=lambda v:[sum(v[i:]) for i in range(len(v))]
Q=lambda n:5*((n+2)//5)
u=suffix(b);C=[x+k for x in u];out=[min(l,c) for l,c in zip(L,C)];active=[i for i in range(9) if L[i]>C[i]];inactive=[i for i in range(9) if i not in active]
thresholds=[l-x for l,x in zip(L,u)]
perms=[v for v in permutations([L[i] for i in active]) if all(min(v[j],C[i])==SP[i] for j,i in enumerate(active))]
late_matrix=[[1,1,1,1],[0,0,1,1],[0,0,0,1]];kernel=[1,-1,0,0]
diagnostic_b=b.copy();diagnostic_b[5]+=1;diagnostic_b[6]-=1;diagnostic_u=suffix(diagnostic_b);diagnostic_caps=[x+k for x in diagnostic_u]
U=[[int(j>=i) for j in range(9)] for i in range(9)]
AU=[[int(i in active)*x for x in U[i]] for i in range(9)]
UAU=[[sum(U[i][z]*AU[z][j] for z in range(9)) for j in range(9)] for i in range(9)]
constant=sum(L[i] for i in inactive)+sum(u[i] for i in active)
deaths=[B[i]-out[i]+(1 if i in active else 0) for i in range(9)]
checks={
 'births_from_begetting':[N+x for x in u]==B,
 'capacity_both_forms':C==[x-F+1 for x in B]==[x-state['Flood_close'] for x in B],
 'whole_nine_SP':out==SP,
 'main_LXX_same_SP':[min(x,c) for x,c in zip(X,C)]==SP,
 'all_death_roles':deaths==[r['SP_death'] for r in rows],
 'three_active':active==[5,7,8],
 'three_k_identifications':[SP[i]-u[i] for i in active]==[601]*3,
 'unique_aggregate_parameter':constant==5334 and (sum(SP)-constant)//3==601,
 'late_kernel':all(sum(a*v for a,v in zip(r,kernel))==0 for r in late_matrix),
 'reverse_changed_begettings':[SP[5]-SP[7]-b[6],SP[7]-SP[8],SP[8]-k]==[62,67,52],
 'late_kernel_full_output':[min(l,c) for l,c in zip(L,diagnostic_caps)]==SP and diagnostic_u!=u,
 'four_compatible_assignments':len(perms)==4,
 'rounded_commutation':[Q(x) for x in SP]==[min(Q(l),Q(c)) for l,c in zip(L,C)],
 'rounded_active_same':[i for i in range(9) if Q(L[i])>Q(C[i])]==active,
 'frame215':[(x+215)-(F+215)+1 for x in B]==C,
 'three_local_paths':52+500+100==53+499+100==53+500+99==652,
 'cap_idempotence':[min(x,c) for x,c in zip(out,C)]==out,
 'residual_support':[Q(s)-s-(Q(l)-l) for s,l in zip(SP,L)]==[0,0,0,0,0,0,0,-1,4]
}
d={'status':'preparatory independent calculations, not numbered root steps','input_packet_sha256':hashlib.sha256((OUT/'selection_constraints_inputs.json').read_bytes()).hexdigest(),'source_sha256':p['source_sha256'],'ordered_names':names,'effective_b':b,'Noah_relative_births':u,'SP_births':B,'capacities':C,'MT_baseline':L,'main_LXX_baseline':X,'predicted_SP':out,'deaths_with_source_count_tags':deaths,'active_names':[names[i] for i in active],'slack':[c-v for c,v in zip(C,out)],'MT_reductions':[l-v for l,v in zip(L,out)],'LXX_reductions':[x-v for x,v in zip(X,out)],'MT_preNoah_cumulative_response':suffix([s-l for s,l in zip(SP,L)])+[0],'SP_minus_MT_total':sum(SP)-sum(L),'support_interval_k':{'lower_inclusive':max(thresholds[i] for i in inactive),'upper_exclusive':min(thresholds[i] for i in active),'integer_choices':min(thresholds[i] for i in active)-max(thresholds[i] for i in inactive)},'total_on_fixed_support':{'constant':constant,'slope':len(active),'equation':'total=5334+3*k','observed_total':sum(SP)},'late_age_matrix':late_matrix,'late_age_kernel':kernel,'late_kernel_diagnostic_birth_change':[v-w for v,w in zip(diagnostic_u,u)],'same_output_ancestral_assignments':perms,'response_matrices':{'regular_U':U,'capped_lifespan_AU':AU,'cumulative_UAU':UAU},'rounded_SP':[Q(x) for x in SP],'round_before_boundary_subtraction_diagnostic':[{'name':names[i],'Q_count':Q(C[i]),'Q_B_minus_Q_F_plus1':Q(B[i])-Q(F)+1} for i in active],'rounded_residual_difference':[Q(s)-s-(Q(l)-l) for s,l in zip(SP,L)],'checks':checks,'passed':all(checks.values())}
target=OUT/'selection_constraints_diagnostics.json';target.write_text(json.dumps(d,ensure_ascii=False,indent=2)+'\n');print(json.dumps({'path':str(target),'sha256':hashlib.sha256(target.read_bytes()).hexdigest(),'checks':checks,'passed':d['passed']},indent=2))
