SPB Git

spb/wp24_uqo

Public
11.8 KB · 206 lines python
1"""Figures from solved scenarios (results/scenarios/<name>_paths.npz). Skips scenarios not yet solved.2Outputs results/figures/fig03..fig09 (pdf + png)."""3import glob4import json5import os6import sys78import matplotlib9import numpy as np1011matplotlib.use("Agg")12import matplotlib.pyplot as plt1314sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))15from agi_ge.analysis import campbell_shiller_decomposition, valuation_ratios  # noqa: E40216from agi_ge.solve import load_paths  # noqa: E4021718ROOT = os.path.join(os.path.dirname(__file__), "..")19SC = os.path.join(ROOT, "results", "scenarios")20FIG = os.path.join(ROOT, "results", "figures")21os.makedirs(FIG, exist_ok=True)22plt.rcParams.update({"font.size": 9, "axes.spines.top": False, "axes.spines.right": False, "legend.frameon": False})23C = {"baseline": "#1f3b73", "no_ai": "#7f8c8d", "rapid_agi": "#c0392b", "fast_moore_cheap_energy": "#e67e22",24     "fast_moore_energy_constrained": "#8e44ad", "complements_leontief_like": "#16a085", "complements_cobb_douglas": "#2980b9",25     "substitutes": "#d35400", "ai_monopoly": "#2c3e50", "citizen_fund_20": "#27ae60", "land_tax_50": "#f39c12",26     "compute_tax_30": "#c0392b", "capital_tax_20": "#8e44ad", "foreign_ai_50": "#7f8c8d", "low_risk_aversion": "#e67e22",27     "high_risk_aversion": "#16a085", "scarce_land": "#8e44ad", "severe_chip_depreciation": "#2c3e50",28     "reinstatement": "#27ae60", "moore_ends_2040": "#f39c12", "moore_never_ends": "#c0392b"}29LAB = {"baseline": "baseline", "no_ai": "AI frozen (2026 capability)", "rapid_agi": "rapid AGI (2032)",30       "fast_moore_cheap_energy": "fast Moore, cheap energy", "fast_moore_energy_constrained": "fast Moore, energy-constrained",31       "complements_leontief_like": r"complements ($\sigma=0.4$)", "complements_cobb_douglas": r"Cobb-Douglas ($\sigma=1$)",32       "substitutes": r"substitutes ($\sigma=1.5$)", "ai_monopoly": "AI monopoly (markup 1.5)", "citizen_fund_20": "citizen fund 20%",33       "land_tax_50": "land tax 50%", "compute_tax_30": "compute tax 30%", "capital_tax_20": "capital-income tax 20%",34       "foreign_ai_50": "50% foreign-owned compute", "low_risk_aversion": r"$\gamma=1$", "high_risk_aversion": r"$\gamma=4$",35       "scarce_land": "scarce land", "severe_chip_depreciation": r"$\delta_Q=0.45$", "reinstatement": "task 4 never automated",36       "moore_ends_2040": "Moore's law ends 2040", "moore_never_ends": "Moore's law never ends"}373839def load_all():40    out = {}41    for f in sorted(glob.glob(os.path.join(SC, "*_paths.npz"))):42        name = os.path.basename(f).replace("_paths.npz", "")43        out[name] = load_paths(f)44    return out454647def save(fig, name):48    for ext in ("pdf", "png"):49        fig.savefig(os.path.join(FIG, f"{name}.{ext}"), dpi=200, bbox_inches="tight")50    plt.close(fig)515253def yr_mask(P, y0=2026, y1=2100):54    return (P["years"] >= y0) & (P["years"] <= y1)555657def fig_baseline(P, P0=None):58    m = yr_mask(P); y = P["years"][m]59    fig, ax = plt.subplots(3, 3, figsize=(10.5, 8))60    gf = P["gf"]61    ax[0, 0].plot(y, (P["GDP"] / P["GDP"][0])[m], color=C["baseline"], label="baseline")62    if P0 is not None:63        ax[0, 0].plot(y, (P0["GDP"] / P0["GDP"][0])[yr_mask(P0)], color=C["no_ai"], ls="--", label="AI frozen")64    ax[0, 0].set_yscale("log"); ax[0, 0].set_title("GDP (2026 = 1)"); ax[0, 0].legend()65    ax[0, 1].plot(y, P["labor_share"][m], color="#c0392b", label="labor")66    ax[0, 1].plot(y, (P["R_Q"] * P["K_Q"][:-1] / P["GDP"])[m], color=C["baseline"], label="compute")67    ax[0, 1].plot(y, (P["R_N"] * P["K_N"][:-1] / P["GDP"])[m], color="#7f8c8d", label="structures")68    ax[0, 1].plot(y, ((P["RTp"] + P["RTHp"]) / P["GDP"])[m], color="#27ae60", label="land")69    ax[0, 1].plot(y, (P["PE"] * P["E"] / P["GDP"])[m], color="#e67e22", label="energy")70    ax[0, 1].set_title("Income shares of GDP"); ax[0, 1].legend(fontsize=7)71    ax[0, 2].plot(y, (P["wL"] * gf / (P["wL"][0]))[m], color="#c0392b", label="$w_L$ per worker")72    ax[0, 2].plot(y, (P["wH"] * gf / (P["wH"][0]))[m], color=C["baseline"], label="$w_H$ per worker")73    ax[0, 2].plot(y, gf[m], color="#7f8c8d", ls=":", label="trend $(1+g_Z)^t$")74    ax[0, 2].set_title("Real wages (2026 = 1)"); ax[0, 2].legend(fontsize=7)75    ax[1, 0].plot(y, 100 * P["r"][1:][m], color=C["baseline"])76    ax[1, 0].set_title("Real return on wealth $r_{t+1}$ (%)")77    ax[1, 1].plot(y, P["K_Q"][:-1][m], color=C["baseline"], label="$K^Q$ (compute units)")78    ax[1, 1].set_yscale("log"); ax[1, 1].set_title("Compute capacity (log)")79    ax2 = ax[1, 1].twinx(); ax2.plot(y, P["A"][m], color="#c0392b", ls="--"); ax2.set_yscale("log"); ax2.set_ylabel("price of compute $A$ (dashed)", color="#c0392b")80    ax[1, 2].plot(y, (P["EQ"] / P["E"])[m], color="#e67e22", label="share of energy to compute")81    ax[1, 2].plot(y, P["util"][m], color="#7f8c8d", ls="--", label="utilization")82    ax[1, 2].plot(y, (P["PE"] / P["PE"][0])[m], color=C["baseline"], ls=":", label="energy price (2026=1)")83    ax[1, 2].set_title("Energy"); ax[1, 2].legend(fontsize=7)84    Li = P["Li"]; Qi = P["Qi"]; al = P["alpha"]85    comp_share_task = (Qi / al) / (Li + Qi / al + 1e-300)86    for i, nm in enumerate(["routine", "cognitive-L", "cognitive-H", "expert"]):87        ax[2, 0].plot(y, comp_share_task[m, i], label=nm)88    ax[2, 0].set_title("Compute share of task input"); ax[2, 0].legend(fontsize=7)89    ax[2, 1].plot(y, (P["inv_goods"] / P["GDP"])[m], color=C["baseline"], label="total investment / GDP")90    ax[2, 1].plot(y, ((P["pQ"] * P["I_Q"] + P["adj_Q"]) / P["GDP"])[m], color="#c0392b", label="compute investment / GDP")91    ax[2, 1].set_title("Investment"); ax[2, 1].legend(fontsize=7)92    ax[2, 2].plot(y, (P["C_W"] / P["C_W"][0] / gf)[m], color="#c0392b", label="workers (detrended)")93    ax[2, 2].plot(y, (P["C_K"] / P["C_K"][0] / gf)[m], color=C["baseline"], label="capitalists (detrended)")94    ax[2, 2].set_yscale("log"); ax[2, 2].set_title("Consumption by class (2026 = 1)"); ax[2, 2].legend(fontsize=7)95    for a in ax.ravel():96        a.set_xlim(2026, 2100)97    fig.tight_layout()98    save(fig, "fig03_baseline")99100101def fig_valuation(P, P0=None):102    m = yr_mask(P); y = P["years"][m]103    v = valuation_ratios(P)104    fig, ax = plt.subplots(2, 3, figsize=(10.5, 5.6))105    for k, lab, col in [("N", "structures", "#7f8c8d"), ("Q", "compute", C["baseline"]), ("E", "energy capital", "#e67e22"), ("H", "housing structures", "#16a085")]:106        ax[0, 0].plot(y, v[f"V_over_GDP_{k}"][m], color=col, label=lab)107    ax[0, 0].plot(y, ((P["PT"] + P["PTH"]) / P["GDP"])[m], color="#27ae60", label="land (both)")108    ax[0, 0].set_title("Market value of claims / GDP"); ax[0, 0].legend(fontsize=7)109    ax[0, 1].plot(y, v["W_over_GDP"][m], color=C["baseline"], label="baseline")110    if P0 is not None:111        ax[0, 1].plot(y, valuation_ratios(P0)["W_over_GDP"][yr_mask(P0)], color=C["no_ai"], ls="--", label="AI frozen")112    ax[0, 1].set_title("Aggregate wealth / GDP"); ax[0, 1].legend(fontsize=7)113    ax[0, 2].plot(y, v["PE_Q"][m], color=C["baseline"], label="compute")114    ax[0, 2].plot(y, v["PE_N"][m], color="#7f8c8d", label="structures")115    ax[0, 2].set_title("Price-earnings ratios"); ax[0, 2].legend(fontsize=7)116    ax[1, 0].plot(y, v["land_PR"][m], color="#27ae60", label="production land")117    ax[1, 0].plot(y, v["house_PR"][m], color="#16a085", label="house (structure + land)")118    ax[1, 0].set_title("Price-rent ratios"); ax[1, 0].legend(fontsize=7)119    ax[1, 1].plot(y, v["q_over_p_N"][m], color="#7f8c8d", label="structures")120    ax[1, 1].plot(y, v["q_over_p_Q"][m], color=C["baseline"], label="compute")121    ax[1, 1].plot(y, v["q_over_p_H"][m], color="#16a085", label="housing")122    ax[1, 1].set_title("Tobin's $q$ (market / replacement cost)"); ax[1, 1].legend(fontsize=7)123    ax[1, 2].plot(y, v["house_land_share"][m], color="#27ae60", label="land share of house value")124    ax[1, 2].plot(y, v["wealth_comp"]["land"][m], color="#7f8c8d", ls="--", label="land share of wealth")125    ax[1, 2].plot(y, v["wealth_comp"]["Q"][m], color=C["baseline"], ls=":", label="compute share of wealth")126    ax[1, 2].set_title("Composition"); ax[1, 2].legend(fontsize=7)127    for a in ax.ravel():128        a.set_xlim(2026, 2100)129    fig.tight_layout()130    save(fig, "fig04_valuation")131132133def fig_scenarios(allP, names, fname, title):134    names = [n for n in names if n in allP]135    if len(names) < 2:136        return137    fig, ax = plt.subplots(2, 3, figsize=(10.5, 5.6))138    for n in names:139        P = allP[n]; m = yr_mask(P); y = P["years"][m]; v = valuation_ratios(P); gf = P["gf"]140        kw = dict(color=C.get(n, "k"), label=LAB.get(n, n), lw=1.3 if n == "baseline" else 1.0)141        ax[0, 0].plot(y, (P["GDP"] / P["GDP"][0] / gf)[m], **kw)142        ax[0, 1].plot(y, P["labor_share"][m], **kw)143        ax[0, 2].plot(y, (P["wL"] * gf / P["wL"][0])[m], **kw)144        ax[1, 0].plot(y, 100 * P["r"][1:][m], **kw)145        ax[1, 1].plot(y, v["W_over_GDP"][m], **kw)146        ax[1, 2].plot(y, v["land_PR"][m], **kw)147    ax[0, 0].set_title("GDP / trend (2026 = 1)"); ax[0, 0].set_yscale("log")148    ax[0, 1].set_title("Labor share")149    ax[0, 2].set_title("Wage of skill L (2026 = 1)"); ax[0, 2].set_yscale("log")150    ax[1, 0].set_title("Real return (%)")151    ax[1, 1].set_title("Wealth / GDP")152    ax[1, 2].set_title("Land price-rent ratio")153    ax[0, 0].legend(fontsize=7)154    for a in ax.ravel():155        a.set_xlim(2026, 2100)156    fig.suptitle(title, fontsize=10)157    fig.tight_layout()158    save(fig, fname)159160161def fig_decomposition(allP):162    if "baseline" not in allP or "no_ai" not in allP:163        return164    P1, P0 = allP["baseline"], allP["no_ai"]165    claims = [("land", "production land"), ("housing_land", "residential land"), ("N", "structures"), ("Q", "compute"), ("H", "housing structures")]166    rows = []167    for c, lab in claims:168        try:169            d = campbell_shiller_decomposition(P1, P0, claim=c)170            rows.append((lab, d["cash_flow"], d["discount_rate"], d["total"]))171        except Exception as e:  # noqa: BLE001172            print("decomp failed", c, e)173    if not rows:174        return175    fig, ax = plt.subplots(figsize=(6.5, 3.2))176    x = np.arange(len(rows)); w = 0.35177    ax.bar(x - w / 2, [r[1] for r in rows], w, color="#27ae60", label="cash-flow channel")178    ax.bar(x + w / 2, [r[2] for r in rows], w, color="#c0392b", label="discount-rate channel")179    ax.plot(x, [r[3] for r in rows], "ko", label="total log change in value (2026)")180    ax.axhline(0, color="k", lw=0.5)181    ax.set_xticks(x); ax.set_xticklabels([r[0] for r in rows], fontsize=8)182    ax.set_ylabel("log(value, baseline / AI frozen)")183    ax.legend(fontsize=7)184    fig.tight_layout()185    save(fig, "fig07_decomposition")186    with open(os.path.join(ROOT, "results", "data", "decomposition_2026.json"), "w") as f:187        json.dump([dict(claim=r[0], cash_flow=r[1], discount_rate=r[2], total=r[3]) for r in rows], f, indent=1)188189190if __name__ == "__main__":191    allP = load_all()192    print("scenarios available:", list(allP))193    if "baseline" in allP:194        fig_baseline(allP["baseline"], allP.get("no_ai"))195        fig_valuation(allP["baseline"], allP.get("no_ai"))196    fig_scenarios(allP, ["baseline", "no_ai", "rapid_agi", "fast_moore_cheap_energy", "fast_moore_energy_constrained", "moore_never_ends"],197                  "fig05_technology_scenarios", "Technology scenarios")198    fig_scenarios(allP, ["baseline", "complements_leontief_like", "complements_cobb_douglas", "substitutes", "scarce_land", "severe_chip_depreciation"],199                  "fig06_structure_scenarios", "Substitutability and scarcity")200    fig_decomposition(allP)201    fig_scenarios(allP, ["baseline", "citizen_fund_20", "land_tax_50", "compute_tax_30", "capital_tax_20", "ai_monopoly", "foreign_ai_50"],202                  "fig08_policy_scenarios", "Ownership, competition and policy")203    fig_scenarios(allP, ["baseline", "low_risk_aversion", "high_risk_aversion", "reinstatement", "moore_ends_2040"],204                  "fig09_preference_scenarios", "Preferences, reinstatement and the end of Moore's law")205    print("done")206
Files · f7215f55e72789efa8efb849ec6020a1edb0a939
Menu

Theme