{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "60e45a53",
   "metadata": {},
   "source": [
    "# DCT Laboratory — Volume I, Chapter 5\n",
    "## Enterprise State Representation\n",
    "**Seed `26105`** · Companion to the chapter and AXIOM Module **AXIOM-05**\n",
    "\n",
    "The state chapter's instruments: **equilibria** of the startup logistic (the\n",
    "expansive phase near the unstable equilibrium at 0, the wall at $\\kappa$),\n",
    "**feasibility as simultaneous constraint satisfaction**, and the **curse of\n",
    "dimensionality** that makes Section 5.8's visualization tools necessary.\n",
    "Mirrored in `DCT_V1_Ch05_Lab.xlsx`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fd3d68ab",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T22:08:48.584193Z",
     "iopub.status.busy": "2026-07-13T22:08:48.584000Z",
     "iopub.status.idle": "2026-07-13T22:08:49.077860Z",
     "shell.execute_reply": "2026-07-13T22:08:49.076718Z"
    }
   },
   "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 pi, lgamma, exp\n",
    "SEED = 26105\n",
    "R, KAPPA, X0, DT, N = 0.9, 100.0, 2.0, 0.25, 40\n",
    "\n",
    "def logistic_path(x0=X0, n=N):\n",
    "    x = np.empty(n+1); x[0] = x0\n",
    "    for k in range(n): x[k+1] = x[k] + DT*R*x[k]*(1 - x[k]/KAPPA)\n",
    "    return x\n",
    "\n",
    "# Feasibility: constraints on (x1 liquidity, x2 leverage)\n",
    "# g1: x1 >= 20 ; g2: x2 <= 4.5 ; g3: x1 - 8*x2 >= -10\n",
    "CANDS = np.array([[100.0,3.2],[15.0,2.0],[60.0,5.0],[25.0,4.4]])\n",
    "def feasible(x1, x2):\n",
    "    return (x1 >= 20) and (x2 <= 4.5) and (x1 - 8*x2 >= -10)\n",
    "\n",
    "def ball_cube_ratio(n):\n",
    "    \"\"\"V_ball(radius 1) / V_cube(side 2) = pi^(n/2) / (2^n * Gamma(n/2+1)).\"\"\"\n",
    "    return exp((n/2)*np.log(pi) - n*np.log(2) - lgamma(n/2 + 1))\n",
    "\n",
    "def mc_fan(n_paths=200, sigma=1.6):\n",
    "    rng = np.random.default_rng(SEED)\n",
    "    out = np.empty((n_paths, N+1))\n",
    "    for p in range(n_paths):\n",
    "        x = X0; out[p,0] = x\n",
    "        for k in range(N):\n",
    "            x = max(x + DT*R*x*(1-x/KAPPA) + sigma*np.sqrt(DT)*rng.standard_normal(), 0.0)\n",
    "            out[p,k+1] = x\n",
    "    return out\n",
    "\n",
    "def reference_values():\n",
    "    x = logistic_path()\n",
    "    feas = [feasible(*c) for c in CANDS]\n",
    "    return {\n",
    "        \"logistic_t5\":   round(x[20], 4),\n",
    "        \"logistic_t10\":  round(x[-1], 4),\n",
    "        \"dist_to_kappa\": round(KAPPA - x[-1], 4),\n",
    "        \"n_feasible\":    int(sum(feas)),\n",
    "        \"cand2_g1_slack\":round(CANDS[1,0]-20, 4),\n",
    "        \"ball_cube_n2\":  round(ball_cube_ratio(2), 6),\n",
    "        \"ball_cube_n8\":  round(ball_cube_ratio(8), 6),\n",
    "    }\n",
    "if __name__ == \"__main__\":\n",
    "    [print(f\"{k:18s} {v}\") for k,v in reference_values().items()]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "edc06622",
   "metadata": {},
   "source": [
    "## Panel 1 — Two equilibria, one startup\n",
    "$x_{k+1} = x_k + \\Delta t\\, r x_k (1 - x_k/\\kappa)$: the origin is an **unstable**\n",
    "equilibrium (the expansive phase lives in its neighborhood), $\\kappa = 100$ is the\n",
    "**stable** one (Enterprise Equilibrium Theorem). The trajectory is the regime\n",
    "handover the CFO memo of Exercise 5.18 demands."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "330dbd72",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T22:08:49.079761Z",
     "iopub.status.busy": "2026-07-13T22:08:49.079505Z",
     "iopub.status.idle": "2026-07-13T22:08:49.275461Z",
     "shell.execute_reply": "2026-07-13T22:08:49.274363Z"
    }
   },
   "outputs": [],
   "source": [
    "x = logistic_path(); t = np.arange(N+1)*DT\n",
    "fig, ax = plt.subplots(figsize=(8,4.2))\n",
    "ax.plot(t, x, c=\"#C8A24B\", lw=2.4)\n",
    "ax.axhline(0, c=\"#8A8F8B\", ls=\":\", lw=1); ax.axhline(KAPPA, c=\"#0B3D2E\", ls=\":\", lw=1)\n",
    "ax.annotate(\"unstable equilibrium\", (0.3, 3), fontsize=9, color=\"#8A8F8B\")\n",
    "ax.annotate(\"stable equilibrium κ\", (0.3, KAPPA-6), fontsize=9, color=\"#0B3D2E\")\n",
    "ax.set(xlabel=\"years\", ylabel=\"enterprise scale x\", title=\"The startup logistic (seed 26105)\")\n",
    "ax.grid(alpha=.25); plt.tight_layout(); plt.show()\n",
    "print(\"x(t=5) =\", round(x[20],4), \"  x(t=10) =\", round(x[-1],4), \"  gap to κ =\", round(KAPPA-x[-1],4))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6f7b33e2",
   "metadata": {},
   "source": [
    "## Panel 2 — The seeded fan: equilibrium as attractor\n",
    "200 disturbed paths. The stable equilibrium organizes the whole distribution —\n",
    "which is exactly what makes equilibria decision-relevant objects rather than\n",
    "curiosities."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0646d420",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T22:08:49.277957Z",
     "iopub.status.busy": "2026-07-13T22:08:49.277203Z",
     "iopub.status.idle": "2026-07-13T22:08:49.852496Z",
     "shell.execute_reply": "2026-07-13T22:08:49.851853Z"
    }
   },
   "outputs": [],
   "source": [
    "paths = mc_fan()\n",
    "fig, ax = plt.subplots(figsize=(8,4.2))\n",
    "ax.plot(t, paths.T, color=\"#1B6B52\", alpha=.05)\n",
    "ax.plot(t, logistic_path(), color=\"#0B3D2E\", lw=2.4, label=\"deterministic core\")\n",
    "ax.axhline(KAPPA, c=\"#C8A24B\", ls=\"--\", lw=1.2, label=\"κ\")\n",
    "ax.set(xlabel=\"years\", ylabel=\"x\", title=\"The attractor at work (n=200)\")\n",
    "ax.legend(frameon=False); ax.grid(alpha=.25); plt.tight_layout(); plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b8a5fe7b",
   "metadata": {},
   "source": [
    "## Panel 3 — Feasibility is simultaneous satisfaction\n",
    "Three constraints on $(x_1, x_2)$: a liquidity floor, the covenant wall\n",
    "$x_2 \\le 4.5$, and a coupling constraint. Four candidate states; **one** is feasible\n",
    "— and one fails by 0.2 on a constraint it never looked at, which is the\n",
    "proposition's point: constraints bind **jointly**."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8a9394cd",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T22:08:49.862517Z",
     "iopub.status.busy": "2026-07-13T22:08:49.862206Z",
     "iopub.status.idle": "2026-07-13T22:08:49.870227Z",
     "shell.execute_reply": "2026-07-13T22:08:49.869225Z"
    }
   },
   "outputs": [],
   "source": [
    "g = [(\"x1 ≥ 20\",        lambda c: c[0]-20),\n",
    "     (\"x2 ≤ 4.5\",       lambda c: 4.5-c[1]),\n",
    "     (\"x1 − 8x2 ≥ −10\", lambda c: c[0]-8*c[1]+10)]\n",
    "print(f\"{'candidate':>16s}  \" + \"  \".join(f\"{n:>14s}\" for n,_ in g) + \"   feasible\")\n",
    "for c in CANDS:\n",
    "    slacks = [f(c) for _,f in g]\n",
    "    print(f\"({c[0]:6.1f},{c[1]:4.1f})   \" + \"  \".join(f\"{s:14.2f}\" for s in slacks) +\n",
    "          f\"   {'YES' if all(s>=0 for s in slacks) else 'no'}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2cb9a470",
   "metadata": {},
   "source": [
    "## Panel 4 — The curse of dimensionality\n",
    "The fraction of the cube occupied by the inscribed ball collapses with dimension:\n",
    "at $n=8$ (Meridian's state) it is already **1.6%**. \"Typical\" states are corner\n",
    "states; low-dimensional intuition fails — hence the radar and parallel-coordinate\n",
    "instruments of §5.8 and AXIOM-05."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0633d405",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T22:08:49.872457Z",
     "iopub.status.busy": "2026-07-13T22:08:49.871769Z",
     "iopub.status.idle": "2026-07-13T22:08:50.040258Z",
     "shell.execute_reply": "2026-07-13T22:08:50.039231Z"
    }
   },
   "outputs": [],
   "source": [
    "ns = np.arange(1,13)\n",
    "ratios = [ball_cube_ratio(int(n)) for n in ns]\n",
    "fig, ax = plt.subplots(figsize=(7.4,4.0))\n",
    "ax.bar(ns, ratios, color=\"#0B3D2E\")\n",
    "ax.bar([8],[ball_cube_ratio(8)], color=\"#C8A24B\")\n",
    "ax.set(xlabel=\"dimension n\", ylabel=\"V_ball / V_cube\", title=\"The curse, quantified\")\n",
    "ax.grid(alpha=.25, axis=\"y\"); plt.tight_layout(); plt.show()\n",
    "print(\"n=2 :\", round(ball_cube_ratio(2),6), \"   n=8 :\", round(ball_cube_ratio(8),6))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d6707e57",
   "metadata": {},
   "source": [
    "## Validation — agrees with `DCT_V1_Ch05_Lab.xlsx`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fe99ccea",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T22:08:50.042324Z",
     "iopub.status.busy": "2026-07-13T22:08:50.042121Z",
     "iopub.status.idle": "2026-07-13T22:08:50.049060Z",
     "shell.execute_reply": "2026-07-13T22:08:50.047996Z"
    }
   },
   "outputs": [],
   "source": [
    "ref = reference_values()\n",
    "expected = {\"logistic_t5\":58.1286,\"logistic_t10\":99.4909,\"dist_to_kappa\":0.5091,\n",
    " \"n_feasible\":1,\"cand2_g1_slack\":-5.0,\"ball_cube_n2\":0.785398,\"ball_cube_n8\":0.015854}\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 26105.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9709fad7",
   "metadata": {},
   "source": [
    "**Next**: Exercises 5.9–5.12 rebuild these panels with AXIOM-05 or this notebook (the book says so explicitly). Solutions: IM Ch. 5."
   ]
  }
 ],
 "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
}
