SPB Git

spb/wp29_uqo

Public
3.5 KB · 90 lines python
1"""F5-conf-03: counterexample to 'sum of normals is normal' (proposition A),2and baseline check for the independent case (proposition B).34Run from workspace root:  ~/wp29/venv/bin/python out/analysis.py5Reads only data/; writes out/results.json and out/counterexample.csv deterministically.6"""7import json8import os910import numpy as np11import pandas as pd12from scipy import stats1314ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))15DATA = os.path.join(ROOT, "data")16OUT = os.path.join(ROOT, "out")1718props = pd.read_csv(os.path.join(DATA, "propositions.csv"))19design = pd.read_csv(os.path.join(DATA, "design.csv"))2021data_issues = []22if sorted(props["id"].tolist()) != ["A", "B"]:23    data_issues.append({"issue": "unexpected proposition ids", "handling": "reported"})24dmap = dict(zip(design["parameter"], design["value"]))25seed = int(dmap["seed"])26n = int(dmap["n"])2728# Single generator, fixed draw order: X, then S, then baseline independent Y.29rng = np.random.default_rng(seed)30x = rng.standard_normal(n)31s = rng.choice(np.array([-1.0, 1.0]), size=n)  # Rademacher sign, independent of X32y = s * x                                          # Y = S X ~ N(0,1) by symmetry33z = x + y                                          # = (1+S) X : 0 w.p. 1/2, else 2X3435def ks_vs_fitted_normal(v):36    m, sd = float(np.mean(v)), float(np.std(v, ddof=1))37    return float(stats.kstest(v, "norm", args=(m, sd)).statistic)3839ks_sum = ks_vs_fitted_normal(z)40ks_x = ks_vs_fitted_normal(x)41ks_y = ks_vs_fitted_normal(y)42frac_sum_zero = float(np.mean(z == 0.0))4344# Baseline (proposition B): independent Y' ~ N(0,1), same evaluation rule.45y_ind = rng.standard_normal(n)46ks_sum_indep = ks_vs_fitted_normal(x + y_ind)4748pd.DataFrame({"x": x, "y": y}).to_csv(os.path.join(OUT, "counterexample.csv"),49                                      index=False, float_format="%.17g")50# Re-read so that summary statistics describe exactly the written file.51cx = pd.read_csv(os.path.join(OUT, "counterexample.csv"))52xv, yv = cx["x"].to_numpy(), cx["y"].to_numpy()53zv = xv + yv5455cv = {56    "construction": ("X ~ N(0,1); S independent of X with P(S=1)=P(S=-1)=1/2; Y = S*X. "57                     "Then Y ~ N(0,1) by symmetry of N(0,1), and X+Y = (1+S)X equals 0 with "58                     "probability 1/2 and 2X ~ N(0,4) otherwise (non-degenerate, not normal)."),59    "n": int(len(cx)),60    "seed": seed,61    "mean_x": float(np.mean(xv)), "sd_x": float(np.std(xv, ddof=1)),62    "mean_y": float(np.mean(yv)), "sd_y": float(np.std(yv, ddof=1)),63    "mean_sum": float(np.mean(zv)), "sd_sum": float(np.std(zv, ddof=1)),64    "ks_sum_vs_normal": ks_vs_fitted_normal(zv),65}6667results = {68    "task_id": "F5-conf-03",69    "statement_true": False,70    "counterexample_provided": True,71    "counterexample_values": cv,72    "statement_b_true": True,73    "feasibility": "complete",74    "feasibility_reason": None,75    "data_issues": data_issues,76    "n_input_rows": {"propositions.csv": int(len(props)), "design.csv": int(len(design))},77    "n_analysed": int(len(cx)),78    "random_seed": seed,79    # supplementary diagnostics80    "ks_x_vs_normal": ks_vs_fitted_normal(xv),81    "ks_y_vs_normal": ks_vs_fitted_normal(yv),82    "frac_sum_exactly_zero": float(np.mean(zv == 0.0)),83    "ks_critical_value_alpha_0_01": float(1.628 / np.sqrt(n)),84    "baseline_ks_sum_independent": ks_sum_indep,85}86with open(os.path.join(OUT, "results.json"), "w") as f:87    json.dump(results, f, indent=2)88print(json.dumps({k: results[k] for k in ["statement_true", "statement_b_true"]}))89print("ks_sum_vs_normal =", cv["ks_sum_vs_normal"], "| baseline independent =", ks_sum_indep)90
Files · main
Menu

Theme