"""Authored two-column chained deterministic OLS mean imputation; one completion, not multiple/posterior imputation."""
import math,json
DATA=[[1.,4.],[2.,None],[None,10.],[4.,13.],[5.,16.]]
def ols(xs,ys):
    if len(xs)<2:raise ValueError('at least two observed targets')
    xm=math.fsum(xs)/len(xs);ym=math.fsum(ys)/len(ys);den=math.fsum((x-xm)**2 for x in xs)
    if den<=0:raise ValueError('nonconstant predictor required')
    slope=math.fsum((x-xm)*(y-ym) for x,y in zip(xs,ys))/den
    return ym-slope*xm,slope
def complete(original,max_rounds=40,tolerance=1e-9):
    mask=[[v is None for v in r] for r in original];means=[]
    for j in range(2):
        seen=[r[j] for r in original if r[j] is not None]
        if not seen:raise ValueError('entire column missing')
        means.append(math.fsum(seen)/len(seen))
    work=[[means[j] if mask[i][j] else v for j,v in enumerate(r)] for i,r in enumerate(original)]
    initial=[r.copy() for r in work];trace=[];converged=False
    for iteration in range(max_rounds):
        previous=[r.copy() for r in work];steps=[]
        for j in range(2):
            other=1-j;known=[i for i in range(len(work)) if not mask[i][j]]
            intercept,slope=ols([work[i][other] for i in known],[original[i][j] for i in known]);updated=[]
            for i in range(len(work)):
                if mask[i][j]:work[i][j]=intercept+slope*work[i][other];updated.append(i)
            steps.append({'target_column':j,'fit_observed_target_rows':known,'intercept':intercept,'slope':slope,'updated_missing_rows':updated})
        delta=max(abs(work[i][j]-previous[i][j]) for i in range(len(work)) for j in range(2))
        assert all(work[i][j]==original[i][j] for i in range(len(work)) for j in range(2) if not mask[i][j])
        trace.append({'round':iteration+1,'regression_steps':steps,'completed_matrix':[r.copy() for r in work],'max_absolute_change':delta})
        if delta<tolerance:converged=True;break
    return {'original_matrix':original,'original_missing_mask':mask,'initial_column_means':means,'initial_filled_matrix':initial,'column_order':[0,1],'max_rounds':max_rounds,'tolerance_absolute':tolerance,'trace':trace,'converged_under_this_stopping_rule':converged,'completed_matrix':work,'observed_cells_preserved':True}
def demo():
    result=complete(DATA);assert result['converged_under_this_stopping_rule']
    assert abs(result['completed_matrix'][1][1]-7)<1e-7 and abs(result['completed_matrix'][2][0]-3)<1e-7
    try:complete([[None,1.],[None,2.]])
    except ValueError:entire_missing_rejected=True
    else:raise AssertionError('all missing accepted')
    result.update(entire_missing_column_rejected=entire_missing_rejected,hidden_authored_reference_only_used_after_completion={'row1_col1':7,'row2_col0':3},references_used_in_regression_fit=False,single_completion_not_posterior_or_multiple_imputation=True,heldout_transform_sequence_or_downstream_accuracy_implemented=False,sklearn_IterativeImputer_executed=False)
    return result
if __name__=='__main__':print(json.dumps(demo(),ensure_ascii=False,indent=2))
