#!/usr/bin/env python3
"""Synthetic NAND TLC state/classification exercise; no company data or device model.
Python 3 standard library only. Run beside nand-vth-synthetic.csv.
"""
import csv
import json
import statistics
from collections import Counter, defaultdict
from pathlib import Path

path=Path(__file__).with_name("nand-vth-synthetic.csv")
with path.open(encoding="utf-8",newline="") as f:
    rows=list(csv.DictReader(f))
assert len(rows)==256, "128 samples for each of two fictional conditions"
all_ids=set()
groups=defaultdict(list)
for row in rows:
    condition=row["condition"]
    state=int(row["state_id"])
    value=float(row["normalized_vth"])
    assert condition in {"Reference","Shifted"} and 0<=state<=7
    assert row["sample_id"] not in all_ids
    all_ids.add(row["sample_id"])
    groups[condition].append((state,value))
assert all(len(groups[condition])==128 for condition in ("Reference","Shifted"))

# Fixed 7 teaching decision boundaries at 0.5,1.5,...6.5 in arbitrary units.
# State symbol mistakes are NOT equivalent to TLC bit errors; no Gray code specified.
def decoded(value):
    return max(0,min(7,int(value+0.5)))

summary={"dataset":"SYNTHETIC_TRAINING_ONLY",
 "reference_boundaries_normalized_units":[i+0.5 for i in range(7)],
 "states_per_cell":8,
 "bits_per_cell_for_TLC":3,
 "warning":"Simplified symbol classification with fixed ideal boundaries. These are dimensionless invented scores, not true voltage thresholds, product RBER, read-retry or ECC performance.",
 "conditions":{}}
for condition in ("Reference","Shifted"):
    data=groups[condition]
    errors=[(true,decoded(v)) for true,v in data if decoded(v)!=true]
    state_counts=Counter(true for true,_ in data)
    assert all(state_counts[s]==16 for s in range(8))
    means={str(s):round(statistics.mean(v for t,v in data if t==s),4) for s in range(8)}
    boundary_near=sum(any(abs(v-b)<=0.10 for b in summary["reference_boundaries_normalized_units"]) for _,v in data)
    summary["conditions"][condition]={
     "cells":len(data),"state_counts":{str(s):state_counts[s] for s in range(8)},
     "wrong_state_count":len(errors),
     "wrong_state_fraction":round(len(errors)/len(data),6),
     "state_mean_normalized":means,
     "cells_near_boundary_within_0_10_normalized_units":boundary_near,
     "confusions":{f"{a}->{b}":count for (a,b),count in sorted(Counter(errors).items())}
    }
assert summary["conditions"]["Reference"]["wrong_state_count"]==0
assert summary["conditions"]["Shifted"]["wrong_state_count"]==35
assert summary["conditions"]["Reference"]["state_mean_normalized"]["0"]==0.0
assert summary["conditions"]["Shifted"]["state_mean_normalized"]["0"]==-0.12
print(json.dumps(summary,ensure_ascii=False,indent=2))
