"""Offline arithmetic reanalysis of published Table 1 means. Python standard library only."""
import csv,json,math,statistics
from pathlib import Path
from plot_utils import svg,text,line,rect,circle
BASE=Path(__file__).resolve().parent

def analyze():
    rows=list(csv.DictReader((BASE/'table1.csv').open()))
    assert len(rows)==9 and len({(r['dataset'],r['size']) for r in rows})==9
    for r in rows:
        for c in ['parameter_fraction','support_score_s','support_grad_s','key_score_s','key_grad_s']:r[c]=float(r[c])
        assert all(r[c]>0 for c in ['support_score_s','support_grad_s','key_score_s','key_grad_s'])
        r['support_grad_over_score']=r['support_grad_s']/r['support_score_s']
        r['key_grad_over_score']=r['key_grad_s']/r['key_score_s']
        r['support_over_key_grad']=r['support_grad_s']/r['key_grad_s']
        r['key_grad_us_per_query_equivalent']=r['key_grad_s']/4096*1e6
        r['support_grad_us_per_query_equivalent']=r['support_grad_s']/4096*1e6
        r['grad_batch_saving_ms']=(r['support_grad_s']-r['key_grad_s'])*1000
        # Amdahl arithmetic: equal downstream cost, neither equal recall nor deployment measured.
        r['combined_ratios']={str(ms):(r['support_grad_s']+ms/1000)/(r['key_grad_s']+ms/1000) for ms in [0,5,20,100]}
        for ratio in r['combined_ratios'].values(): assert 1<ratio<=r['support_over_key_grad']
    nonmonotonic=[]
    for ds in dict.fromkeys(r['dataset'] for r in rows):
        subset=[r for r in rows if r['dataset']==ds]
        for col in ['support_score_s','support_grad_s','key_score_s','key_grad_s']:
            if subset[2][col]<subset[1][col]:nonmonotonic.append({'dataset':ds,'column':col,'M_to_L_ratio':subset[2][col]/subset[1][col]})
    result={'evidence':'published batch timing means, not new model runs','rows':rows,'support_grad_over_score_range':[min(r['support_grad_over_score'] for r in rows),max(r['support_grad_over_score'] for r in rows)],'key_grad_over_score_range':[min(r['key_grad_over_score'] for r in rows),max(r['key_grad_over_score'] for r in rows)],'support_over_key_grad_range':[min(r['support_over_key_grad'] for r in rows),max(r['support_over_key_grad'] for r in rows)],'median_support_over_key_grad':statistics.median(r['support_over_key_grad'] for r in rows),'nonmonotonic_pairs':nonmonotonic}
    assert len(nonmonotonic)==8
    (BASE/'results.json').write_text(json.dumps(result,indent=2)+'\n')
    return result

def draw(result):
    rows=result['rows'];body=''
    for val in [1,1.25,1.5,1.75,2,2.25]:
        x=245+(val-1)/1.25*565;body+=line(x,107,x,455)+text(x,482,f'{val:g}×',anchor='middle')
    for i,r in enumerate(rows):
        y=121+i*37;body+=text(36,y+5,r['dataset']+' · '+r['size'])
        x1=245+(r['key_grad_over_score']-1)/1.25*565;x2=245+(r['support_grad_over_score']-1)/1.25*565
        body+=line(x1,y,x2,y,'#929d90',3)+circle(x1,y,5,'#394d3c')+circle(x2,y,5,'#b37951')+text(x2+10,y+5,f"{r['support_grad_over_score']:.2f}×")
    body+=circle(290,512,5,'#394d3c')+text(301,517,'KeyNet')+circle(440,512,5,'#b37951')+text(451,517,'SupportNet')
    (BASE/'gradient-overhead.svg').write_text(svg('A predicted key changes the cost of the interface','Gradient time / score time within each published configuration. Batch = 4096; 100-run means.',body,550))
    body=''
    for v in [1,1.25,1.5,1.75,2,2.25]:
        y=400-(v-1)/1.25*280;body+=line(100,y,840,y)+text(84,y+4,f'{v:g}×',anchor='end')
    colors=['#6f836f','#b37951','#374f52']
    for j,ds in enumerate(['Quora','Natural Questions','HotpotQA']):
        r=next(x for x in rows if x['dataset']==ds and x['size']=='M');pts=[]
        for ms in range(101):
            ratio=(r['support_grad_s']+ms/1000)/(r['key_grad_s']+ms/1000)
            x=120+ms/100*690;y=400-(ratio-1)/1.25*280;pts.append(f'{x},{y}')
        body+='<polyline fill="none" stroke="'+colors[j]+'" stroke-width="2" points="'+' '.join(pts)+'"/>'
        for ms in [0,5,20,100]:
            x=120+ms/100*690;y=400-(r['combined_ratios'][str(ms)]-1)/1.25*280
            body+=circle(x,y,5,colors[j])
        body+=text(80+j*280,465,ds+' · M',fill=colors[j])
    for ms in [0,20,40,60,80,100]:body+=text(120+ms/100*690,428,str(ms)+' ms',anchor='middle')
    body+=text(470,502,'Assumed equal downstream time per batch',anchor='middle',cls='sub')
    (BASE/'downstream-sensitivity.svg').write_text(svg('A twofold component ratio is not a twofold pipeline gain','Calculated sensitivity using M-size published means; downstream time is an assumption, not a measurement.',body,530))

if __name__=='__main__':
    result=analyze();draw(result)
    print(json.dumps({k:v for k,v in result.items() if k not in ['rows','nonmonotonic_pairs']},indent=2));print('Assertions passed. Wrote results.json and two SVG figures.')
