"""FlashMemory educational synthetic data analysis. Python 3 standard library only.
Download this file and the four CSVs into one directory; run: python3 analyze.py
No corporate data, production recipes, trained AI models or verified root causes.
"""
import csv,json,math
from pathlib import Path
from statistics import mean
ROOT=Path(__file__).resolve().parent

def read(name):
    with (ROOT/name).open(newline='',encoding='utf-8') as f:
        return list(csv.DictReader(f))

def analyze():
    rows=read('doe.csv');screen=[r for r in rows if r['stage']=='screen']
    effects={}
    for name,cols in [('A',['factor_a']),('B',['factor_b']),('AB',['factor_a','factor_b'])]:
        groups={-1:[],1:[]}
        for r in screen:
            sign=math.prod(int(r[c]) for c in cols);groups[sign].append(float(r['yield_pct']))
        effects[name]=round(mean(groups[1])-mean(groups[-1]),6)
    doe={'effects_pp':effects,'confirmation_mean_pct':mean(float(r['yield_pct']) for r in rows if r['stage']=='confirmation')}
    pe=read('pe.csv');n=sum(int(r['tested_units']) for r in pe);passed=sum(int(r['first_pass']) for r in pe);recovered=sum(int(r['recovered_units']) for r in pe)
    for r in pe:
        assert int(r['first_pass'])+int(r['bin_a'])+int(r['bin_b'])==int(r['tested_units'])
        assert 0<=int(r['recovered_units'])<=int(r['retested_units'])<=int(r['tested_units'])-int(r['first_pass'])
    pe_result={'first_yield_pct':100*passed/n,'cumulative_yield_pct':100*(passed+recovered)/n,'site_fail_pct':{r['site']:100*(int(r['tested_units'])-int(r['first_pass']))/int(r['tested_units']) for r in pe}}
    eq=read('equipment.csv');baseline=[r for r in eq if int(r['minute'])<20];after=[r for r in eq if int(r['minute'])>=20]
    eq_result={'baseline_sensor_mean_kpa':mean(float(r['sensor_kpa']) for r in baseline),'after_sensor_mean_kpa':mean(float(r['sensor_kpa']) for r in after),'after_reference_mean_kpa':mean(float(r['reference_kpa']) for r in after),'after_supply_mean_kpa':mean(float(r['supply_kpa']) for r in after)}
    w=read('wafer-spc.csv');spc=[r for r in w if r['pattern']=='spc'];base=spc[:20]
    pbar=sum(int(r['failed_dies']) for r in base)/sum(int(r['tested_dies']) for r in base)
    n=100;ucl=pbar+3*math.sqrt(pbar*(1-pbar)/n);lcl=max(0,pbar-3*math.sqrt(pbar*(1-pbar)/n))
    abnormal=[int(r['time']) for r in spc if int(r['failed_dies'])/int(r['tested_dies'])>ucl or int(r['failed_dies'])/int(r['tested_dies'])<lcl]
    patterns={name:{r['region']:100*int(r['failed_dies'])/int(r['tested_dies']) for r in w if r['pattern']==name} for name in ['center','edge','ring','cluster']}
    return {'doe':doe,'pe':pe_result,'equipment':eq_result,'wafer_spc':{'baseline_p':pbar,'lcl':lcl,'ucl':ucl,'out_of_control_times':abnormal,'region_fail_pct':patterns},'notice':'Synthetic educational observations; no verified root cause or production optimum.'}

if __name__=='__main__':
    print(json.dumps(analyze(),ensure_ascii=False,indent=2))
