assembly-economics/simulations/gadm02/life_cycle.py
tegwick c03cf98756 ASSEMBLY-WP-0006-T01: durable human capability (GADM-0.4)
- gadm04.py: cohort capability split into durable (education-formed, slow
  depreciation, birth dilution) and current components; learning begets
  learning; starts identical to GADM-0.3 (tested)
- L3 now supported: education reaches working-age capability with a 17-year
  half-time and 3x the effect; L1 still holds, more weakly
- life_cycle.py selectable per model; GADM-0.3 results unchanged

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 08:24:34 +02:00

85 lines
4 KiB
Python

"""Life-cycle hypotheses L1-L3 for GADM-0.3 with cohorts (gadm03c).
L1: strong intergenerational transfer T_g lets an ageing society keep H.
L2: care demand competes with attention; without recognized care participation
(C_p), attention headroom falls fastest in the working-age cohort.
L3: children's capability formation reaches working-age capability with a lag
of 15-20 years.
Usage: python3 -B simulations/gadm02/life_cycle.py [--model gadm04]
(default model: gadm03c, the GADM-0.3 cohort model)
"""
from __future__ import annotations
import sys
from pathlib import Path
sys.dont_write_bytecode = True
import importlib # noqa: E402
MODEL = sys.argv[sys.argv.index("--model") + 1] if "--model" in sys.argv else "gadm03c"
c = importlib.import_module(MODEL)
from scenarios import load_all # noqa: E402
OUT = Path(__file__).resolve().parent / "results"
STABLE, AGEING = 1 / 45, 0.75 / 45
def run(params: dict, base: dict) -> list[dict]:
return c.simulate({**base["params"], **params}, base["init"])
def main() -> None:
OUT.mkdir(exist_ok=True)
sc = load_all()["baseline"]
lines = [f"# {c.MODEL_VERSION}: life-cycle hypotheses", "",
"Generated by `simulations/gadm02/life_cycle.py`. Baseline background,",
"t = 100 years. Ageing demography: births at 75 % of replacement.", ""]
lines += ["## L1: intergenerational transfer in an ageing society", "",
"| Demography | T_g (tg) | seniors + very old (share, t=100) | H (t=0) | H (t=100) | ΔH |",
"|---|---|---|---|---|---|"]
for demo, b in (("stable", STABLE), ("ageing", AGEING)):
for tg in (0.0, 0.05, 0.15):
r = run({"birth": b, "tg": tg}, sc)
old = r[-1]["n_s"] + r[-1]["n_d"]
lines.append(f"| {demo} | {tg:.2f} | {old:.2f} | {r[0]['H']:.3f} | {r[-1]['H']:.3f} | "
f"{r[-1]['H'] - r[0]['H']:+.3f} |")
lines += ["", "## L2: care load and attention", "",
"Levels at t = 100 are compared across settings (not against t = 0, because",
"initial cohort attention is not at its own equilibrium).", "",
"| Demography | care_sen (seniors' care share) | cp | A working age | A seniors | care load per working-age person | per senior |",
"|---|---|---|---|---|---|---|"]
for demo, b in (("stable", STABLE), ("ageing", AGEING)):
for cs in (0.1, 0.3):
for cp in (0.0, 0.15):
prm = {"birth": b, "cp": cp, "care_sen": cs}
r = run(prm, sc)[-1]
pp = {**c.PARAMS, **sc["params"], **prm}
load = pp["care_load"] * r["care_need"] * max(0.0, 1 - pp["care_relief"] * cp)
lines.append(f"| {demo} | {cs:.1f} | {cp:.2f} | {r['Aw']:.3f} | {r['As']:.3f} | "
f"{load * (1 - cs) / r['n_w']:.4f} | {load * cs / r['n_s']:.4f} |")
lines += ["", "## L3: lag from education to working-age capability", "",
"Run difference: education intensity 1.5 vs. 1.0, everything else equal.", "",
"| t | ΔH children | ΔH working age | ΔH aggregate |", "|---|---|---|---|"]
lo, hi = run({"edu": 1.0}, sc), run({"edu": 1.5}, sc)
diffs = [(a["t"], b["Hch"] - a["Hch"], b["Hw"] - a["Hw"], b["H"] - a["H"]) for a, b in zip(lo, hi)]
for t, dc, dw, dh in diffs:
if t in (0, 5, 10, 15, 20, 25, 30, 40, 50, 75, 100):
lines.append(f"| {t:.0f} | {dc:+.3f} | {dw:+.3f} | {dh:+.3f} |")
final_w, final_c = diffs[-1][2], diffs[-1][1]
t_w = next(t for t, _dc, dw, _dh in diffs if dw >= 0.5 * final_w)
t_c = next(t for t, dc, _dw, _dh in diffs if dc >= 0.5 * final_c)
lines += ["", f"Half of the final effect is reached after {t_c:.0f} years for children and "
f"{t_w:.0f} years for working-age capability.", ""]
name = "life_cycle.md" if MODEL == "gadm03c" else f"life_cycle_{MODEL}.md"
(OUT / name).write_text("\n".join(lines))
print("\n".join(lines))
if __name__ == "__main__":
main()