assembly-economics/simulations/gadm02/robustness.py
tegwick 6077f6a815 ASSEMBLY-WP-0006-T04: equilibrium initialisation of wealth and cohort attention
- gadm04: W, Aw, As start at their equilibria (equilibrium_init, tested);
  channel counters calibrated at GADM-0.4's own initial state
- robustness/gsa use the model's own calibration
- P3 now holds in all robustness variants (the T02 exception was an
  initial-condition artifact); life-cycle readings confirmed
- GSA rerun: model mostly additive (sum S1 ~0.99 generative, was 0.89);
  governance levers m, L, r_lin strongly non-linear; T03 reading corrected

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1494246@bnt-lap001
Assistant-Session: caf6de6f-f9e4-47ce-a584-49baa271fa4b
2026-10-12 09:35:20 +02:00

90 lines
4 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Robustness of key GADM readings to grounded and bracketed parameters (T02).
Variants: GADM-0.4 with the old organism depreciation (dO = 0.06), with the
grounded value (dO = 0.20, rescaled), and the grounded value with brackets on
the ungrounded channel self-reinforcement r and wealth conversion k_w. Channel
counters are recalibrated for every variant so each starts in equilibrium.
Usage: python3 -B simulations/gadm02/robustness.py
"""
from __future__ import annotations
import itertools
import sys
from pathlib import Path
sys.dont_write_bytecode = True
import gadm04 as g # noqa: E402
from scenarios import load_all # noqa: E402
OUT = Path(__file__).resolve().parent / "results"
R_KEYS = ("r_m", "r_i", "r_mem", "r_lin", "r_pol")
OLD_DO = {"dO": 0.06, "aO": 0.15, "ell": 0.25, "oseed": 0.01}
def variant(extra: dict) -> dict:
return {**extra, **g.calibrate(extra)}
VARIANTS = [
("old dO = 0.06", variant(OLD_DO)),
("grounded dO = 0.20", variant({})),
("grounded, r = 0.15", variant({**{k: 0.15 for k in R_KEYS}, "r_d": 0.2})),
("grounded, r = 0.45", variant({**{k: 0.45 for k in R_KEYS}, "r_d": 0.6})),
("grounded, k_w = 0.02", variant({"k_w": 0.02})),
("grounded, k_w = 0.20", variant({"k_w": 0.20})),
]
GRID = {"lineage": ({"L": 0.1, "lin_open": 0.1}, {"L": 0.8, "lin_open": 0.8}),
"membrane": ({"m": 0.2}, {"m": 0.8}),
"attention": ({"x_att": 0.9}, {"x_att": 0.2})}
def main() -> None:
OUT.mkdir(exist_ok=True)
scs = load_all()
names = list(scs)
ref_rank = None
lines = [f"# {g.MODEL_VERSION}: robustness of key readings", "",
"Generated by `simulations/gadm02/robustness.py`. t = 100 years.",
"Readings checked: (1) scenario VFAC ranking (Spearman ρ against the grounded",
"variant), (2) generative regime lowest P, (3) organism lever order on the",
"baseline background, (4) P3: full wealth tax lowers P by < 0.06 in the",
"membrane/lineage-dominated case.", "",
"| Variant | best scenario | worst scenario | ρ ranking | generative P | lineage / membrane / attention effect | lever order holds | P3 ΔP | P3 holds |",
"|---|---|---|---|---|---|---|---|---|"]
rows = []
for label, prm in VARIANTS:
res = {n: g.simulate({**scs[n]["params"], **prm}, scs[n]["init"])[-1] for n in names}
order = sorted(names, key=lambda n: -res[n]["VFAC"])
rank = {n: i for i, n in enumerate(order)}
rows.append((label, prm, res, order, rank))
ref_rank = rows[1][4]
k = len(names)
for label, prm, res, order, rank in rows:
rho = 1 - 6 * sum((rank[n] - ref_rank[n]) ** 2 for n in names) / (k * (k * k - 1))
gen_lowest = min(names, key=lambda n: res[n]["P"]) == "generative_regime"
base = scs["baseline"]
out = {}
for lv in itertools.product((0, 1), repeat=3):
p = {**base["params"], **prm}
for ax, l in zip(GRID, lv):
p.update(GRID[ax][l])
out[lv] = g.simulate(p, base["init"])[-1]["VFAC"]
eff = [sum((1 if lv[i] else -1) * v for lv, v in out.items()) / 4 for i in range(3)]
order_ok = eff[0] > eff[1] > eff[2] > 0
mem = scs["generative_concentrated_lineages"]
p0 = g.simulate({**mem["params"], **prm, "wtax": 0.0}, mem["init"])[-1]["P"]
p1 = g.simulate({**mem["params"], **prm, "wtax": 1.0}, mem["init"])[-1]["P"]
lines.append(f"| {label} | {scs[order[0]]['title']} ({res[order[0]]['VFAC']:.3f}) | "
f"{scs[order[-1]]['title']} ({res[order[-1]]['VFAC']:.3f}) | {rho:.2f} | "
f"{res['generative_regime']['P']:.2f}{' (lowest)' if gen_lowest else ''} | "
f"{eff[0]:+.3f} / {eff[1]:+.3f} / {eff[2]:+.3f} | {'yes' if order_ok else 'no'} | "
f"{p1 - p0:+.3f} | {'yes' if p0 - p1 < 0.06 else 'no'} |")
(OUT / "robustness.md").write_text("\n".join(lines) + "\n")
print("\n".join(lines))
if __name__ == "__main__":
main()