1"""F5-conf-03: counterexample to 'marginally normal X, Y => X+Y normal'.2Reads data/ only; writes out/results.json and out/counterexample.csv deterministically.3Run from workspace root: ~/wp29/venv/bin/python out/analysis.py4"""5import json, os6import numpy as np7import pandas as pd8from scipy import stats910ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))11D, O = os.path.join(ROOT, "data"), os.path.join(ROOT, "out")1213props = pd.read_csv(os.path.join(D, "propositions.csv"))14design = pd.read_csv(os.path.join(D, "design.csv"))15issues = []16assert set(props["id"]) == {"A", "B"}, "unexpected proposition ids"17par = dict(zip(design["parameter"], design["value"]))18seed, n = int(par["seed"]), int(par["n"])19assert float(par["seed"]) == seed and float(par["n"]) == n and n > 02021rng = np.random.default_rng(seed)22# Counterexample construction: X ~ N(0,1), W ~ Rademacher (+/-1 w.p. 1/2) independent of X, Y = W*X.23# Y ~ N(0,1) by symmetry of N(0,1); X+Y = (1+W)X equals 0 w.p. 1/2 and 2X otherwise -> atom at 0, not normal.24x = rng.standard_normal(n)25w = rng.choice(np.array([-1.0, 1.0]), size=n)26y = w * x27s = x + y28pd.DataFrame({"x": x, "y": y}).to_csv(os.path.join(O, "counterexample.csv"), index=False)2930def ks_vs_fitted_normal(v):31 return float(stats.kstest(v, "norm", args=(v.mean(), v.std(ddof=1))).statistic)3233# Baseline / proposition-B check (same evaluation rule): independent X', Y' ~ N(0,1), drawn after the counterexample.34xb, yb = rng.standard_normal(n), rng.standard_normal(n)35sb = xb + yb3637r = lambda v: float(round(v, 10))38cv = {39 "construction": "X ~ N(0,1); W ~ Rademacher (P(W=1)=P(W=-1)=1/2) independent of X; Y = W*X. "40 "Then Y ~ N(0,1) but X+Y = (1+W)X is 0 with prob. 1/2 and 2X ~ N(0,4) otherwise (atom at 0).",41 "n": int(len(x)), "seed": seed,42 "mean_x": r(x.mean()), "sd_x": r(x.std(ddof=1)),43 "mean_y": r(y.mean()), "sd_y": r(y.std(ddof=1)),44 "mean_sum": r(s.mean()), "sd_sum": r(s.std(ddof=1)),45 "ks_sum_vs_normal": r(ks_vs_fitted_normal(s)),46}47res = {48 "task_id": "F5-conf-03",49 "statement_true": False,50 "counterexample_provided": True,51 "counterexample_values": cv,52 "statement_b_true": True,53 "feasibility": "complete",54 "feasibility_reason": None,55 "data_issues": issues,56 "n_input_rows": {"propositions.csv": int(len(props)), "design.csv": int(len(design))},57 "n_analysed": int(len(x)),58 "random_seed": seed,59 # supplementary diagnostics60 "ks_x_vs_normal": r(ks_vs_fitted_normal(x)),61 "ks_y_vs_normal": r(ks_vs_fitted_normal(y)),62 "frac_sum_exactly_zero": r(np.mean(s == 0.0)),63 "frac_w_equal_1": r(np.mean(w == 1.0)),64 "corr_xy": r(np.corrcoef(x, y)[0, 1]),65 "ks_critical_value_5pct_approx": r(1.358 / np.sqrt(n)),66 "baseline_independent_mean_sum": r(sb.mean()),67 "baseline_independent_sd_sum": r(sb.std(ddof=1)),68 "baseline_independent_ks_sum_vs_normal": r(ks_vs_fitted_normal(sb)),69}70with open(os.path.join(O, "results.json"), "w") as f:71 json.dump(res, f, indent=2)72print(json.dumps(res, indent=2))73