{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "dec5c13a",
   "metadata": {},
   "source": [
    "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/MeiraDavidson/biology_aging/blob/main/notebooks/build-the-goldilocks-dose.ipynb)\n\n",
    "# The Goldilocks Dose: Why \"More\" Is the Wrong Question 🥣\n",
    "### A hands-on companion to Chapter 4\n",
    "\n",
    "Chapter 4 is about the **nutrient-sensing dials** — mTOR, IGF-1, AMPK, sirtuins — that switch your cells between **growing** and **maintaining themselves**. Its biggest surprise is that the interventions which most reliably extend life in animals — **caloric restriction, rapamycin, even exercise** — all work by *mild stress*, and they all follow the same shape: **too little does nothing, too much does harm, and the benefit lives at an intermediate dose.** Biologists call it **hormesis**.\n",
    "\n",
    "In this notebook you'll:\n",
    "1. **build** that inverted-U curve from the two opposing forces underneath it,\n",
    "2. discover why **every intervention has its own sweet spot**, and\n",
    "3. uncover the deeper reason it all works — the **growth-vs-maintenance trade-off** — and why it means *we may be able to live longer than evolution tuned us to.*\n",
    "\n",
    "No setup. Runs in Colab. Press ▶ on each cell, top to bottom."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "67022386",
   "metadata": {},
   "source": [
    "## Step 0 — Tools"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a3379725",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "print(\"Ready.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a6cdc41d",
   "metadata": {},
   "source": [
    "## Part 1 — Build the curve from two opposing forces\n",
    "\n",
    "A hormetic intervention does **two things at once**:\n",
    "\n",
    "- It switches on **protective maintenance** — autophagy, stress defenses, repair — but with *diminishing returns* (the first bit of stress helps a lot; more helps less). We'll model that benefit as a saturating curve: `B(d) = Bmax · d/(Kd + d)`.\n",
    "- It also does **direct harm** that gets *worse faster* the more you take (toxicity, side effects). We'll model that as: `H(d) = a · d²`.\n",
    "\n",
    "The **net effect on health** is simply protection minus harm: `B(d) − H(d)`. Let's plot all three and find the best dose."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7dcbf565",
   "metadata": {},
   "outputs": [],
   "source": [
    "dose = np.linspace(0, 6, 1000)\n",
    "Bmax, Kd, a = 10.0, 1.0, 1.0          # <-- try changing these and re-running\n",
    "\n",
    "benefit = Bmax * dose/(Kd + dose)     # protective maintenance (saturating)\n",
    "harm    = a * dose**2                 # direct toxicity (accelerating)\n",
    "net     = benefit - harm\n",
    "\n",
    "best = np.argmax(net)\n",
    "print(f\"Best dose: {dose[best]:.2f}   net benefit there: {net[best]:.2f}\")\n",
    "print(f\"At zero dose: {net[0]:.2f} (nothing happens).  At a big dose (6): {net[-1]:.2f} (net harm).\")\n",
    "\n",
    "plt.figure(figsize=(7,4.5))\n",
    "plt.plot(dose, benefit, '--', color=\"#2a9d8f\", label=\"protection (saturating)\")\n",
    "plt.plot(dose, harm,    '--', color=\"#e76f51\", label=\"harm (accelerating)\")\n",
    "plt.plot(dose, net,     '-',  color=\"#264653\", lw=2.5, label=\"NET effect on health\")\n",
    "plt.axhline(0, color=\"k\", lw=0.5)\n",
    "plt.scatter([dose[best]],[net[best]], color=\"#264653\", zorder=5, s=60)\n",
    "plt.annotate(\"the sweet spot\", (dose[best], net[best]), textcoords=\"offset points\", xytext=(10,-4))\n",
    "plt.xlabel(\"dose  (of CR, rapamycin, exercise, a stressor...)\"); plt.ylabel(\"effect on health\")\n",
    "plt.title(\"Hormesis: the inverted-U is a tug-of-war\"); plt.legend(); plt.tight_layout(); plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b6e98f3d",
   "metadata": {},
   "source": [
    "The inverted-U isn't a mysterious law — it **falls out** of two ordinary curves pulling against each other. Where protection's diminishing returns meet harm's accelerating cost, you get a peak. **Zero** does nothing; **too much** tips into net harm; the good stuff lives in between. *That's why the question \"should I take more?\" is the wrong question — the right one is \"what's the dose?\"*"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6ddb62ef",
   "metadata": {},
   "source": [
    "## Part 2 — Every intervention has its *own* sweet spot\n",
    "\n",
    "Now the useful part. How toxic an intervention is (our `a`) completely changes where its sweet spot sits. A **gentle** intervention can be pushed far and still help; a **harsh** one has a narrow, low sweet spot — or none. Watch the optimum move as we crank up the toxicity."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b371801f",
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.figure(figsize=(7,4.5))\n",
    "toxicities = [0.3, 0.7, 1.5, 3.0, 6.0]\n",
    "opt_dose, opt_benefit = [], []\n",
    "for a in toxicities:\n",
    "    net = Bmax*dose/(Kd+dose) - a*dose**2\n",
    "    j = np.argmax(net)\n",
    "    opt_dose.append(dose[j]); opt_benefit.append(net[j])\n",
    "    plt.plot(dose, net, label=f\"toxicity a = {a}\")\n",
    "    plt.scatter([dose[j]],[net[j]], zorder=5)\n",
    "plt.axhline(0, color=\"k\", lw=0.5); plt.ylim(-2, 6)\n",
    "plt.xlabel(\"dose\"); plt.ylabel(\"net effect on health\")\n",
    "plt.title(\"Gentle interventions -> wide, high sweet spot.  Harsh ones -> narrow, low.\")\n",
    "plt.legend(); plt.tight_layout(); plt.show()\n",
    "\n",
    "fig,ax=plt.subplots(1,2,figsize=(11,3.8))\n",
    "ax[0].plot(toxicities, opt_dose, 'o-', color=\"#457b9d\"); ax[0].set_xlabel(\"toxicity a\"); ax[0].set_ylabel(\"best dose\"); ax[0].set_title(\"Harsher -> use less\")\n",
    "ax[1].plot(toxicities, opt_benefit, 'o-', color=\"#2a9d8f\"); ax[1].set_xlabel(\"toxicity a\"); ax[1].set_ylabel(\"benefit at best dose\"); ax[1].set_title(\"Harsher -> less to gain\")\n",
    "plt.tight_layout(); plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2d9f5e21",
   "metadata": {},
   "source": [
    "This is why **exercise and mild caloric restriction** have a wide, forgiving sweet spot, while **megadosing a drug or a supplement backfires** — recall the sharp lesson from Chapter 5, where high-dose antioxidants *erased* the benefits of exercise. Same curve, pushed past its peak. The optimal dose is **specific to the molecule**, which is exactly why \"a longevity supplement\" with no dose-response data is a red flag."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "42ba3035",
   "metadata": {},
   "source": [
    "## Part 3 — The deeper *why*: the growth-vs-maintenance dial\n",
    "\n",
    "Why does *mild stress* help at all? Chapter 4's answer is the **disposable-soma** idea. An organism has a **limited energy budget**, and it must split it between two jobs:\n",
    "\n",
    "- **growing and reproducing** now, versus\n",
    "- **maintaining and repairing** the body for later.\n",
    "\n",
    "The nutrient-sensing pathways *are* that dial: lots of food and growth signaling (**mTOR high**) → spend on growth; scarcity (**mTOR low**, via CR or rapamycin) → spend on maintenance. Turning the dial toward maintenance buys you a longer life — but the budget is fixed, so you **pay in growth and reproduction.** Let's see the trade-off, and then something surprising."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c1ad465e",
   "metadata": {},
   "outputs": [],
   "source": [
    "f = np.linspace(0, 1, 1000)          # fraction of the budget spent on MAINTENANCE\n",
    "amp = 3.0                             # how much maintenance can extend life\n",
    "\n",
    "lifespan      = 1.0*(1 + amp*f)      # more maintenance -> longer life\n",
    "reproduction  = 1.0*(1 - f)          # ...but less reproduction right now\n",
    "fitness       = reproduction*lifespan # what evolution 'cares about': lifetime offspring\n",
    "\n",
    "f_evo  = f[np.argmax(fitness)]       # the dial evolution settles on\n",
    "f_life = f[np.argmax(lifespan)]      # the dial that would maximize lifespan\n",
    "\n",
    "fig,ax=plt.subplots(1,2,figsize=(11,4.2))\n",
    "ax[0].plot(f, lifespan, color=\"#2a9d8f\", lw=2, label=\"lifespan\")\n",
    "ax[0].plot(f, reproduction, color=\"#e76f51\", lw=2, label=\"reproduction now\")\n",
    "ax[0].set_xlabel(\"dial -> maintenance\"); ax[0].set_ylabel(\"relative amount\")\n",
    "ax[0].set_title(\"No free lunch: buy lifespan, pay in reproduction\"); ax[0].legend()\n",
    "\n",
    "ax[1].plot(f, fitness, color=\"#264653\", lw=2.5)\n",
    "ax[1].axvline(f_evo,  color=\"#e76f51\", ls=\"--\", label=f\"evolution's setting (f={f_evo:.2f})\")\n",
    "ax[1].axvline(f_life, color=\"#2a9d8f\", ls=\"--\", label=f\"longest-life setting (f={f_life:.2f})\")\n",
    "ax[1].axvspan(f_evo, f_life, color=\"#2a9d8f\", alpha=0.10)\n",
    "ax[1].set_xlabel(\"dial -> maintenance\"); ax[1].set_ylabel(\"evolutionary fitness\")\n",
    "ax[1].set_title(\"Evolution stops short of the longest life\"); ax[1].legend()\n",
    "plt.tight_layout(); plt.show()\n",
    "\n",
    "print(f\"Evolution sets the dial at f={f_evo:.2f}, but lifespan keeps rising all the way to f={f_life:.2f}.\")\n",
    "print(f\"That gap (shaded) is unused longevity -- room a drug like rapamycin could turn the dial into.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6ad8222c",
   "metadata": {},
   "source": [
    "Look at what the model just told you. Evolutionary fitness peaks at an **intermediate** maintenance setting — but **lifespan keeps climbing past it.** Evolution tuned your dial to maximize *reproduction*, not *longevity*, so it stopped short of the longest possible life. Everything to the right of evolution's setting is **unused lifespan.**\n",
    "\n",
    "That gap is the whole opportunity of this chapter. **Caloric restriction and rapamycin turn the dial rightward** — toward maintenance, past the fitness optimum your genes were set to — buying years by spending a reproductive budget an adult no longer needs. It's the book's *\"brake and price\"* in one picture: **the maintenance setting really is the longevity setting**, and there's no free lunch. (And the honesty of the chapter still holds — rapamycin is the most reproducible *animal* geroprotector, its side effects *are* the price, and whether the trade pays off in *humans* is not yet settled.)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f8e6b32b",
   "metadata": {},
   "source": [
    "## Go further (for the reader who finished hungry)\n",
    "\n",
    "- **Sweep the dial knobs.** Change `amp` in Part 3 (how much maintenance can extend life). When does the gap between evolution's setting and the longest-life setting grow — and when does it vanish?\n",
    "- **Make harm have a threshold.** Replace `a*d²` with a term that's near-zero until some dose and then shoots up. How does the sweet spot change?\n",
    "- **Two interventions at once.** Give two hormetic stressors and see whether their sweet spots add up — or whether \"stacking\" pushes you over the edge.\n",
    "- **Connect the whole book.** This same inverted-U is the *hormesis* of Chapter 5 (mild mitochondrial stress) and the *\"partial\"* window of Chapter 7 (reprogramming) — one shape, three chapters, rising stakes. *Biology runs on curves, not lines.*\n",
    "\n",
    "---\n",
    "*Companion notebook to* **Chapter 4 — Deregulated Nutrient Sensing**, *from the \"AI for Drug Discovery for Kids\" aging & longevity volume. A teaching model: the shapes are real, the numbers are illustrative.*"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}