"""One observed training label changes; fixed 1-nearest-neighbor state, features and held-out rows."""
from fractions import Fraction as F
import json
TRAIN=[('R1',F(-3),0),('R2',F(-1),0),('R3',F(1),1),('R4',F(3),1)]
QUERIES=[('Q1',F(-2)),('Q2',F(-1,2)),('Q3',F(1,2)),('Q4',F(2)),('Q5',F(5,2))]
def reference(x):return int(x>=0)
def fit(rows):
    if len({r[0] for r in rows})!=len(rows):raise ValueError('unique source row ids')
    return tuple(rows)
def predict(model,x):
    chosen=min(model,key=lambda r:(abs(r[1]-x),r[0]));return {'nearest_id':chosen[0],'distance':str(abs(chosen[1]-x)),'prediction':chosen[2]}
def evaluate(model):
    return [{'id':qid,'x':str(x),'reference':reference(x),**predict(model,x)} for qid,x in QUERIES]
def demo():
    clean=fit(TRAIN);changed=[(rid,x,1-y if rid=='R3' else y) for rid,x,y in TRAIN];noisy=fit(changed)
    a,b=evaluate(clean),evaluate(noisy);ea=[r['id'] for r in a if r['prediction']!=r['reference']];eb=[r['id'] for r in b if r['prediction']!=r['reference']]
    assert ea==[] and eb==['Q3','Q4']
    assert [(rid,x) for rid,x,y in clean]==[(rid,x) for rid,x,y in noisy]
    assert sum(ya!=yb for (_,_,ya),(_,_,yb) in zip(clean,noisy))==1
    observed_train_errors=[sum(predict(model,x)['prediction']!=y for rid,x,y in model) for model in [clean,noisy]];assert observed_train_errors==[0,0]
    return {'true_reference_rule':'class1 iff x>=0, authored ground truth for this toy world only','clean_train':[[rid,str(x),y] for rid,x,y in clean],'changed_train':[[rid,str(x),y] for rid,x,y in noisy],'changed_label_id':'R3','training_corruption_count':1,'training_rows':4,'k':1,'distance':'absolute 1D distance','ties':'lexically smaller training row id','clean_heldout_results':a,'changed_heldout_results':b,'heldout_error_ids_clean':ea,'heldout_error_ids_changed':eb,'observed_training_errors_both_models':observed_train_errors,'random_label_noise_process_estimated':False,'sklearn_executed':False}
if __name__=='__main__':print(json.dumps(demo(),ensure_ascii=False,indent=2))
