#!/usr/bin/env python3
from __future__ import annotations
import json, math
from common import load_manifest, write_receipt
TAU=2*math.pi

def sep(a,b):
    d=abs((a-b)%TAU); return min(d,TAU-d)
def sgnproj(az,axis): return 1 if math.cos(az-axis)>=0 else -1
def rho(az,x,y):
    phi=sep(x,y); c=math.cos(phi); same=sgnproj(az,x)==sgnproj(az,y)
    return (1+c)/(8*(math.pi-phi)) if same else (1-c)/(8*phi)
def breaks(*axes):
    xs=[0.0,TAU]
    for a in axes:
        xs.extend(((a+math.pi/2)%TAU,(a-math.pi/2)%TAU))
    return sorted(set(xs))
def joint(phi):
    x=0.0; y=phi; out={(1,1):0.0,(1,-1):0.0,(-1,1):0.0,(-1,-1):0.0}
    bs=breaks(x,y)
    for lo,hi in zip(bs,bs[1:]):
        mid=(lo+hi)/2; w=2*(hi-lo)*rho(mid,x,y)
        out[(sgnproj(mid,x),-sgnproj(mid,y))]+=w
    return out
def l1_density(x,y,xp,yp):
    bs=breaks(x,y,xp,yp); total=0.0
    for lo,hi in zip(bs,bs[1:]):
        mid=(lo+hi)/2; total+=2*(hi-lo)*abs(rho(mid,x,y)-rho(mid,xp,yp))
    return total

def target_joint(phi,a,b): return 0.25*(1-a*b*math.cos(phi))
def golden_max(f,a,b,iters=96):
    gr=(math.sqrt(5)-1)/2; c=b-gr*(b-a); d=a+gr*(b-a); fc=f(c); fd=f(d)
    for _ in range(iters):
        if fc>fd: b,d,fd=d,c,fc; c=b-gr*(b-a); fc=f(c)
        else: a,c,fc=c,d,fd; d=a+gr*(b-a); fd=f(d)
    x=(a+b)/2; return x,f(x)

def main():
    m=load_manifest('hall-singlet-v1.json'); phis=[.15*math.pi,.25*math.pi,math.pi/3,.5*math.pi,.75*math.pi,.9*math.pi]
    cases=[]; worst_p=worst_corr=worst_marg=0.0
    for phi in phis:
        p=joint(phi); targets={k:target_joint(phi,*k) for k in p}
        perr=max(abs(p[k]-targets[k]) for k in p); corr=sum(a*b*v for (a,b),v in p.items())
        cerr=abs(corr+math.cos(phi)); ma={a:sum(v for (aa,_),v in p.items() if aa==a) for a in (-1,1)}; mb={b:sum(v for (_,bb),v in p.items() if bb==b) for b in (-1,1)}
        merr=max([abs(v-.5) for v in ma.values()]+[abs(v-.5) for v in mb.values()])
        worst_p=max(worst_p,perr); worst_corr=max(worst_corr,cerr); worst_marg=max(worst_marg,merr)
        cases.append({'phi_rad':phi,'joint':{f'{a},{b}':v for (a,b),v in p.items()},'target':{f'{a},{b}':v for (a,b),v in targets.items()},'correlation':corr,'marginal_A':ma,'marginal_B':mb,'max_probability_error':perr})
    f=lambda phi:l1_density(0.0,phi,math.pi/2,math.pi/2+phi)
    phi_star,M=golden_max(f,.5,1.2); target=m['erratum_target']['M_singlet']; merrM=abs(M-target)
    ok=worst_p<=m['tolerances']['probability'] and worst_corr<=m['tolerances']['correlation'] and worst_marg<=m['tolerances']['marginal'] and merrM<=m['tolerances']['measurement_dependence']
    receipt={'schema':'classical-reconstruction-receipt/v1','benchmark_id':m['benchmark_id'],'ok':ok,
      'ontology_contract_sha256':m['ontology_contract_sha256'],'cases':cases,
      'worst_errors':{'joint_probability':worst_p,'correlation':worst_corr,'marginal':worst_marg},
      'measurement_dependence':{'M_numeric':M,'phi_star_rad':phi_star,'phi_star_over_pi':phi_star/math.pi,'erratum_target':target,'absolute_error':merrM,'original_incorrect_value':m['erratum_target']['original_incorrect_M']},
      'verified_properties':['deterministic local response functions','setting-dependent hidden-state density','singlet joint probabilities','singlet correlation','one-half local marginals / no-signalling at tested settings'],
      'physical_mechanism_status':'not supplied by this adapter','q1_q5':m['q1_q5'],'scope_exclusion':m['scope_exclusion'],'sources':m['sources']}
    write_receipt('hall-singlet-v1.json',receipt); return receipt
if __name__=='__main__': print(json.dumps(main(),indent=2))
