"""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 pca_fit(X, components):
    X = np.asarray(X,float)
    if X.ndim!=2 or len(X)<2 or not 1<=components<=min(X.shape):
        raise ValueError("Invalid data or component count")
    mean = X.mean(0)
    _, singular, vt = np.linalg.svd(X-mean,full_matrices=False)
    variance = singular**2/(len(X)-1)
    ratio = variance/variance.sum() if variance.sum()>0 else np.zeros_like(variance)
    return mean, vt[:components].T, ratio[:components]

if __name__ == "__main__":
    from sklearn.linear_model import Ridge
    rng=np.random.default_rng(42)
    X=rng.normal(size=(1200,2));X[:,0]*=10
    y=2*X[:,1]+rng.normal(0,.2,len(X))
    tr,te=np.arange(800),np.arange(800,1200)
    mean,directions,ratio=pca_fit(X[tr],1)
    one=Ridge(alpha=1).fit((X[tr]-mean)@directions,y[tr])
    full=Ridge(alpha=1).fit(X[tr],y[tr])
    one_mse=np.mean((one.predict((X[te]-mean)@directions)-y[te])**2)
    full_mse=np.mean((full.predict(X[te])-y[te])**2)
    np.testing.assert_allclose(directions.T@directions,np.eye(1),atol=1e-12)
    print_result({"explained_ratio":ratio,"one_component_mse":one_mse,
        "full_features_mse":full_mse,"direction":directions[:,0]})
