SPB Git

spb/wp24_uqo

Public
6.8 KB · 168 lines python
1"""Parameter container for the AGI general-equilibrium model (see docs/model_dictionary.md).23All defaults here are *placeholders of the right order of magnitude*; `calibration.py` overwrites the4calibrated ones from data/processed/calibration_targets.csv and records the provenance of every value in5results/data/parameters.json (field `source`: "data", "calibrated", "scenario" or "assumed").6"""7from __future__ import annotations89import dataclasses10import json11from dataclasses import dataclass, field12from typing import Dict, List, Optional1314import numpy as np1516from .ces import rho_of_sigma171819@dataclass20class TaskSpec:21    """Task classes. Index 0..n-1; bottleneck tasks have nu>0, accessory tasks have gamma>0."""22    names: List[str] = field(default_factory=lambda: ["routine", "cognitive-L", "cognitive-H", "expert", "acc-L", "acc-H"])23    skill: List[int] = field(default_factory=lambda: [0, 0, 1, 1, 0, 1])          # 0 = L, 1 = H24    nu: List[float] = field(default_factory=lambda: [0.30, 0.25, 0.25, 0.20, 0.0, 0.0])25    gamma: List[float] = field(default_factory=lambda: [0.0, 0.0, 0.0, 0.0, 0.05, 0.05])26    alpha_inf: List[float] = field(default_factory=lambda: [1.0, 2.0, 4.0, 8.0, 3.0, 6.0])   # terminal compute per worker2728    @property29    def n(self):30        return len(self.names)3132    @property33    def is_acc(self):34        return np.array([g > 0 for g in self.gamma])353637@dataclass38class Params:39    # --- horizon ---40    T: int = 275                      # periods (2026 .. 2300)41    year0: int = 202642    # --- tasks ---43    tasks: TaskSpec = field(default_factory=TaskSpec)44    sigma_B: float = 0.5              # elasticity across bottleneck tasks45    H: List[float] = field(default_factory=lambda: [0.6, 0.4])   # skill supplies (L, H)46    # --- nests ---47    sigma_N: float = 0.7              # tasks vs structures48    nu_N: float = 0.3049    sigma_T: float = 0.6              # top nest: land, energy, V50    nu_T: float = 0.0551    nu_E: float = 0.0352    # --- technology paths ---53    Z0: float = 1.054    g_Z: float = 0.01                 # non-AI TFP growth55    ZE: float = 1.0                   # energy TFP56    eta: float = 0.35                 # resource share in energy57    RE: float = 1.0                   # energy resource endowment58    T_land: float = 1.059    TH_land: float = 1.060    nu_H: float = 0.35                # land share in housing61    theta_H: float = 0.15             # housing expenditure share62    # --- capital ---63    delta: Dict[str, float] = field(default_factory=lambda: {"N": 0.06, "Q": 0.25, "E": 0.05, "H": 0.025})64    phi: Dict[str, float] = field(default_factory=lambda: {"N": 3.0, "Q": 1.0, "E": 3.0, "H": 3.0})65    pQ0: float = 1.0                  # initial price of one compute unit66    g_pQ: float = 0.25                # rate of decline of compute price67    pQ_floor_ratio: float = 1e-3      # floor relative to pQ0 (Moore's law ends when reached)68    eps0: float = 1.0                 # energy per compute unit69    g_eps: float = 0.10               # energy efficiency gains70    eps_floor_ratio: float = 1e-271    # --- preferences (two-class capitalists) ---72    beta: float = 0.9673    gamma_u: float = 2.074    # --- alpha paths: log-linear decline from alpha0 to alpha_inf at rate g_alpha ---75    alpha0_mult: List[float] = field(default_factory=lambda: [3.0, 50.0, 400.0, 3000.0, 100.0, 1000.0])76    g_alpha: float = 0.1577    alpha_shock_year: Optional[int] = None    # if set: alpha jumps to alpha_inf in that year (rapid AGI)78    alpha_freeze: bool = False                # if True: alpha stays at alpha0 forever (no-AI reference)79    reinstate_task: Optional[int] = None      # index of a task whose alpha stays at its 2026 value (never automated)80    alpha_inf_scale: float = 1.0              # multiplies all terminal alpha_i^inf (2026 values unchanged)81    # --- policy ---82    tau_T: float = 0.0                # land value tax (share of land rent)83    tau_K: float = 0.0                # tax on all capital income84    tau_Q: float = 0.0                # tax on compute rental income85    theta_F: float = 0.0              # citizen fund share of equity86    markup_Q: float = 1.0             # AI-provider markup on compute services (1 = competitive)87    foreign_share_Q: float = 0.0      # share of compute equity owned abroad88    # --- initial stocks (set by calibration) ---89    KN0: float = 2.590    KQ0: float = 0.0291    KE0: float = 0.392    KH0: float = 1.293    # --- provenance ---94    source: Dict[str, str] = field(default_factory=dict)9596    # ---------- derived ----------97    @property98    def rho_B(self):99        return rho_of_sigma(self.sigma_B)100101    @property102    def rho_N(self):103        return rho_of_sigma(self.sigma_N)104105    @property106    def rho_T(self):107        return rho_of_sigma(self.sigma_T)108109    def years(self):110        return np.arange(self.year0, self.year0 + self.T)111112    def Z_path(self):113        """Hicks-neutral TFP: constant in the baseline (trend growth g_Z is Harrod-neutral, see transition.py);114        the 'AI for science' robustness scenario raises Z along a path set in scenarios.py."""115        return self.Z0 * np.ones(self.T)116117    def pQ_path(self):118        t = np.arange(self.T)119        return self.pQ0 * np.maximum(np.exp(-self.g_pQ * t), self.pQ_floor_ratio)120121    def eps_path(self):122        t = np.arange(self.T)123        return self.eps0 * np.maximum(np.exp(-self.g_eps * t), self.eps_floor_ratio)124125    def alpha_path(self):126        """Array (T, n_tasks) of alpha_{i,t}; np.inf = not automatable."""127        n = self.tasks.n128        a_inf = np.array(self.tasks.alpha_inf, dtype=float)129        a0 = a_inf * np.array(self.alpha0_mult, dtype=float)130        a_inf = np.minimum(a_inf * self.alpha_inf_scale, a0)131        t = np.arange(self.T)[:, None]132        if self.alpha_freeze:133            return np.tile(a0, (self.T, 1))134        if self.alpha_shock_year is not None:135            ts = self.alpha_shock_year - self.year0136            path = np.where(t < ts, a0[None, :], a_inf[None, :])137            if self.reinstate_task is not None:138                path[:, self.reinstate_task] = a0[self.reinstate_task]139            return path140        path = np.maximum(a0[None, :] * np.exp(-self.g_alpha * t), a_inf[None, :])141        if self.reinstate_task is not None:142            path[:, self.reinstate_task] = a0[self.reinstate_task]143        return path144145    # ---------- I/O ----------146    def to_dict(self):147        d = dataclasses.asdict(self)148        return d149150    def to_json(self, path):151        with open(path, "w") as f:152            json.dump(self.to_dict(), f, indent=2)153154    @classmethod155    def from_dict(cls, d):156        d = dict(d)157        if "tasks" in d and isinstance(d["tasks"], dict):158            d["tasks"] = TaskSpec(**d["tasks"])159        return cls(**d)160161    @classmethod162    def from_json(cls, path):163        with open(path) as f:164            return cls.from_dict(json.load(f))165166    def replace(self, **kw):167        return dataclasses.replace(self, **kw)168
Files · main
Menu

Theme