"""Standalone synthetic teaching example. Run locally with Python, not in the HTML."""
import json
import numpy as np
import pandas as pd
from scipy.special import expit

def clean(value):
    if isinstance(value, dict): return {str(k):clean(v) for k,v in value.items()}
    if isinstance(value,(list,tuple,np.ndarray)): return [clean(v) for v in value]
    if isinstance(value,(np.integer,)): return int(value)
    if isinstance(value,(float,np.floating)): return float(value) if np.isfinite(value) else None
    if isinstance(value,(np.bool_,)): return bool(value)
    return value

def print_result(result):
    print(json.dumps(clean(result),ensure_ascii=False,allow_nan=False))


def ols_fit(X, y):
    """X excludes intercept. Return intercept, slopes, rank of centered X."""
    X, y = np.asarray(X, float), np.asarray(y, float)
    if X.ndim != 2 or y.shape != (len(X),) or len(X) == 0:
        raise ValueError("Expected nonempty X(n,p) and y(n)")
    if not np.isfinite(X).all() or not np.isfinite(y).all():
        raise ValueError("Resolve nonfinite data first")
    mean = X.mean(axis=0)
    coef, _, rank, _ = np.linalg.lstsq(X-mean, y-y.mean(), rcond=None)
    return float(y.mean()-mean@coef), coef, int(rank)

if __name__ == "__main__":
    X = np.array([[-2.,1.],[-1.,-1.],[0.,2.],[1.,0.],[2.,-2.]])
    y = 3 + X@np.array([2.,-.5])
    intercept, coef, rank = ols_fit(X,y)
    residual = y-intercept-X@coef
    np.testing.assert_allclose(coef,[2,-.5],atol=1e-12)
    np.testing.assert_allclose((X-X.mean(0)).T@residual,0,atol=1e-12)
    duplicated = np.column_stack([X[:,0],2*X[:,0]])
    b2,w2,r2 = ols_fit(duplicated,3+4*X[:,0])
    print_result({"intercept":intercept,"coef":coef,"rank":rank,
        "max_residual":abs(residual).max(),"duplicate_column_rank":r2,
        "duplicate_column_coef":w2})
