{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "24937a22",
   "metadata": {},
   "source": [
    "# DCT Laboratory — Volume I, Chapter 8\n",
    "## Stochastic Enterprise Dynamics\n",
    "**Seed `26108`** · Companion to the chapter and AXIOM Module **AXIOM-08**\n",
    "\n",
    "The fiction is dropped: the environment channel is random, trajectories become\n",
    "**fans**, and the state at $t$ is a **distribution**. Three instruments here: the\n",
    "enterprise diffusion (GBM) with its analytic moments, the **flaw of averages**\n",
    "made visible (mean path ≠ median path; $\\mathbb{E}[f(X)] \\ne f(\\mathbb{E}[X])$),\n",
    "and jump-diffusion — restructuring's stochastic home. The analytic core is\n",
    "mirrored in `DCT_V1_Ch08_Lab.xlsx`; Monte Carlo fans live here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5fd069e7",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T22:42:38.619647Z",
     "iopub.status.busy": "2026-07-13T22:42:38.619485Z",
     "iopub.status.idle": "2026-07-13T22:42:39.600247Z",
     "shell.execute_reply": "2026-07-13T22:42:39.598665Z"
    }
   },
   "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, exp, erf\n",
    "SEED = 26108\n",
    "X0, MU, SIG, T = 100.0, 0.08, 0.25, 5.0\n",
    "BARRIER = 80.0\n",
    "LAM_J, MJ = 0.4, 0.9          # jump intensity /yr, mean jump multiplier\n",
    "\n",
    "def Phi(z): return 0.5*(1+erf(z/sqrt(2)))\n",
    "\n",
    "def mean_T():   return X0*exp(MU*T)\n",
    "def median_T(): return X0*exp((MU-SIG**2/2)*T)\n",
    "def p_below_barrier():\n",
    "    z = (log(BARRIER/X0)-(MU-SIG**2/2)*T)/(SIG*sqrt(T))\n",
    "    return Phi(z)\n",
    "def mean_T_jumps():   # compound Poisson multiplicative jumps\n",
    "    return X0*exp((MU+LAM_J*(MJ-1))*T)\n",
    "\n",
    "def mc_paths(n_paths=2000, steps=60):\n",
    "    rng = np.random.default_rng(SEED)\n",
    "    dt = T/steps\n",
    "    z = rng.standard_normal((n_paths, steps))\n",
    "    logx = np.cumsum((MU-SIG**2/2)*dt + SIG*sqrt(dt)*z, axis=1)\n",
    "    return X0*np.exp(np.hstack([np.zeros((n_paths,1)), logx]))\n",
    "\n",
    "def mc_jump_paths(n_paths=2000, steps=60):\n",
    "    rng = np.random.default_rng(SEED+1)\n",
    "    dt = T/steps\n",
    "    z = rng.standard_normal((n_paths, steps))\n",
    "    nj = rng.poisson(LAM_J*dt, (n_paths, steps))\n",
    "    logx = np.cumsum((MU-SIG**2/2)*dt + SIG*sqrt(dt)*z + nj*log(MJ), axis=1)\n",
    "    return X0*np.exp(np.hstack([np.zeros((n_paths,1)), logx]))\n",
    "\n",
    "def reference_values():\n",
    "    return {\n",
    "        \"mean_t5\":        round(mean_T(), 4),\n",
    "        \"median_t5\":      round(median_T(), 4),\n",
    "        \"mean_median_gap\":round(mean_T()-median_T(), 4),\n",
    "        \"p_breach_t5\":    round(p_below_barrier(), 4),\n",
    "        \"mean_t5_jumps\":  round(mean_T_jumps(), 4),\n",
    "        \"jump_drag\":      round(mean_T()-mean_T_jumps(), 4),\n",
    "        \"sigma_sqrtT\":    round(SIG*sqrt(T), 4),\n",
    "    }\n",
    "if __name__ == \"__main__\":\n",
    "    [print(f\"{k:18s} {v}\") for k,v in reference_values().items()]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "68860ae7",
   "metadata": {},
   "source": [
    "## Panel 1 — The fan, and two \"forecasts\" inside it\n",
    "2,000 GBM paths, seed `26108`. The **mean path** (what the Expected Enterprise\n",
    "Evolution Theorem tracks) and the **median path** diverge — at $t=5$ they are\n",
    "21.6 apart on a base of 100. The mean is dragged up by a thin right tail; the\n",
    "median is what the typical path does. Deterministic dynamics are the degenerate\n",
    "case (Prop.): switch $\\sigma$ to 0 and the fan collapses to Chapter 7."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e7e0c204",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T22:42:39.603443Z",
     "iopub.status.busy": "2026-07-13T22:42:39.602230Z",
     "iopub.status.idle": "2026-07-13T22:42:40.182176Z",
     "shell.execute_reply": "2026-07-13T22:42:40.181394Z"
    }
   },
   "outputs": [],
   "source": [
    "paths = mc_paths()\n",
    "t = np.linspace(0, T, paths.shape[1])\n",
    "fig, ax = plt.subplots(figsize=(8.4,4.6))\n",
    "ax.plot(t, paths[:150].T, color=\"#1B6B52\", alpha=.04)\n",
    "ax.plot(t, X0*np.exp(MU*t), c=\"#C8A24B\", lw=2.5, label=f\"mean path → {mean_T():.1f}\")\n",
    "ax.plot(t, X0*np.exp((MU-SIG**2/2)*t), c=\"#0B3D2E\", lw=2.5, ls=\"--\", label=f\"median path → {median_T():.1f}\")\n",
    "ax.axhline(BARRIER, c=\"#B0532F\", lw=1.2, ls=\":\", label=f\"barrier {BARRIER:.0f}\")\n",
    "ax.set(xlabel=\"years\", ylabel=\"enterprise value\", title=\"The fan: 2,000 futures, two summaries (seed 26108)\")\n",
    "ax.legend(frameon=False); ax.grid(alpha=.25); plt.tight_layout(); plt.show()\n",
    "print(f\"analytic mean {mean_T():.4f}   MC mean {paths[:,-1].mean():.4f}\")\n",
    "print(f\"analytic median {median_T():.4f}   MC median {np.median(paths[:,-1]):.4f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5f229d03",
   "metadata": {},
   "source": [
    "## Panel 2 — The flaw of averages, exactly\n",
    "Two demonstrations. **(a)** The mean–median gap above: \"the average outcome\"\n",
    "and \"the typical outcome\" are different numbers. **(b)** $\\mathbb{E}[f(X)]\n",
    "\\ne f(\\mathbb{E}[X])$ for the breach indicator $f(x) = \\mathbf{1}[x < 80]$:\n",
    "evaluated **at the mean**, the breach \"cannot happen\" ($f(149.2) = 0$); in\n",
    "**expectation**, it happens with probability 0.2018 — one path in five.\n",
    "Planning on the mean path deletes a 20% event."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9c39cbb0",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T22:42:40.184998Z",
     "iopub.status.busy": "2026-07-13T22:42:40.184621Z",
     "iopub.status.idle": "2026-07-13T22:42:40.190769Z",
     "shell.execute_reply": "2026-07-13T22:42:40.189741Z"
    }
   },
   "outputs": [],
   "source": [
    "p_analytic = p_below_barrier()\n",
    "p_mc = float((paths[:,-1] < BARRIER).mean())\n",
    "print(f\"f(E[X_5]) = 1[{mean_T():.1f} < 80]        = 0        (the mean-path plan)\")\n",
    "print(f\"E[f(X_5)] = P(X_5 < 80)  analytic = {p_analytic:.4f}\")\n",
    "print(f\"                          MC       = {p_mc:.4f}   (2,000 paths)\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ed59344c",
   "metadata": {},
   "source": [
    "## Panel 3 — Jumps: restructuring's stochastic home\n",
    "A compound-Poisson jump component ($\\lambda = 0.4$/yr, mean multiplier 0.9)\n",
    "riding on the diffusion — the Jump-Diffusion Theorem's world. The jump drag on\n",
    "the mean is analytic: $\\mathbb{E}[X_T] = x_0 e^{(\\mu + \\lambda(m-1))T}$, a\n",
    "27-point haircut at $t=5$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "555f96bc",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T22:42:40.193119Z",
     "iopub.status.busy": "2026-07-13T22:42:40.192378Z",
     "iopub.status.idle": "2026-07-13T22:42:40.653128Z",
     "shell.execute_reply": "2026-07-13T22:42:40.650938Z"
    }
   },
   "outputs": [],
   "source": [
    "jp = mc_jump_paths()\n",
    "fig, ax = plt.subplots(figsize=(8.4,4.4))\n",
    "ax.plot(t, jp[:150].T, color=\"#1B6B52\", alpha=.04)\n",
    "ax.plot(t, X0*np.exp((MU+LAM_J*(MJ-1))*t), c=\"#C8A24B\", lw=2.5, label=f\"mean with jumps → {mean_T_jumps():.1f}\")\n",
    "ax.plot(t, X0*np.exp(MU*t), c=\"#8A8F8B\", lw=1.8, ls=\"--\", label=f\"diffusion-only mean → {mean_T():.1f}\")\n",
    "ax.set(xlabel=\"years\", ylabel=\"enterprise value\", title=\"Jump-diffusion: discrete events on a continuous base (seed 26109)\")\n",
    "ax.legend(frameon=False); ax.grid(alpha=.25); plt.tight_layout(); plt.show()\n",
    "print(f\"jump drag at t=5 (analytic): {mean_T()-mean_T_jumps():.4f}\")\n",
    "print(f\"MC mean with jumps: {jp[:,-1].mean():.4f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f1132edb",
   "metadata": {},
   "source": [
    "## Validation — agrees with `DCT_V1_Ch08_Lab.xlsx` (analytic core)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0f3b8728",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T22:42:40.655501Z",
     "iopub.status.busy": "2026-07-13T22:42:40.655315Z",
     "iopub.status.idle": "2026-07-13T22:42:40.662045Z",
     "shell.execute_reply": "2026-07-13T22:42:40.661042Z"
    }
   },
   "outputs": [],
   "source": [
    "ref = reference_values()\n",
    "expected = {\"mean_t5\":149.1825,\"median_t5\":127.6025,\"mean_median_gap\":21.5799,\n",
    " \"p_breach_t5\":0.2018,\"mean_t5_jumps\":122.1403,\"jump_drag\":27.0422,\"sigma_sqrtT\":0.559}\n",
    "for k,v in expected.items():\n",
    "    assert abs(ref[k]-v)<5e-4, f\"MISMATCH {k}\"\n",
    "    print(f\"PASS  {k:18s} {ref[k]}\")\n",
    "print(\"\\nAll checkpoints agree — seed 26108.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1286e005",
   "metadata": {},
   "source": [
    "**Next**: Exercises 8.9–8.12 (Part C) vary σ, λ, and the barrier; AXIOM-08's fan theater animates Panel 1 with a σ-slider whose zero position is Chapter 7. Solutions: IM Ch. 8."
   ]
  }
 ],
 "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
}
