{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "bf3aa60b",
   "metadata": {},
   "source": [
    "# DCT Laboratory — Volume I, Chapter 6\n",
    "## Enterprise Transformation Operators\n",
    "**Seed `26106`** · Companion to the chapter and AXIOM Module **AXIOM-06**\n",
    "\n",
    "The verb's grammar, computed: **iteration** driving the state to the sustainable\n",
    "core (the invariant fixed point of a contraction), **composition** where order\n",
    "matters, and **reachability** — which target configurations any sequence of feasible\n",
    "programs can attain. Mirrored in `DCT_V1_Ch06_Lab.xlsx`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5fe7dfea",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T22:20:46.693899Z",
     "iopub.status.busy": "2026-07-13T22:20:46.693723Z",
     "iopub.status.idle": "2026-07-13T22:20:47.501874Z",
     "shell.execute_reply": "2026-07-13T22:20:47.500629Z"
    }
   },
   "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",
    "SEED = 26106\n",
    "# 2-D state: (x4 technology, x5 efficiency); affine operator T(x) = A x + b\n",
    "A = np.array([[0.55, 0.15],[0.10, 0.60]])\n",
    "B = np.array([14.0, 24.0])\n",
    "X0 = np.array([41.0, 68.0])\n",
    "\n",
    "def T(x): return A @ x + B\n",
    "def core():                      # sustainable core = fixed point (I-A)^-1 b\n",
    "    return np.linalg.solve(np.eye(2) - A, B)\n",
    "def iterate(k=12, x0=X0):\n",
    "    xs = np.empty((k+1, 2)); xs[0] = x0\n",
    "    for i in range(k): xs[i+1] = T(xs[i])\n",
    "    return xs\n",
    "\n",
    "# Two named programs for composition/reachability\n",
    "A1 = np.array([[1.10, 0.00],[-0.06, 0.98]]); B1 = np.array([0.0, 4.0])   # digital push\n",
    "A2 = np.array([[0.97, 0.05],[0.00, 1.04]]);  B2 = np.array([2.0, 0.0])   # cost program\n",
    "def T1(x): return A1 @ x + B1\n",
    "def T2(x): return A2 @ x + B2\n",
    "\n",
    "def reachable(depth=3):\n",
    "    \"\"\"All 2^depth endpoints from X0 applying T1/T2 in every order.\"\"\"\n",
    "    states = [X0]\n",
    "    for _ in range(depth):\n",
    "        states = [f(s) for s in states for f in (T1, T2)]\n",
    "    return np.array(states)\n",
    "\n",
    "TARGET = lambda x: (x[0] >= 48.0) and (x[1] >= 71.0)   # 4 of 8 depth-3 sequences reach it\n",
    "\n",
    "def reference_values():\n",
    "    c = core(); xs = iterate()\n",
    "    r1 = float(np.linalg.norm(xs[1]-c)/np.linalg.norm(xs[0]-c))\n",
    "    gap = float(np.linalg.norm(T2(T1(X0)) - T1(T2(X0))))\n",
    "    reach = reachable()\n",
    "    return {\n",
    "        \"core_x4\": round(float(c[0]),4), \"core_x5\": round(float(c[1]),4),\n",
    "        \"iter10_x4\": round(float(xs[10,0]),4), \"iter10_x5\": round(float(xs[10,1]),4),\n",
    "        \"contraction_ratio\": round(r1,4),\n",
    "        \"order_gap\": round(gap,4),\n",
    "        \"n_reachable_in_target\": int(sum(TARGET(s) for s in reach)),\n",
    "        \"spectral_radius_A\": round(float(max(abs(np.linalg.eigvals(A)))),4),\n",
    "    }\n",
    "if __name__ == \"__main__\":\n",
    "    [print(f\"{k:24s} {v}\") for k,v in reference_values().items()]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5f362025",
   "metadata": {},
   "source": [
    "## Panel 1 — Iteration and the sustainable core\n",
    "$T(\\mathbf{x}) = A\\mathbf{x} + \\mathbf{b}$ with spectral radius 0.7: a contraction.\n",
    "Iterates converge geometrically to the **invariant fixed point** — the sustainable\n",
    "core of §6.4. The contraction ratio measured on the first step already predicts the\n",
    "whole approach."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "78ad6a10",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T22:20:47.503985Z",
     "iopub.status.busy": "2026-07-13T22:20:47.503714Z",
     "iopub.status.idle": "2026-07-13T22:20:47.889927Z",
     "shell.execute_reply": "2026-07-13T22:20:47.888870Z"
    }
   },
   "outputs": [],
   "source": [
    "c = core(); xs = iterate(12)\n",
    "fig, ax = plt.subplots(figsize=(6.4,5.2))\n",
    "ax.plot(xs[:,0], xs[:,1], \"o-\", c=\"#C8A24B\", lw=2, ms=5)\n",
    "ax.scatter([c[0]],[c[1]], c=\"#0B3D2E\", s=90, zorder=5, label=\"sustainable core x* = (I−A)⁻¹b\")\n",
    "ax.annotate(\"$x_0$\", xs[0], textcoords=\"offset points\", xytext=(8,-4))\n",
    "ax.set(xlabel=\"$x_4$ technology\", ylabel=\"$x_5$ efficiency\",\n",
    "       title=\"Iteration $T^k x_0$ → the invariant core (seed 26106)\")\n",
    "ax.legend(frameon=False); ax.grid(alpha=.25); plt.tight_layout(); plt.show()\n",
    "print(\"core:\", np.round(c,4), \" iterate k=10:\", np.round(xs[10],4))\n",
    "print(\"first-step contraction ratio:\", round(float(np.linalg.norm(xs[1]-c)/np.linalg.norm(xs[0]-c)),4),\n",
    "      \"  (spectral radius:\", round(float(max(abs(np.linalg.eigvals(A)))),4),\")\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0310d2b8",
   "metadata": {},
   "source": [
    "## Panel 2 — Composition: order matters\n",
    "The digital push $T_1$ then the cost program $T_2$, versus the reverse. Same two\n",
    "operators, different terminal states — the Transformation Composition Theorem says\n",
    "composites are valid operators; it does not say they commute."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e064afa8",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T22:20:47.891818Z",
     "iopub.status.busy": "2026-07-13T22:20:47.891630Z",
     "iopub.status.idle": "2026-07-13T22:20:47.897849Z",
     "shell.execute_reply": "2026-07-13T22:20:47.896774Z"
    }
   },
   "outputs": [],
   "source": [
    "a = T2(T1(X0)); b = T1(T2(X0))\n",
    "print(\"T2∘T1(x0):\", np.round(a,4))\n",
    "print(\"T1∘T2(x0):\", np.round(b,4))\n",
    "print(\"order gap ‖·‖:\", round(float(np.linalg.norm(a-b)),4))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "280cc283",
   "metadata": {},
   "source": [
    "## Panel 3 — Reachability under a feasible set\n",
    "Every depth-3 sequence over $\\{T_1, T_2\\}$: $2^3 = 8$ endpoints from one $x_0$.\n",
    "The target region ($x_4 \\ge 48$, $x_5 \\ge 71$) is reached by exactly **4** sequences\n",
    "— reachability is a property of the *set* of feasible operators, not of any single\n",
    "program (§6.6)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f12bb25b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T22:20:47.900239Z",
     "iopub.status.busy": "2026-07-13T22:20:47.899596Z",
     "iopub.status.idle": "2026-07-13T22:20:48.155319Z",
     "shell.execute_reply": "2026-07-13T22:20:48.153063Z"
    }
   },
   "outputs": [],
   "source": [
    "r = reachable(3)\n",
    "fig, ax = plt.subplots(figsize=(6.6,5.2))\n",
    "inT = np.array([TARGET(s) for s in r])\n",
    "ax.scatter(r[~inT,0], r[~inT,1], c=\"#8A8F8B\", s=60, label=\"misses target\")\n",
    "ax.scatter(r[inT,0],  r[inT,1],  c=\"#C8A24B\", s=80, label=\"reaches target\")\n",
    "ax.scatter([X0[0]],[X0[1]], c=\"k\", s=70, zorder=5)\n",
    "ax.annotate(\"$x_0$\", X0, textcoords=\"offset points\", xytext=(8,-4))\n",
    "ax.axvline(48, ls=\":\", c=\"#0B3D2E\", lw=1); ax.axhline(71, ls=\":\", c=\"#0B3D2E\", lw=1)\n",
    "ax.set(xlabel=\"$x_4$\", ylabel=\"$x_5$\", title=\"8 sequences, 8 endpoints, 4 in-target\")\n",
    "ax.legend(frameon=False); ax.grid(alpha=.25); plt.tight_layout(); plt.show()\n",
    "print(\"endpoints in target:\", int(inT.sum()), \"of\", len(r))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b2e1559a",
   "metadata": {},
   "source": [
    "## Validation — agrees with `DCT_V1_Ch06_Lab.xlsx`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bc9ce869",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-13T22:20:48.158102Z",
     "iopub.status.busy": "2026-07-13T22:20:48.157815Z",
     "iopub.status.idle": "2026-07-13T22:20:48.165560Z",
     "shell.execute_reply": "2026-07-13T22:20:48.164572Z"
    }
   },
   "outputs": [],
   "source": [
    "ref = reference_values()\n",
    "expected = {\"core_x4\":55.7576,\"core_x5\":73.9394,\"iter10_x4\":55.4884,\"iter10_x5\":73.6732,\n",
    " \"contraction_ratio\":0.6488,\"order_gap\":0.6158,\"n_reachable_in_target\":4,\"spectral_radius_A\":0.7}\n",
    "for k,v in expected.items():\n",
    "    assert abs(ref[k]-v)<5e-4, f\"MISMATCH {k}\"\n",
    "    print(f\"PASS  {k:24s} {ref[k]}\")\n",
    "print(\"\\nAll checkpoints agree — seed 26106.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fe653af6",
   "metadata": {},
   "source": [
    "**Next**: Exercises 6.9–6.12 (Part C); AXIOM-06's operator bench animates iteration and reachability trees. Solutions: IM Ch. 6."
   ]
  }
 ],
 "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
}
