SPB Git

spb/wp25_uqo

Public
4.1 KB · 91 lines python
1"""Task-based production with compute (Model A, §1.3 of docs/model_specification.md).23Y = e^z K^alpha T^(1-alpha),   ln T = ∫ ln y(x) dx  (Cobb–Douglas over tasks x in [0,1]).4Tasks x <= iota are produced by compute with productivity psi(x) = psi0 * exp(-psi1 x); the rest by labour.5With unit elasticity across tasks the bundle is67    T = Psi(iota) * (Q_P/iota)^iota * (L/(1-iota))^(1-iota),   Psi(iota) = psi0^iota * exp(-psi1 iota^2 / 2).89The automated set is [0, iota] with iota = min(iota_bar, iota*) and  psi(iota*) = p_Q / w  (threshold condition),10which combined with the factor-price conditions gives  psi(iota) = iota/(1-iota) * L/Q_P   (A.3).1112All functions are pure numpy; no state.13"""14from __future__ import annotations1516from dataclasses import dataclass1718import numpy as np19from scipy.optimize import brentq202122@dataclass(frozen=True)23class TaskTech:24    alpha: float = 0.3325    iota_bar: float = 0.526    psi0: float = 1.027    psi1: float = 3.02829    def psi(self, x):30        return self.psi0 * np.exp(-self.psi1 * np.asarray(x, dtype=float))3132    def Psi(self, iota):33        """exp(∫_0^iota ln psi(x) dx) = psi0^iota * exp(-psi1 iota^2/2)."""34        iota = np.asarray(iota, dtype=float)35        return self.psi0 ** iota * np.exp(-self.psi1 * iota ** 2 / 2.0)3637    # ------------------------------------------------------------------ automation threshold38    def iota_of(self, QP: float, L: float) -> float:39        """Automated task share from (A.3): psi(iota) = iota/(1-iota) * L/QP, capped at iota_bar.4041        LHS is decreasing in iota, RHS increasing from 0 to +inf, hence a unique interior root for QP > 0.42        """43        if QP <= 1e-9 * L:44            return 0.045        f = lambda i: np.log(self.psi(i)) - np.log(i / (1.0 - i)) - np.log(L / QP)46        # f(0+) = +inf, f(1-) = -inf  -> unique root47        lo, hi = 1e-9, 1.0 - 1e-948        if f(lo) <= 0:49            return 0.050        root = brentq(f, lo, hi, xtol=1e-14, rtol=1e-12, maxiter=200)51        return float(min(root, self.iota_bar))5253    # ------------------------------------------------------------------ bundle and output54    def bundle(self, QP: float, L: float, iota: float | None = None) -> float:55        if iota is None:56            iota = self.iota_of(QP, L)57        if iota <= 0.0:58            return float(L)59        return float(self.Psi(iota) * (QP / iota) ** iota * (L / (1.0 - iota)) ** (1.0 - iota))6061    def output(self, z: float, K: float, QP: float, L: float, iota: float | None = None) -> float:62        T = self.bundle(QP, L, iota)63        return float(np.exp(z) * K ** self.alpha * T ** (1.0 - self.alpha))6465    # ------------------------------------------------------------------ prices (competitive, CRS)66    def prices(self, z: float, K: float, QP: float, L: float) -> dict:67        """Rental rate of capital, wage, compute rental, output, automated share and factor shares.6869        When iota is at the frontier iota_bar (corner), the compute price is still the marginal product of compute70        in the automated tasks, (1-alpha) iota Y / QP, and the threshold condition holds with inequality.71        """72        iota = self.iota_of(QP, L)73        Y = self.output(z, K, QP, L, iota)74        RK = self.alpha * Y / K75        w = (1.0 - self.alpha) * (1.0 - iota) * Y / L76        pQ = (1.0 - self.alpha) * iota * Y / QP if QP > 0 else 0.077        return dict(Y=Y, iota=iota, RK=RK, w=w, pQ=pQ,78                    share_K=self.alpha, share_Q=(1.0 - self.alpha) * iota, share_L=(1.0 - self.alpha) * (1.0 - iota))7980    def production_compute_demand(self, pQ: float, w: float, L: float, z: float, K: float) -> float:81        """Compute demanded by the firm at rental pQ given the wage (used for compute-market clearing).8283        From the FOCs: pQ = (1-alpha) iota Y/QP and w = (1-alpha)(1-iota) Y/L  ->  QP = iota/(1-iota) * L * w/pQ,84        with iota from the threshold psi(iota) = pQ/w (capped at iota_bar). If pQ/w > psi(0), no task is automated.85        """86        ratio = pQ / w87        if ratio >= self.psi0:88            return 0.089        iota = min(self.iota_bar, float(-np.log(ratio / self.psi0) / self.psi1))90        return float(iota / (1.0 - iota) * L / ratio)91
Files · main
Menu

Theme