{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "b760937f",
   "metadata": {},
   "source": [
    "# DCT Laboratory — Volume I, Chapter 12\n",
    "## Enterprise Risk, Resilience, and Robustness Architecture\n",
    "**Seed `26112`** · Companion to the chapter and AXIOM Module **AXIOM-12**\n",
    "\n",
    "Four instruments on one bench: **robustness** (worst case over a declared stress\n",
    "set), **resilience** (recovery time after a shock), **survivability** (Chapter 8's\n",
    "barrier probability, reused), and **risk propagation** on Chapter 9's graph with a\n",
    "coupling gain $g$ — including the systemic threshold $g^* = 1/\\rho(W)$ where\n",
    "cascades stop dying out. Mirrored in `DCT_V1_Ch12_Lab.xlsx`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9030cb3d",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T23:03:59.815187Z",
     "iopub.status.busy": "2026-07-13T23:03:59.814964Z",
     "iopub.status.idle": "2026-07-13T23:04:00.347921Z",
     "shell.execute_reply": "2026-07-13T23:04:00.346717Z"
    }
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "plt.rcParams['figure.dpi']=110\n",
    "\n",
    "import numpy as np\n",
    "from math import log, sqrt, erf\n",
    "SEED = 26112\n",
    "# --- propagation on Chapter 9's graph ---\n",
    "W = np.array([\n",
    " [0.00,0.30,0.10,0.40,0.00,0.20],\n",
    " [0.10,0.00,0.45,0.20,0.25,0.00],\n",
    " [0.15,0.05,0.00,0.00,0.20,0.00],\n",
    " [0.00,0.35,0.30,0.00,0.10,0.00],\n",
    " [0.05,0.10,0.00,0.00,0.00,0.00],\n",
    " [0.20,0.15,0.25,0.15,0.05,0.00]])\n",
    "E0 = np.zeros(6); E0[2] = 10.0            # shock to Technology\n",
    "\n",
    "def cum_impact(g, rounds=6):\n",
    "    s, tot = E0.copy(), 0.0\n",
    "    per_round = []\n",
    "    for _ in range(rounds):\n",
    "        s = g*(W @ s)\n",
    "        per_round.append(float(s.sum()))\n",
    "        tot += s.sum()\n",
    "    return float(tot), per_round\n",
    "\n",
    "# --- robustness: worst case over a declared stress set ---\n",
    "P_BASE = 75.0\n",
    "SCEN = {\"demand\": 12.0, \"funding\": 18.0, \"cyber\": 9.0}\n",
    "FLOOR = 50.0\n",
    "\n",
    "# --- resilience: 30% performance shock, rho recovery ---\n",
    "RHO_P = 0.8\n",
    "def recovery_time(frac=0.9):\n",
    "    \"\"\"quarters until frac of the loss is recovered: rho^n = 1-frac\"\"\"\n",
    "    return log(1-frac)/log(RHO_P)\n",
    "\n",
    "# --- survivability: Ch. 8's barrier, 1 - P(breach) ---\n",
    "X0, MU, SIG, T, BARRIER = 100.0, 0.08, 0.25, 5.0, 80.0\n",
    "def Phi(z): return 0.5*(1+erf(z/sqrt(2)))\n",
    "def survivability():\n",
    "    z = (log(BARRIER/X0)-(MU-SIG**2/2)*T)/(SIG*sqrt(T))\n",
    "    return 1 - Phi(z)\n",
    "\n",
    "def reference_values():\n",
    "    c1,_ = cum_impact(1.0)\n",
    "    c15,_ = cum_impact(1.5)\n",
    "    _, pr = cum_impact(1.7)\n",
    "    return {\n",
    "        \"rho_W\": round(float(max(abs(np.linalg.eigvals(W)))),4),\n",
    "        \"critical_gain\": round(1/float(max(abs(np.linalg.eigvals(W)))),4),\n",
    "        \"cum6_g1.0\": round(c1,4),\n",
    "        \"cum6_g1.5\": round(c15,4),\n",
    "        \"amp_ratio_g1.7\": round(pr[5]/pr[4],4),\n",
    "        \"robust_perf\": round(P_BASE-max(SCEN.values()),4),\n",
    "        \"robust_margin\": round(P_BASE-max(SCEN.values())-FLOOR,4),\n",
    "        \"recover90_quarters\": round(recovery_time(0.9),4),\n",
    "        \"survivability_t5\": round(survivability(),4),\n",
    "    }\n",
    "if __name__ == \"__main__\":\n",
    "    [print(f\"{k:20s} {v}\") for k,v in reference_values().items()]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c7c2e789",
   "metadata": {},
   "source": [
    "## Panel 1 — Propagation with a gain: the road to systemic risk\n",
    "The same Technology shock, three coupling gains. At $g = 1$ (Chapter 9's world),\n",
    "six rounds absorb 28.4. At $g = 1.5$, still subcritical ($g\\rho = 0.94$), the\n",
    "same shock costs 87.4. At $g = 1.7 > g^* = 1.60$, round-over-round impacts\n",
    "**grow** — the Risk Propagation Theorem's phase change, visible in a ratio."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b2db12dd",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T23:04:00.350268Z",
     "iopub.status.busy": "2026-07-13T23:04:00.349909Z",
     "iopub.status.idle": "2026-07-13T23:04:00.740313Z",
     "shell.execute_reply": "2026-07-13T23:04:00.738986Z"
    }
   },
   "outputs": [],
   "source": [
    "fig, ax = plt.subplots(figsize=(8.4,4.4))\n",
    "for g,c,nm in [(1.0,\"#0B3D2E\",\"g = 1.0 (ρg = 0.63)\"),(1.5,\"#C8A24B\",\"g = 1.5 (ρg = 0.94)\"),(1.7,\"#B0532F\",\"g = 1.7 (ρg = 1.06)\")]:\n",
    "    _, pr = cum_impact(g)\n",
    "    ax.plot(range(1,7), pr, \"o-\", c=c, lw=2.2, label=nm)\n",
    "ax.set(xlabel=\"round\", ylabel=\"round impact (sum over components)\", yscale=\"log\",\n",
    "       title=\"Same shock, three gains — systemic threshold g* = 1.60 (seed 26112)\")\n",
    "ax.legend(frameon=False); ax.grid(alpha=.25); plt.tight_layout(); plt.show()\n",
    "for g in (1.0,1.5,1.7):\n",
    "    tot, pr = cum_impact(g)\n",
    "    print(f\"g={g:.1f}  cum 6 rounds {tot:8.4f}   round6/round5 ratio {pr[5]/pr[4]:.4f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "80802774",
   "metadata": {},
   "source": [
    "## Panel 2 — Robustness: worst case over a declared set\n",
    "Three stress scenarios on baseline performance 75. The Enterprise Robustness\n",
    "Theorem evaluates the **minimum**: robust performance is 57 (the funding\n",
    "scenario binds), leaving margin 7 above the survival floor of 50. Robustness is\n",
    "a property of the *declared set* — an undeclared scenario is not covered, which\n",
    "is the definition's honesty."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "064c0478",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T23:04:00.742266Z",
     "iopub.status.busy": "2026-07-13T23:04:00.742066Z",
     "iopub.status.idle": "2026-07-13T23:04:00.747934Z",
     "shell.execute_reply": "2026-07-13T23:04:00.746955Z"
    }
   },
   "outputs": [],
   "source": [
    "print(f\"baseline performance: {P_BASE}\")\n",
    "for nm, d in SCEN.items():\n",
    "    print(f\"  scenario {nm:8s} drop {d:5.1f} → {P_BASE-d:5.1f}\")\n",
    "worst = P_BASE - max(SCEN.values())\n",
    "print(f\"robust performance (min over set): {worst}   margin over floor {FLOOR}: {worst-FLOOR}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c22439f0",
   "metadata": {},
   "source": [
    "## Panel 3 — Resilience and survivability\n",
    "Resilience: a shock erases 30% of performance; with response inertia $\\rho =\n",
    "0.8$, recovering **90% of the loss takes 10.32 quarters** (Enterprise Resilience\n",
    "Theorem, as a logarithm). Survivability: with Chapter 8's diffusion and the\n",
    "80-barrier, the enterprise survives to $t = 5$ with probability **0.7982** —\n",
    "the same $\\Phi(z)$, now read from the survival side."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "aa4a741d",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T23:04:00.750255Z",
     "iopub.status.busy": "2026-07-13T23:04:00.749539Z",
     "iopub.status.idle": "2026-07-13T23:04:00.934019Z",
     "shell.execute_reply": "2026-07-13T23:04:00.932862Z"
    }
   },
   "outputs": [],
   "source": [
    "n = np.arange(0, 16)\n",
    "loss_frac = RHO_P**n\n",
    "fig, ax = plt.subplots(figsize=(7.8,3.9))\n",
    "ax.plot(n, 100*(1-loss_frac), \"o-\", c=\"#C8A24B\", lw=2.2, ms=4)\n",
    "ax.axhline(90, c=\"#0B3D2E\", ls=\":\", lw=1.2, label=\"90% recovered\")\n",
    "ax.axvline(recovery_time(0.9), c=\"#0B3D2E\", ls=\"--\", lw=1, label=f\"t = {recovery_time(0.9):.2f} q\")\n",
    "ax.set(xlabel=\"quarters since shock\", ylabel=\"% of loss recovered\", title=\"Recovery under ρ = 0.8\")\n",
    "ax.legend(frameon=False); ax.grid(alpha=.25); plt.tight_layout(); plt.show()\n",
    "print(f\"recover 90% of loss: {recovery_time(0.9):.4f} quarters\")\n",
    "print(f\"survivability to t=5 (Ch. 8 barrier): {survivability():.4f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "78a21b28",
   "metadata": {},
   "source": [
    "## Validation — agrees with `DCT_V1_Ch12_Lab.xlsx`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c09ef5af",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T23:04:00.936308Z",
     "iopub.status.busy": "2026-07-13T23:04:00.935622Z",
     "iopub.status.idle": "2026-07-13T23:04:00.943254Z",
     "shell.execute_reply": "2026-07-13T23:04:00.942287Z"
    }
   },
   "outputs": [],
   "source": [
    "ref = reference_values()\n",
    "expected = {\"rho_W\":0.625,\"critical_gain\":1.6001,\"cum6_g1.0\":28.4266,\"cum6_g1.5\":87.4202,\n",
    " \"amp_ratio_g1.7\":1.0581,\"robust_perf\":57.0,\"robust_margin\":7.0,\n",
    " \"recover90_quarters\":10.3189,\"survivability_t5\":0.7982}\n",
    "for k,v in expected.items():\n",
    "    assert abs(ref[k]-v)<5e-4, f\"MISMATCH {k}\"\n",
    "    print(f\"PASS  {k:20s} {ref[k]}\")\n",
    "print(\"\\nAll checkpoints agree — seed 26112.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d6427044",
   "metadata": {},
   "source": [
    "**Next**: Exercises 12.9–12.12 (Part C) sweep the gain through the threshold; AXIOM-12's cascade theater animates the phase change. Solutions: IM Ch. 12."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
