{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "e3014562",
   "metadata": {},
   "source": [
    "# DCT Laboratory — Volume I, Chapter 1\n",
    "## Introduction to Dynamic Corporate Transformation\n",
    "**Seed `26101`** · Companion to the chapter and to AXIOM Module **AXIOM-01**\n",
    "\n",
    "This notebook puts the chapter's central image in your hands: the **Meridian Group**\n",
    "at its initial state $\\mathbf{x}_0 \\in \\mathbb{R}^8$ (eq. 1.1 of the book), and the\n",
    "board's three options — **digital transformation**, **restructuring**, **turnaround** —\n",
    "as three trajectories through the state space $\\mathcal{X}$.\n",
    "\n",
    "The deterministic core below is reproduced, formula for formula, in the Excel\n",
    "workbook `DCT_V1_Ch01_Lab.xlsx`; the validation cell at the end checks the two agree.\n",
    "Read §1.1 and Examples 1.1–1.3 of the book before running."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6dddd3eb",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T21:21:44.388826Z",
     "iopub.status.busy": "2026-07-13T21:21:44.387579Z",
     "iopub.status.idle": "2026-07-13T21:21:46.328555Z",
     "shell.execute_reply": "2026-07-13T21:21:46.327282Z"
    }
   },
   "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",
    "\n",
    "SEED = 26101\n",
    "COORDS = [\"x1 Liquidity\", \"x2 Leverage\", \"x3 Workforce capability\",\n",
    "          \"x4 Technology platform\", \"x5 Operational efficiency\",\n",
    "          \"x6 ROIC\", \"x7 Strategic risk\", \"x8 Market share\"]\n",
    "\n",
    "# Meridian initial state (index form, x6 in %, x8 in % share)\n",
    "X0 = np.array([100.0, 3.2, 62.0, 41.0, 68.0, 9.5, 55.0, 17.5])\n",
    "\n",
    "T_YEARS, STEPS_PER_YEAR = 5.0, 12\n",
    "N = int(T_YEARS * STEPS_PER_YEAR)          # 60 monthly steps\n",
    "TGRID = np.arange(N + 1) / STEPS_PER_YEAR  # 0..5 years\n",
    "\n",
    "def relax(x0, xinf, k, t):\n",
    "    \"\"\"Exponential relaxation toward xinf.\"\"\"\n",
    "    return xinf + (x0 - xinf) * np.exp(-k * t)\n",
    "\n",
    "def trough(D, tau, t):\n",
    "    \"\"\"Trough term: depth D at t = tau, Excel-friendly form D*(t/tau)*exp(1-t/tau).\"\"\"\n",
    "    return D * (t / tau) * np.exp(1.0 - t / tau)\n",
    "\n",
    "# --- deterministic cores: dict coord-name -> array over TGRID ---\n",
    "def digital(t=TGRID):\n",
    "    return {\n",
    "        \"x1\": relax(X0[0], 112.0, 0.35, t) - trough(28.0, 2.0, t),\n",
    "        \"x4\": relax(X0[3], 78.0, 0.55, t),\n",
    "        \"x5\": relax(X0[4], 74.0, 0.50, t) - trough(9.0, 1.5, t),\n",
    "        \"x7\": relax(X0[6], 42.0, 0.40, t) + trough(14.0, 1.2, t),\n",
    "    }\n",
    "\n",
    "def restructuring(t=TGRID, t_jump=1.0):\n",
    "    j = (t >= t_jump).astype(float)\n",
    "    return {\n",
    "        \"x1\": relax(X0[0], 104.0, 0.30, t) + 18.0 * j,\n",
    "        \"x4\": relax(X0[3], 38.0, 0.25, t),\n",
    "        \"x5\": relax(X0[4], 71.0, 0.45, t),\n",
    "        \"x7\": relax(X0[6], 47.0, 0.35, t) - 8.0 * j,\n",
    "    }\n",
    "\n",
    "def turnaround(t=TGRID):\n",
    "    return {\n",
    "        \"x1\": relax(X0[0], 106.0, 0.45, t),\n",
    "        \"x4\": relax(X0[3], 33.0, 0.20, t),\n",
    "        \"x5\": relax(X0[4], 76.0, 0.60, t),\n",
    "        \"x7\": relax(X0[6], 58.0, 0.30, t),\n",
    "    }\n",
    "\n",
    "OPTIONS = {\"Digital\": digital, \"Restructuring\": restructuring, \"Turnaround\": turnaround}\n",
    "\n",
    "def monte_carlo_fan(option=\"Digital\", coord=\"x1\", n_paths=200, sigma=2.2):\n",
    "    \"\"\"Seeded stochastic fan around the deterministic core (notebook only).\"\"\"\n",
    "    rng = np.random.default_rng(SEED)\n",
    "    core = OPTIONS[option]()[coord]\n",
    "    dW = rng.standard_normal((n_paths, N)) / np.sqrt(STEPS_PER_YEAR)\n",
    "    noise = np.cumsum(sigma * dW, axis=1)\n",
    "    return core, np.hstack([np.zeros((n_paths, 1)), noise]) + core\n",
    "\n",
    "def reference_values():\n",
    "    \"\"\"Canonical checkpoints — must match the Excel workbook to 4 dp.\"\"\"\n",
    "    d, r, u = digital(), restructuring(), turnaround()\n",
    "    i30, i60 = 30, 60   # t = 2.5y, 5.0y\n",
    "    return {\n",
    "        \"digital_x1_t2.5 (trough zone)\": round(d[\"x1\"][i30], 4),\n",
    "        \"digital_x1_t5.0\": round(d[\"x1\"][i60], 4),\n",
    "        \"digital_x4_t5.0\": round(d[\"x4\"][i60], 4),\n",
    "        \"restr_x1_jump_delta\": 18.0,\n",
    "        \"restr_x1_t5.0\": round(r[\"x1\"][i60], 4),\n",
    "        \"turn_x5_t5.0\": round(u[\"x5\"][i60], 4),\n",
    "        \"turn_x4_t5.0\": round(u[\"x4\"][i60], 4),\n",
    "        \"digital_x1_min_over_grid\": round(d[\"x1\"].min(), 4),\n",
    "    }\n",
    "\n",
    "if __name__ == \"__main__\":\n",
    "    for k, v in reference_values().items():\n",
    "        print(f\"{k:38s} {v}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7c1847a7",
   "metadata": {},
   "source": [
    "## Panel 1 — The state inspector\n",
    "The eight coordinates of $\\mathbf{x}_0$: a deliberately coarse first representation.\n",
    "The point of Chapter 1 is not these particular numbers — it is that *once a state is\n",
    "declared, transformation becomes motion through a space* (Proposition 1.1)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f37daad9",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T21:21:46.330768Z",
     "iopub.status.busy": "2026-07-13T21:21:46.330343Z",
     "iopub.status.idle": "2026-07-13T21:21:46.335892Z",
     "shell.execute_reply": "2026-07-13T21:21:46.334873Z"
    }
   },
   "outputs": [],
   "source": [
    "for name, v in zip(COORDS, X0):\n",
    "    print(f\"{name:28s} {v:8.1f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "25a44309",
   "metadata": {},
   "source": [
    "## Panel 2 — Three options, three trajectories\n",
    "Liquidity $x_1(t)$ under each option. Note the **digital trough** (transformations\n",
    "die mid-trajectory, not at endpoints — Example 1.1), the **restructuring jump** at\n",
    "$t=1$ (Example 1.2, foreshadowing Ch. 6 discrete operators and Ch. 8 jump processes),\n",
    "and the turnaround's modest, safe drift (Example 1.3)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b2719925",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T21:21:46.337648Z",
     "iopub.status.busy": "2026-07-13T21:21:46.337464Z",
     "iopub.status.idle": "2026-07-13T21:21:46.678040Z",
     "shell.execute_reply": "2026-07-13T21:21:46.676748Z"
    }
   },
   "outputs": [],
   "source": [
    "fig, ax = plt.subplots(figsize=(8, 4.4))\n",
    "colors = {\"Digital\": \"#C8A24B\", \"Restructuring\": \"#1B6B52\", \"Turnaround\": \"#8A8F8B\"}\n",
    "for name, fn in OPTIONS.items():\n",
    "    ax.plot(TGRID, fn()[\"x1\"], lw=2.4, color=colors[name], label=name)\n",
    "ax.axhline(X0[0], ls=\":\", c=\"k\", lw=0.8)\n",
    "ax.set(xlabel=\"years\", ylabel=\"$x_1$ liquidity (index)\",\n",
    "       title=\"Meridian: liquidity under three transformation programs\")\n",
    "ax.legend(frameon=False); ax.grid(alpha=0.25)\n",
    "plt.tight_layout(); plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ac56bdbd",
   "metadata": {},
   "source": [
    "## Panel 3 — The trajectory, not the endpoint\n",
    "Phase view $(x_4, x_1)$: technology platform against liquidity. Two programs could\n",
    "share a terminal state and still differ enormously in the depth of the liquidity\n",
    "trough traversed to reach it — the trough is a first-class object of analysis."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cc88ef1d",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T21:21:46.680231Z",
     "iopub.status.busy": "2026-07-13T21:21:46.680033Z",
     "iopub.status.idle": "2026-07-13T21:21:46.956893Z",
     "shell.execute_reply": "2026-07-13T21:21:46.955672Z"
    }
   },
   "outputs": [],
   "source": [
    "fig, ax = plt.subplots(figsize=(6.4, 5))\n",
    "for name, fn in OPTIONS.items():\n",
    "    tr = fn()\n",
    "    ax.plot(tr[\"x4\"], tr[\"x1\"], lw=2.2, color=colors[name], label=name)\n",
    "    ax.scatter(tr[\"x4\"][-1], tr[\"x1\"][-1], color=colors[name], zorder=5)\n",
    "ax.scatter([X0[3]], [X0[0]], c=\"k\", zorder=6)\n",
    "ax.annotate(\"$\\\\mathbf{x}_0$\", (X0[3], X0[0]), textcoords=\"offset points\", xytext=(8, -12))\n",
    "ax.set(xlabel=\"$x_4$ technology platform\", ylabel=\"$x_1$ liquidity\",\n",
    "       title=\"State-space view: three trajectories from one initial state\")\n",
    "ax.legend(frameon=False); ax.grid(alpha=0.25)\n",
    "plt.tight_layout(); plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "299acd74",
   "metadata": {},
   "source": [
    "## Panel 4 — The seeded fan\n",
    "The deterministic core is a modeling fiction; the environment disturbs every\n",
    "trajectory. A 200-path fan around the digital option's liquidity, seeded `26101` so\n",
    "your fan is everyone's fan."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dfc43882",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T21:21:46.959111Z",
     "iopub.status.busy": "2026-07-13T21:21:46.958889Z",
     "iopub.status.idle": "2026-07-13T21:21:47.528131Z",
     "shell.execute_reply": "2026-07-13T21:21:47.527345Z"
    }
   },
   "outputs": [],
   "source": [
    "core, paths = monte_carlo_fan(\"Digital\", \"x1\", n_paths=200)\n",
    "fig, ax = plt.subplots(figsize=(8, 4.4))\n",
    "ax.plot(TGRID, paths.T, color=\"#C8A24B\", alpha=0.05)\n",
    "ax.plot(TGRID, core, color=\"#0B3D2E\", lw=2.6, label=\"deterministic core\")\n",
    "q10, q90 = np.quantile(paths, [0.1, 0.9], axis=0)\n",
    "ax.plot(TGRID, q10, \"--\", c=\"#0B3D2E\", lw=1.1, label=\"10–90% band\")\n",
    "ax.plot(TGRID, q90, \"--\", c=\"#0B3D2E\", lw=1.1)\n",
    "ax.set(xlabel=\"years\", ylabel=\"$x_1$ liquidity\",\n",
    "       title=\"Digital option: seeded Monte Carlo fan (n=200, seed 26101)\")\n",
    "ax.legend(frameon=False); ax.grid(alpha=0.25)\n",
    "plt.tight_layout(); plt.show()\n",
    "print(\"Trough of the core:\", round(core.min(), 4), \"at t =\", TGRID[core.argmin()], \"years\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dcbc415d",
   "metadata": {},
   "source": [
    "## Panel 5 — Why no scalar suffices (Proposition 1.2)\n",
    "Two distinct enterprise states with the **same scalar score**: a continuous scalar\n",
    "metric on a state space of dimension $\\ge 2$ must identify some pair of distinct\n",
    "states. Here: equal-weighted composite of the digital and restructuring terminal\n",
    "states after normalization — different enterprises, one number."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6454a6ab",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T21:21:47.540326Z",
     "iopub.status.busy": "2026-07-13T21:21:47.539955Z",
     "iopub.status.idle": "2026-07-13T21:21:47.551864Z",
     "shell.execute_reply": "2026-07-13T21:21:47.550591Z"
    }
   },
   "outputs": [],
   "source": [
    "d5 = np.array([digital()[k][-1] for k in (\"x1\",\"x4\",\"x5\",\"x7\")])\n",
    "r5 = np.array([restructuring()[k][-1] for k in (\"x1\",\"x4\",\"x5\",\"x7\")])\n",
    "w  = np.array([0.25, 0.25, 0.25, -0.25])          # composite score weights\n",
    "# rescale restructuring state along the score's null direction until scores match\n",
    "null = np.array([1.0, -1.0, 0.0, 0.0])            # w @ null == 0\n",
    "r5_adj = r5 + ((w @ (d5 - r5)) / 1.0) * 0 + null * 0\n",
    "alpha = (w @ d5 - w @ r5) / (w @ np.array([1,0,0,0]))\n",
    "r5_same_score = r5 + np.array([alpha, 0, 0, 0])\n",
    "print(\"Digital terminal state       :\", np.round(d5, 3))\n",
    "print(\"Restructuring (score-matched):\", np.round(r5_same_score, 3))\n",
    "print(\"Composite score, digital     :\", round(float(w @ d5), 4))\n",
    "print(\"Composite score, restructured:\", round(float(w @ r5_same_score), 4))\n",
    "print(\"States equal?\", np.allclose(d5, r5_same_score), \" — distinct states, identical score.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "494c807b",
   "metadata": {},
   "source": [
    "## Validation — the MFMF convention\n",
    "These checkpoints are the workbook's `Reference_Values` tab. If any assertion fails,\n",
    "your environment and the canonical engine disagree — stop and investigate."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7206dce6",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T21:21:47.553901Z",
     "iopub.status.busy": "2026-07-13T21:21:47.553616Z",
     "iopub.status.idle": "2026-07-13T21:21:47.561772Z",
     "shell.execute_reply": "2026-07-13T21:21:47.560530Z"
    }
   },
   "outputs": [],
   "source": [
    "ref = reference_values()\n",
    "expected = {\n",
    " \"digital_x1_t2.5 (trough zone)\": 79.7396, \"digital_x1_t5.0\": 94.2956,\n",
    " \"digital_x4_t5.0\": 75.6347, \"restr_x1_jump_delta\": 18.0,\n",
    " \"restr_x1_t5.0\": 121.1075, \"turn_x5_t5.0\": 75.6017,\n",
    " \"turn_x4_t5.0\": 35.943, \"digital_x1_min_over_grid\": 77.7339}\n",
    "for k, v in expected.items():\n",
    "    assert abs(ref[k] - v) < 5e-4, f\"MISMATCH {k}: {ref[k]} vs {v}\"\n",
    "    print(f\"PASS  {k:38s} {ref[k]}\")\n",
    "print(\"\\nAll checkpoints agree with DCT_V1_Ch01_Lab.xlsx — seed 26101.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "710d422c",
   "metadata": {},
   "source": [
    "---\n",
    "**Next**: Exercises 1.9–1.12 (Part C, computational) extend this laboratory; AXIOM\n",
    "Module **AXIOM-01** provides the interactive version with radar and\n",
    "parallel-coordinate views of $\\mathbf{x}_0$. Full solutions: Instructor's Manual, Ch. 1."
   ]
  }
 ],
 "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
}
