"""Generate every model table in the report directly from the results files, so no number is copied by hand. -> report/tables_v4.md Usage: python3 make_tables.py""" import json import os import numpy as np HERE = os.path.dirname(os.path.abspath(__file__)) MOD = os.path.join(HERE, "..", "models") R = json.load(open(os.path.join(MOD, "integrate4_results.json"))) CL, S = R["classes"], R["schools"] SHORT = {"site": "Earth given", "ssa_all": "typical, all time", "ssa_now": "typical, to date", "ssa_obs": "typical observer", "sia": "SIA"} NAMES = {"empty_universe": "Nobody else in the observable universe", "rare": "Others exist, none ever in our Galaxy", "en_route": "Expanders hold >1% of the universe, not here yet", "stuck": "Civilisations arose in the Galaxy, none became a sustained expander", "unnoticed": "Galaxy settled by low-footprint expanders, not evident", "hidden": "Galaxy settled, deliberately hidden", "excluded": "Galaxy claimed by evident settlers (we are in a pocket)"} out = [] P = out.append f2 = lambda v: f"{v:.2f}" f3 = lambda v: f"{v:.3f}" def table(head, rows): P("| " + " | ".join(head) + " |"); P("|" + "|".join(["---"] + ["---:"] * (len(head) - 1)) + "|") for r in rows: P("| " + " | ".join(str(x) for x in r) + " |") P("") b = R["base"] fam3 = lambda p: (p["empty_universe"] + p["rare"], p["stuck"], p["en_route"] + p["unnoticed"] + p["hidden"] + p["excluded"]) P(f"# Model {R.get('model_version', '4')} tables (generated by make_tables.py from models/integrate4_results.json)\n") P(f"Samples per run: {R['n_per_run']:,}; base columns pool {R.get('n_seeds', 8)} runs. Monte Carlo standard errors on class probabilities: " + ", ".join(f"{SHORT[s]} {max(R['mc_sd'][s].values()):.4f}" for s in R["mc_sd"]) + " (largest class). " "The self-indication (SIA) column rests on far fewer effective samples and is good to about 5 points.\n") P("## A0. The three answers\n") table(["Answer", "Prior"] + [SHORT[s] for s in S], [[n, f3(fam3(b["prior"])[i])] + [f3(fam3(b["schools"][s]["posterior"])[i]) for s in S] for i, n in enumerate(["Nobody here, nobody coming (empty universe + none in our Galaxy)", "They arise and never spread", "Someone did spread (on the way, unnoticed, hidden, or evident)"])] + [["Same three among non-evident explanations only: " + n, f3(fam3({**b["prior"], "excluded": 0})[i] / (1 - b["prior"]["excluded"]))] + [f3(fam3({**b["schools"][s]["posterior"], "excluded": 0})[i] / (1 - b["schools"][s]["posterior"]["excluded"])) for s in S] for i, n in enumerate(["nobody", "never spread", "spread"])]) P("## A. Posterior by explanation and by convention\n") table(["Explanation", "Prior"] + [SHORT[s] for s in S], [[NAMES[c], f3(b["prior"][c])] + [f3(b["schools"][s]["posterior"][c]) for s in S] for c in CL]) ps = b["prior_stats"] rows = [["No other civilisation ever in the Galaxy", f3(ps["p_no_other_ever_in_galaxy"])] + [f3(b["schools"][s]["p_no_other_ever_in_galaxy"]) for s in S], ["... of which: no life anywhere else in the Galaxy", f3(ps["sub"]["alone_sterile"])] + [f3(b["schools"][s]["sub"]["alone_sterile"]) for s in S], ["... of which: life elsewhere, no other technology", f3(ps["sub"]["alone_inhabited"])] + [f3(b["schools"][s]["sub"]["alone_inhabited"]) for s in S], ["Stuck: a universal barrier to expansion", f3(ps["sub"]["stuck_barrier"])] + [f3(b["schools"][s]["sub"]["stuck_barrier"]) for s in S], ["Stuck: no barrier, 100+ civilisations, none expanded", f3(ps["sub"]["stuck_many"])] + [f3(b["schools"][s]["sub"]["stuck_many"]) for s in S], ["Stuck: no barrier, fewer than 100 civilisations", f3(ps["sub"]["stuck_few"])] + [f3(b["schools"][s]["sub"]["stuck_few"]) for s in S], ["Unnoticed: low footprint forced on everyone", f3(ps["sub"]["unnoticed_cc"])] + [f3(b["schools"][s]["sub"]["unnoticed_cc"]) for s in S], ["Unnoticed: mixed lineages, all happen to be discreet", f3(ps["sub"]["unnoticed_mixed"])] + [f3(b["schools"][s]["sub"]["unnoticed_mixed"]) for s in S], ["Nobody (three-answer sense): no life anywhere else in the Galaxy", f3(ps["sub"]["nobody_sterile"])] + [f3(b["schools"][s]["sub"]["nobody_sterile"]) for s in S], ["Nobody (three-answer sense): life elsewhere, no other technology", f3(ps["sub"]["nobody_inhabited"])] + [f3(b["schools"][s]["sub"]["nobody_inhabited"]) for s in S], ["Nobody and a universal barrier exists", f3(ps["sub"]["nobody_barrier"])] + [f3(b["schools"][s]["sub"]["nobody_barrier"]) for s in S], ["No other ever arose here, but the Galaxy is settled from outside", f3(ps["sub"]["alone_settled"])] + [f3(b["schools"][s]["sub"]["alone_settled"]) for s in S], ["Life starts easily and nobody", f3(ps["sub"]["fast_nobody"])] + [f3(b["schools"][s]["sub"]["fast_nobody"]) for s in S], ["Life starts easily and never spread", f3(ps["sub"]["fast_stuck"])] + [f3(b["schools"][s]["sub"]["fast_stuck"]) for s in S], ["A home-grown civilisation other than us exists in the Galaxy now", "-"] + [f3(b["schools"][s]["p_other_now_in_galaxy"]) for s in S], ["Anyone else (home-grown or settler) is in the Galaxy now", "-"] + [f3(b["schools"][s]["p_anyone_now_in_galaxy"]) for s in S], ["Nobody has yet arisen in the region reachable at 0.1c", "-"] + [f3(b["schools"][s]["p_nobody_in_reach"]) for s in S], ["Nobody has yet arisen in the region reachable at c", "-"] + [f3(b["schools"][s]["p_nobody_in_reach_c"]) for s in S], ["A universal barrier to expansion exists", f3(ps["p_barrier"])] + [f3(b["schools"][s]["p_barrier"]) for s in S], ["P(p_exp < 1e-6)", f3(ps["p_pexp_lt_1e6"])] + [f3(b["schools"][s]["p_pexp_lt_1e6"]) for s in S], ["Mean chance a civilisation becomes an evident sustained expander", "-"] + [f"{b['schools'][s]['mean_p_exp_evident']:.2g}" for s in S], ["Life starts easily (lambda >= 1)", f3(ps["p_fast"])] + [f3(b["schools"][s]["p_fast"]) for s in S], ["No hard steps (gated)", f3(ps["p_gated"])] + [f3(b["schools"][s]["p_gated"]) for s in S], ["Mean number of hard steps", f2(ps["mean_hard_steps"])] + [f2(b["schools"][s]["mean_hard_steps"]) for s in S], ["Effective sample size", "-"] + [f"{b['schools'][s]['ess']:,.0f}" for s in S]] P("## B. Headline quantities and splits\n") table(["Quantity", "Prior"] + [SHORT[s] for s in S], rows) P("Mean likelihood of the observations by explanation (Earth-given column): " + ", ".join(f"{NAMES[c].split(',')[0][:38]} {b['schools']['site']['mean_like'][c]:.3f}" for c in CL) + ".\n") q = ps["log10_p_civ_per_planet_q"]; qe = ps["log10_p_exp_q"]; qn = ps["log10_N_ever_q"] P("Implied priors (5%, 25%, 50%, 75%, 95%): log10 P(technological civilisation per rocky habitable-zone planet of a Sun-like star) " + ", ".join(f"{q[k]:.1f}" for k in q) + "; log10 p_exp " + ", ".join(("barrier" if qe[k] <= -39 else f"{qe[k]:.1f}") for k in qe) + "; log10 expected civilisations ever in the Galaxy " + ", ".join(f"{qn[k]:.1f}" for k in qn) + ".\n") P("## C. What each observation contributes (Shapley values over all orderings)\n") T = ("early", "late", "local", "surveys") TN = {"early": "Life started early on Earth", "late": "We arrived late in Earth's window", "local": "Nobody is visibly here", "surveys": "Galaxy surveys and radio searches"} SH = R["shapley"] for key, lab in (("alone", "P(no other civilisation ever arose in the Galaxy)"), ("nobody", "P(nobody here, nobody coming)")): sh, lo = SH[key], SH["logodds_" + key] table([lab + ", Earth given", "Shapley share (points)", "lowest over orders", "highest over orders", "odds multiplied by"], [["Before the evidence", f3(sh["start"]), "", "", ""]] + [[TN[t], f"{sh['contributions'][t]:+.3f}", f"{sh['lowest'][t]:+.3f}", f"{sh['highest'][t]:+.3f}", f"{np.exp(lo['contributions'][t]):.2f}"] for t in T] + [["After all the evidence", f3(sh["end"]), "", "", f"{np.exp(lo['end'] - lo['start']):.2f} in total"]]) el = R["early_life_factor"] P(f"Early life as evidence for an easy origin, as a likelihood ratio (easy : hard): {el['alone']:.2f} alone, {el['after_late']:.2f} given our late arrival, {el['after_all']:.2f} given everything else. " f"P(life starts easily): prior {ps['p_fast']:.3f}, posterior {b['schools']['site']['p_fast']:.3f}.\n") ab = R["ablation"] seq = ["prior", "early", "early+late", "early+late+local", "early+late+local+surveys"] P("Sequential (one ordering) and single observations, Earth given:\n") table(["Observations included", "no other ever", "nobody", "never spread", "evident settlement"], [[k, f3(ab[k]["schools"]["site"]["p_no_other_ever_in_galaxy"]), f3(fam3(ab[k]["schools"]["site"]["posterior"])[0]), f3(ab[k]["schools"]["site"]["posterior"]["stuck"]), f3(ab[k]["schools"]["site"]["posterior"]["excluded"])] for k in seq + ["local", "surveys", "early+late+surveys"]]) P("## D. Camps: the same evidence under each school's priors\n") rows = [] for name, c in R["camps"].items(): s1 = c["schools"]["site"]; f0 = fam3(c["prior"]); f1 = fam3(s1["posterior"]) rows.append([name, f2(f0[0]), f2(f1[0]), f2(f1[1]), f2(f1[2]), f2(c["prior_stats"]["p_no_other_ever_in_galaxy"]), f2(s1["p_no_other_ever_in_galaxy"]), f2(fam3(c["schools"]["ssa_all"]["posterior"])[0]), f2(fam3(c["schools"]["ssa_obs"]["posterior"])[0]), f2(c["prior_stats"]["p_fast"]), f2(s1["p_fast"])]) table(["Camp", "nobody before", "nobody", "never spread", "spread", "no other ever, before", "no other ever", "nobody (typical, all time)", "nobody (typical observer)", "P(easy life) before", "after"], rows) P("Columns 2 to 7 and the last two are the Earth-given convention.\n") P("## E. One prior at a time\n") LN = {"w_fast": "P(life starts easily)", "q_barrier": "P(universal barrier to expansion)", "q_cc": "P(low footprint forced on everyone)", "p_stealth": "P(everyone hides)", "obs_R": "observers per expander (typical-observer column)", "q_ig": "P(expansion can cross between galaxies)"} for key, lst in R["levers"].items(): col = "ssa_obs" if key == "obs_R" else "site" table([LN[key], "nobody before", "nobody", "never spread before", "never spread", "unnoticed before", "unnoticed", "hidden", "no other ever"], [[f"{d['value']:g}", f2(fam3(d["prior"])[0]), f2(fam3(d["schools"][col]["posterior"])[0]), f2(d["prior"]["stuck"]), f2(d["schools"][col]["posterior"]["stuck"]), f2(d["prior"]["unnoticed"]), f2(d["schools"][col]["posterior"]["unnoticed"]), f2(d["schools"][col]["posterior"]["hidden"]), f2(d["schools"][col]["p_no_other_ever_in_galaxy"])] for d in lst]) g = R["grid_barrier_cc"] qbs = sorted({d["q_barrier"] for d in g}); qcs = sorted({d["q_cc"] for d in g}) P("P(no other civilisation ever in the Galaxy), Earth-given, against the two late-stage priors (rows: barrier; columns: forced low footprint):\n") table(["barrier \\ low footprint"] + [f"{c:g}" for c in qcs], [[f"{qb:g}"] + [f2(next(d["site"] for d in g if d["q_barrier"] == qb and d["q_cc"] == qc)) for qc in qcs] for qb in qbs]) P("## F. Possible future observations\n") rows = [] for name, fo in R["future"].items(): s1 = fo["schools"]["site"]; f1 = fam3(s1["posterior"]) alt = "; ".join(f"{list(a['overrides'].items())[0][0]}={list(a['overrides'].items())[0][1]}: nobody {fam3(a['schools']['site']['posterior'])[0]:.2f}, never spread {a['schools']['site']['posterior']['stuck']:.2f}" for a in fo.get("alternatives", [])) pt = s1.get("predictive_true") rows.append([name, f2(s1["predictive"]), f2(pt) if pt is not None else "-", f2(fo["schools"]["ssa_obs"]["predictive"]), "about " + f"{round(fo['schools']['sia']['predictive'] * 20) / 20:.2f}", f2(f1[0]), f2(f1[1]), f2(f1[2]), f2(s1["p_no_other_ever_in_galaxy"]), alt or "-"]) table(["Observation", "forecast (Earth given)", "of which true", "forecast (typical observer)", "forecast (SIA)", "nobody after", "never spread after", "spread after", "no other ever, after", "other error rates"], rows) f1 = fam3(b["schools"]["site"]["posterior"]) P(f"Now (Earth given): nobody {f1[0]:.2f}, never spread {f1[1]:.2f}, spread {f1[2]:.2f}; no other ever {b['schools']['site']['p_no_other_ever_in_galaxy']:.2f}.\n") sp = os.path.join(MOD, "integrate4_scan.json") if os.path.exists(sp): sc = json.load(open(sp)) P(f"## G. Joint scan: {len(sc)} complete alternative sets of priors\n") qf = lambda v: "/".join(f2(x) for x in np.quantile(v, [0.05, 0.5, 0.95])) nb = lambda r, k: r[k]["posterior"]["empty_universe"] + r[k]["posterior"]["rare"] spr = lambda r, k: 1 - nb(r, k) - r[k]["posterior"]["stuck"] rows = [] for k in ("site", "ssa_all", "ssa_now", "ssa_obs"): lead = np.mean([nb(r, k) > max(r[k]["posterior"]["stuck"], spr(r, k)) for r in sc]) rows.append([SHORT[k], qf([nb(r, k) for r in sc]), qf([r[k]["posterior"]["stuck"] for r in sc]), qf([spr(r, k) for r in sc]), qf([r[k]["alone"] for r in sc]), qf([r[k]["now"] for r in sc]), f"{100 * lead:.0f}%", f"{100 * np.mean([nb(r, k) > 0.5 for r in sc]):.0f}%", f"{min(r[k]['ess'] for r in sc):.0f}"]) table(["Convention", "nobody 5/50/95%", "never spread", "spread", "no other ever", "anyone else here now", "draws where nobody leads", "draws where nobody > 50%", "min ESS"], rows) pn = np.array([r["prior"]["empty_universe"] + r["prior"]["rare"] for r in sc]); sn = np.array([nb(r, "site") for r in sc]) P(f"Prior P(nobody) across the scan: {qf(pn)}. Posterior minus prior (Earth given): {qf(sn - pn)}; the observations raise P(nobody) in {100 * np.mean(sn > pn):.0f}% of draws. " f"Correlation of posterior with prior P(nobody): {np.corrcoef(pn, sn)[0, 1]:.2f}." + (f" Correlation of posterior P(nobody) with the drawn prior on easy life: {np.corrcoef([r['params']['w_fast'] for r in sc], sn)[0, 1]:.2f}." if "w_fast" in sc[0].get("params", {}) else "") + "\n") open(os.path.join(HERE, "tables_v4.md"), "w").write("\n".join(out).replace("| Biology optimist |", "| Life starts easily and no later step is improbable (was: Biology optimist) |")) print("\n".join(out))