{
 "nbformat": 4,
 "nbformat_minor": 5,
 "metadata": {
  "kernelspec": {
   "name": "python3",
   "display_name": "Python 3"
  },
  "language_info": {
   "name": "python"
  },
  "colab": {
   "provenance": []
  }
 },
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Day 55: The Rules of do-Calculus\n",
    "\n",
    "*Beginner to Ninja: Math for Causal Inference*\n",
    "\n",
    "Three rules, each licensed by a d-separation in a modified graph, let you add or remove observations, swap actions for observations, and add or remove actions. Every identifiable causal effect can be derived with them.\n",
    "\n",
    "**Learning outcomes**\n",
    "\n",
    "- Build the modified graphs G with incoming or outgoing arrows removed.\n",
    "- State the three rules of do-calculus and check their graphical conditions.\n",
    "- Derive the back-door and front-door formulas, and the g-formula for two sequential treatments, step by step.\n",
    "- Recognise when no sequence of rules can work and show non-identification with two models."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Theory\n",
    "\n",
    "### Modified graphs\n",
    "\n",
    "For sets of nodes $\\mathbf X, \\mathbf Z$ in $G$:\n",
    "\n",
    "- $G_{\\overline{\\mathbf X}}$: delete all arrows **into** $\\mathbf X$ (the graph after intervening on $\\mathbf X$);\n",
    "- $G_{\\underline{\\mathbf Z}}$: delete all arrows **out of** $\\mathbf Z$ (only back-door paths from $\\mathbf Z$ remain);\n",
    "- $G_{\\overline{\\mathbf X}\\underline{\\mathbf Z}}$: both.\n",
    "\n",
    "### The three rules\n",
    "\n",
    "For disjoint sets $\\mathbf X, \\mathbf Y, \\mathbf Z, \\mathbf W$:\n",
    "\n",
    "**Rule 1 (insert or delete observations).**\n",
    "\n",
    "$$\n",
    "P(\\mathbf y \\mid \\operatorname{do}(\\mathbf x), \\mathbf z, \\mathbf w) = P(\\mathbf y \\mid \\operatorname{do}(\\mathbf x), \\mathbf w) \\quad \\text{if } (\\mathbf Y \\perp\\!\\!\\!\\perp \\mathbf Z \\mid \\mathbf X, \\mathbf W)_{G_{\\overline{\\mathbf X}}}.\n",
    "$$\n",
    "\n",
    "**Rule 2 (exchange action and observation).**\n",
    "\n",
    "$$\n",
    "P(\\mathbf y \\mid \\operatorname{do}(\\mathbf x), \\operatorname{do}(\\mathbf z), \\mathbf w) = P(\\mathbf y \\mid \\operatorname{do}(\\mathbf x), \\mathbf z, \\mathbf w) \\quad \\text{if } (\\mathbf Y \\perp\\!\\!\\!\\perp \\mathbf Z \\mid \\mathbf X, \\mathbf W)_{G_{\\overline{\\mathbf X}\\underline{\\mathbf Z}}}.\n",
    "$$\n",
    "\n",
    "**Rule 3 (insert or delete actions).**\n",
    "\n",
    "$$\n",
    "P(\\mathbf y \\mid \\operatorname{do}(\\mathbf x), \\operatorname{do}(\\mathbf z), \\mathbf w) = P(\\mathbf y \\mid \\operatorname{do}(\\mathbf x), \\mathbf w) \\quad \\text{if } (\\mathbf Y \\perp\\!\\!\\!\\perp \\mathbf Z \\mid \\mathbf X, \\mathbf W)_{G_{\\overline{\\mathbf X}\\overline{\\mathbf Z(\\mathbf W)}}},\n",
    "$$\n",
    "\n",
    "where $\\mathbf Z(\\mathbf W)$ is the set of $\\mathbf Z$-nodes that are not ancestors of any $\\mathbf W$-node in $G_{\\overline{\\mathbf X}}$.\n",
    "\n",
    "### Reading the rules\n",
    "\n",
    "- **Rule 1** is d-separation applied in the post-intervention world.\n",
    "- **Rule 2** says: if $\\mathbf Z$ has no open back-door paths to $\\mathbf Y$ (given $\\mathbf X, \\mathbf W$), seeing $\\mathbf z$ is as good as setting it. It generalises the back-door criterion.\n",
    "- **Rule 3** says: if $\\mathbf Z$ cannot reach $\\mathbf Y$ through any causal path (given the rest), setting it changes nothing. The $\\mathbf Z(\\mathbf W)$ subtlety handles conditioning on descendants of $\\mathbf Z$.\n",
    "\n",
    "### Identification as derivation\n",
    "\n",
    "A causal query $P(\\mathbf y \\mid \\operatorname{do}(\\mathbf x))$ is **identified** if the rules, plus ordinary probability, transform it into an expression with no $\\operatorname{do}$. The rules are **complete**: if no derivation exists, the effect is not identified from observational data in that graph (Shpitser & Pearl, 2006). Day 56 gives an algorithm that finds the derivation automatically.\n",
    "\n",
    "### Standard moves\n",
    "\n",
    "1. **Condition and sum:** $P(y \\mid \\operatorname{do}(x)) = \\sum_z P(y \\mid \\operatorname{do}(x), z)P(z \\mid \\operatorname{do}(x))$.\n",
    "2. Remove the $\\operatorname{do}$ from $P(z \\mid \\operatorname{do}(x))$ with Rule 3 (if $Z$ is not a descendant) or Rule 2.\n",
    "3. Turn $\\operatorname{do}(x)$ into $x$ inside $P(y \\mid \\operatorname{do}(x), z)$ with Rule 2.\n",
    "\n",
    "## Part 1 · Warm-up\n",
    "\n",
    "Exercises 1 and 4 use $G$: $Z \\to X \\to Y$, $Z \\to Y$, $X \\to W$."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 1 · Modified graphs\n",
    "\n",
    "Write the edges of $G_{\\overline X}$, $G_{\\underline X}$ and $G_{\\overline Z}$.\n",
    "\n",
    "<details><summary>Show solution</summary>\n",
    "\n",
    "**Step 1.** $G_{\\overline X}$: remove $Z \\to X$. Left: $X \\to Y$, $Z \\to Y$, $X \\to W$.\n",
    "\n",
    "**Step 2.** $G_{\\underline X}$: remove $X \\to Y$, $X \\to W$. Left: $Z \\to X$, $Z \\to Y$.\n",
    "\n",
    "**Step 3.** $G_{\\overline Z}$: $Z$ has no incoming arrows, so $G_{\\overline Z} = G$.\n",
    "\n",
    "</details>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*Your work:*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 2 · Randomised treatment\n",
    "\n",
    "In $X \\to Y$ with $X$ randomised (no parents), use Rule 2 to show $P(y \\mid \\operatorname{do}(x)) = P(y \\mid x)$.\n",
    "\n",
    "<details><summary>Show solution</summary>\n",
    "\n",
    "**Step 1.** Rule 2 with empty outer $\\mathbf X$ and $\\mathbf W$, and $\\mathbf Z = \\{X\\}$: condition $(Y \\perp\\!\\!\\!\\perp X)_{G_{\\underline X}}$.\n",
    "\n",
    "**Step 2.** $G_{\\underline X}$ removes $X \\to Y$: no edges remain, so $X$ and $Y$ are d-separated.\n",
    "\n",
    "**Answer:** Rule 2 applies: $P(y \\mid \\operatorname{do}(x)) = P(y \\mid x)$.\n",
    "\n",
    "</details>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*Your work:*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 3 · Actions that cannot matter\n",
    "\n",
    "If $X$ is not an ancestor of $Y$, show $P(y \\mid \\operatorname{do}(x)) = P(y)$ with Rule 3.\n",
    "\n",
    "<details><summary>Show solution</summary>\n",
    "\n",
    "**Step 1.** Rule 3 with empty $\\mathbf W$: condition $(Y \\perp\\!\\!\\!\\perp X)_{G_{\\overline X}}$.\n",
    "\n",
    "**Step 2.** In $G_{\\overline X}$, $X$ has no incoming arrows; any path from $X$ starts $X \\to \\cdots$.\n",
    "\n",
    "**Step 3.** Since $X$ is not an ancestor of $Y$, such a path must contain a collider (it cannot be directed all the way to $Y$); unconditioned, it is blocked.\n",
    "\n",
    "**Answer:** d-separated, so $P(y \\mid \\operatorname{do}(x)) = P(y)$.\n",
    "\n",
    "</details>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*Your work:*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 4 · Rule 1 in action\n",
    "\n",
    "In $G$, is $P(y \\mid \\operatorname{do}(x), w) = P(y \\mid \\operatorname{do}(x))$?\n",
    "\n",
    "<details><summary>Show solution</summary>\n",
    "\n",
    "**Step 1.** Rule 1 condition: $(Y \\perp\\!\\!\\!\\perp W \\mid X)_{G_{\\overline X}}$.\n",
    "\n",
    "**Step 2.** In $G_{\\overline X}$, paths $Y$–$W$: $Y \\leftarrow X \\to W$ (fork at $X$, conditioned: blocked).\n",
    "\n",
    "**Step 3.** $Y \\leftarrow Z \\to Y$ is not a path to $W$; and $Z \\to X$ is gone, so no other path exists.\n",
    "\n",
    "**Answer:** yes; once $X$ is set, $W$ (a side effect of $X$) carries no information about $Y$.\n",
    "\n",
    "</details>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*Your work:*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 5 · Name the rule\n",
    "\n",
    "Which rule justifies each step? (a) $P(z \\mid \\operatorname{do}(x)) = P(z)$ for a pre-treatment $Z$. (b) $P(y \\mid \\operatorname{do}(x), z) = P(y \\mid x, z)$ when $Z$ blocks the back-door paths. (c) Dropping a measured side effect of treatment from the conditioning set.\n",
    "\n",
    "<details><summary>Show solution</summary>\n",
    "\n",
    "**Step 1.** (a) Rule 3 (deleting an action that cannot affect $Z$).\n",
    "\n",
    "**Step 2.** (b) Rule 2 (exchanging the action $\\operatorname{do}(x)$ for the observation $x$).\n",
    "\n",
    "**Step 3.** (c) Rule 1 (deleting an observation).\n",
    "\n",
    "</details>\n",
    "\n",
    "## Part 2 · Proofs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*Your work:*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 6 · The back-door formula by do-calculus\n",
    "\n",
    "Let $\\mathbf Z$ satisfy the back-door criterion for $(X, Y)$. Derive $P(y \\mid \\operatorname{do}(x)) = \\sum_{\\mathbf z} P(y \\mid x, \\mathbf z)P(\\mathbf z)$.\n",
    "\n",
    "<details><summary>Show solution</summary>\n",
    "\n",
    "**Step 1.** Condition and sum: $P(y \\mid \\operatorname{do}(x)) = \\sum_{\\mathbf z} P(y \\mid \\operatorname{do}(x), \\mathbf z)P(\\mathbf z \\mid \\operatorname{do}(x))$.\n",
    "\n",
    "**Step 2.** Rule 3 for $P(\\mathbf z \\mid \\operatorname{do}(x))$: need $(\\mathbf Z \\perp\\!\\!\\!\\perp X)_{G_{\\overline X}}$. In $G_{\\overline X}$, paths from $X$ leave through its children; since no $\\mathbf Z$ node is a descendant of $X$, each such path meets a collider and is blocked. So $P(\\mathbf z \\mid \\operatorname{do}(x)) = P(\\mathbf z)$.\n",
    "\n",
    "**Step 3.** Rule 2 for $P(y \\mid \\operatorname{do}(x), \\mathbf z)$: need $(Y \\perp\\!\\!\\!\\perp X \\mid \\mathbf Z)_{G_{\\underline X}}$. In $G_{\\underline X}$ only back-door paths from $X$ remain, and $\\mathbf Z$ blocks them all. So $P(y \\mid \\operatorname{do}(x), \\mathbf z) = P(y \\mid x, \\mathbf z)$.\n",
    "\n",
    "**Step 4.** Substitute. $\\blacksquare$ (This also proves fact (b) assumed on Day 52.)\n",
    "\n",
    "</details>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*Your work:*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 7 · Front door, first piece\n",
    "\n",
    "In the front-door graph $U \\to X$, $U \\to Y$, $X \\to M \\to Y$ ($U$ unobserved), show $P(m \\mid \\operatorname{do}(x)) = P(m \\mid x)$.\n",
    "\n",
    "<details><summary>Show solution</summary>\n",
    "\n",
    "**Step 1.** Rule 2 condition: $(M \\perp\\!\\!\\!\\perp X)_{G_{\\underline X}}$.\n",
    "\n",
    "**Step 2.** $G_{\\underline X}$ removes $X \\to M$. Remaining paths $X$–$M$: $X \\leftarrow U \\to Y \\leftarrow M$, with a collider at $Y$: blocked.\n",
    "\n",
    "**Answer:** Rule 2 applies. $\\blacksquare$\n",
    "\n",
    "</details>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*Your work:*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 8 · Front door, second piece\n",
    "\n",
    "In the same graph, show $P(y \\mid \\operatorname{do}(m)) = \\sum_x P(y \\mid m, x)P(x)$.\n",
    "\n",
    "<details><summary>Show solution</summary>\n",
    "\n",
    "**Step 1.** Condition and sum: $P(y \\mid \\operatorname{do}(m)) = \\sum_x P(y \\mid \\operatorname{do}(m), x)P(x \\mid \\operatorname{do}(m))$.\n",
    "\n",
    "**Step 2.** Rule 2 on the first factor: $(Y \\perp\\!\\!\\!\\perp M \\mid X)_{G_{\\underline M}}$. Removing $M \\to Y$ leaves the path $M \\leftarrow X \\leftarrow U \\to Y$, blocked by $X$ (chain). So $P(y \\mid \\operatorname{do}(m), x) = P(y \\mid m, x)$.\n",
    "\n",
    "**Step 3.** Rule 3 on the second factor: $(X \\perp\\!\\!\\!\\perp M)_{G_{\\overline M}}$. Removing $X \\to M$ leaves $M \\to Y \\leftarrow U \\to X$ with a collider at $Y$: blocked. So $P(x \\mid \\operatorname{do}(m)) = P(x)$.\n",
    "\n",
    "**Step 4.** Substitute. $\\blacksquare$\n",
    "\n",
    "</details>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*Your work:*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 9 · Front door, assembled\n",
    "\n",
    "Complete the derivation of $P(y \\mid \\operatorname{do}(x)) = \\sum_m P(m \\mid x)\\sum_{x'} P(y \\mid m, x')P(x')$.\n",
    "\n",
    "<details><summary>Show solution</summary>\n",
    "\n",
    "**Step 1.** Condition and sum: $P(y \\mid \\operatorname{do}(x)) = \\sum_m P(y \\mid \\operatorname{do}(x), m)P(m \\mid \\operatorname{do}(x))$.\n",
    "\n",
    "**Step 2.** The second factor is $P(m \\mid x)$ (Exercise 7).\n",
    "\n",
    "**Step 3.** Rule 2 on the first: $(Y \\perp\\!\\!\\!\\perp M \\mid X)_{G_{\\overline X}\\underline M}$. Removing arrows into $X$ and out of $M$ leaves no path $M$–$Y$ except through $X$, which is conditioned. So $P(y \\mid \\operatorname{do}(x), m) = P(y \\mid \\operatorname{do}(x), \\operatorname{do}(m))$.\n",
    "\n",
    "**Step 4.** Rule 3: $(Y \\perp\\!\\!\\!\\perp X \\mid M)_{G_{\\overline X\\,\\overline M}}$. With arrows into $X$ and $M$ removed, $X$ is isolated. So $P(y \\mid \\operatorname{do}(x), \\operatorname{do}(m)) = P(y \\mid \\operatorname{do}(m))$.\n",
    "\n",
    "**Step 5.** By Exercise 8, $P(y \\mid \\operatorname{do}(m)) = \\sum_{x'} P(y \\mid m, x')P(x')$. Substitute. $\\blacksquare$\n",
    "\n",
    "</details>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*Your work:*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 10 · Two models, one distribution\n",
    "\n",
    "In the \"bow\" graph $X \\to Y$ with $X \\leftrightarrow Y$, show that $P(y \\mid \\operatorname{do}(x))$ is not identified by exhibiting two SCMs with the same $P(x, y)$ and different interventional distributions.\n",
    "\n",
    "<details><summary>Show solution</summary>\n",
    "\n",
    "**Step 1.** Model A: $U \\sim \\text{Bernoulli}(0.5)$, $X := U$, $Y := U$. $X$ has no effect on $Y$.\n",
    "\n",
    "**Step 2.** Model B: $X := U \\sim \\text{Bernoulli}(0.5)$, $Y := X$. Effect of 1.\n",
    "\n",
    "**Step 3.** Both give $P(X = Y = 1) = P(X = Y = 0) = 0.5$: identical observational distributions.\n",
    "\n",
    "**Step 4.** $P(Y = 1 \\mid \\operatorname{do}(X = 1))$ is 0.5 in Model A and 1 in Model B.\n",
    "\n",
    "**Answer:** data cannot distinguish the models, so no formula can recover the effect: it is not identified. $\\blacksquare$\n",
    "\n",
    "</details>\n",
    "\n",
    "## Part 3 · Applied"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*Your work:*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 11 · A tax credit and labour supply\n",
    "\n",
    "An earned-income tax credit $X$ (eligibility depends on number of children $C$) affects hours worked $Y$; children also affect hours directly. Graph: $C \\to X$, $C \\to Y$, $X \\to Y$. Derive $P(y \\mid \\operatorname{do}(x))$ with the rules, naming each.\n",
    "\n",
    "<details><summary>Show solution</summary>\n",
    "\n",
    "**Step 1.** Condition and sum: $P(y \\mid \\operatorname{do}(x)) = \\sum_c P(y \\mid \\operatorname{do}(x), c)P(c \\mid \\operatorname{do}(x))$.\n",
    "\n",
    "**Step 2.** Rule 3: in $G_{\\overline X}$ the arrow $C \\to X$ is gone; paths $X$–$C$: $X \\to Y \\leftarrow C$, collider: blocked. So $P(c \\mid \\operatorname{do}(x)) = P(c)$.\n",
    "\n",
    "**Step 3.** Rule 2: in $G_{\\underline X}$, paths $X$–$Y$: $X \\leftarrow C \\to Y$, blocked by $C$. So $P(y \\mid \\operatorname{do}(x), c) = P(y \\mid x, c)$.\n",
    "\n",
    "**Answer:** $P(y \\mid \\operatorname{do}(x)) = \\sum_c P(y \\mid x, c)P(c)$: compare hours of eligible and ineligible families with the same number of children, and average over the distribution of family size.\n",
    "\n",
    "</details>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*Your work:*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 12 · Effects within subgroups\n",
    "\n",
    "In Exercise 11's graph plus a pre-treatment region indicator $R$ ($R \\to C$, $R \\to Y$), derive the region-specific effect $P(y \\mid \\operatorname{do}(x), r)$.\n",
    "\n",
    "<details><summary>Show solution</summary>\n",
    "\n",
    "**Step 1.** Condition and sum within region: $P(y \\mid \\operatorname{do}(x), r) = \\sum_c P(y \\mid \\operatorname{do}(x), c, r)P(c \\mid \\operatorname{do}(x), r)$.\n",
    "\n",
    "**Step 2.** Rule 3 (with $\\mathbf W = \\{R\\}$): in $G_{\\overline X}$, paths $X$–$C$ go through the collider $Y$ ($X \\to Y \\leftarrow C$ or $X \\to Y \\leftarrow R \\to C$), unconditioned: blocked. So $P(c \\mid \\operatorname{do}(x), r) = P(c \\mid r)$.\n",
    "\n",
    "**Step 3.** Rule 2: in $G_{\\underline X}$, back-door paths $X \\leftarrow C \\to Y$ and $X \\leftarrow C \\leftarrow R \\to Y$ are blocked by $C$. So $P(y \\mid \\operatorname{do}(x), c, r) = P(y \\mid x, c, r)$.\n",
    "\n",
    "**Answer:** $P(y \\mid \\operatorname{do}(x), r) = \\sum_c P(y \\mid x, c, r)P(c \\mid r)$, a conditional (CATE-type) version of the adjustment formula.\n",
    "\n",
    "</details>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*Your work:*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 13 · Two rounds of HIV treatment\n",
    "\n",
    "A clinic decides treatment $X_1$ at the first visit; CD4 count $L$ is measured; treatment $X_2$ is decided at the second visit based on $L$; viral suppression $Y$ is measured. Graph: $X_1 \\to L$, $X_1 \\to Y$, $L \\to X_2$, $X_2 \\to Y$, $U \\to L$, $U \\to Y$ ($U$ = unobserved health status); $X_1$ is randomised. Derive $P(y \\mid \\operatorname{do}(x_1), \\operatorname{do}(x_2))$.\n",
    "\n",
    "<details><summary>Show solution</summary>\n",
    "\n",
    "**Step 1.** Condition on $L$ and sum: $P(y \\mid \\operatorname{do}(x_1, x_2)) = \\sum_l P(y \\mid \\operatorname{do}(x_1, x_2), l)\\,P(l \\mid \\operatorname{do}(x_1, x_2))$.\n",
    "\n",
    "**Step 2.** Rule 3 removes $\\operatorname{do}(x_2)$ from the second factor: $X_2$ is not an ancestor of $L$. Then Rule 2 turns $\\operatorname{do}(x_1)$ into $x_1$: $X_1$ has no back-door paths. So $P(l \\mid \\operatorname{do}(x_1, x_2)) = P(l \\mid x_1)$.\n",
    "\n",
    "**Step 3.** Rule 2 for $X_2$ in the first factor: in $G_{\\overline{X_1}\\underline{X_2}}$, back-door paths from $X_2$ ($X_2 \\leftarrow L \\leftarrow U \\to Y$, $X_2 \\leftarrow L \\leftarrow X_1 \\to Y$) are blocked by $L$ (and $X_1$). So it equals $P(y \\mid \\operatorname{do}(x_1), x_2, l)$.\n",
    "\n",
    "**Step 4.** Rule 2 for $X_1$: in $G_{\\underline{X_1}}$, $X_1$ has no remaining edges. So it equals $P(y \\mid x_1, x_2, l)$.\n",
    "\n",
    "**Answer:** the **g-formula** $P(y \\mid \\operatorname{do}(x_1, x_2)) = \\sum_l P(y \\mid x_1, l, x_2)\\,P(l \\mid x_1)$. Note that regressing $Y$ on $X_1, X_2, L$ would be wrong: $L$ is a mediator for $X_1$ and a collider ($X_1 \\to L \\leftarrow U$). Day 96 develops this.\n",
    "\n",
    "</details>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*Your work:*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 14 · Ice cream and drowning\n",
    "\n",
    "Hot weather $H$ raises ice-cream sales $I$ and swimming, hence drownings $D$: $H \\to I$, $H \\to D$. A mayor proposes banning ice cream to cut drownings. Use Rule 3 to evaluate the proposal, and contrast with the observational association.\n",
    "\n",
    "<details><summary>Show solution</summary>\n",
    "\n",
    "**Step 1.** Rule 3: $(D \\perp\\!\\!\\!\\perp I)_{G_{\\overline I}}$? Removing $H \\to I$ isolates $I$: d-separated.\n",
    "\n",
    "**Step 2.** So $P(d \\mid \\operatorname{do}(i)) = P(d)$: setting ice-cream sales to zero changes nothing.\n",
    "\n",
    "**Step 3.** Observationally, $P(d \\mid i)$ rises with $i$ through the fork $I \\leftarrow H \\to D$.\n",
    "\n",
    "**Answer:** the ban would not reduce drownings; the association is pure confounding by weather.\n",
    "\n",
    "</details>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*Your work:*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 15 · A non-identified effect, numerically\n",
    "\n",
    "A health economist has data only on insurance status $X$ and medical spending $Y$ (both binary), with unobserved health $U$ affecting both. Build two SCMs matching $P(X = 1, Y = 1) = 0.3$, $P(X = 1, Y = 0) = 0.2$, $P(X = 0, Y = 1) = 0.1$, $P(X = 0, Y = 0) = 0.4$, one where insurance has no effect and one where it does.\n",
    "\n",
    "<details><summary>Show solution</summary>\n",
    "\n",
    "**Step 1.** Model A (no effect): let $U$ take four values that encode $(X, Y)$ directly, with $P(U = (x, y))$ equal to the table; set $X := U_1$, $Y := U_2$. The table is reproduced and $Y$ does not depend on $X$: $P(Y = 1 \\mid \\operatorname{do}(x)) = P(Y = 1) = 0.4$ for both $x$.\n",
    "\n",
    "**Step 2.** Model B (no confounding): $X \\sim \\text{Bernoulli}(0.5)$ and $Y := \\mathbf 1[V < p_X]$ with $V$ uniform, $p_1 = 0.3/0.5 = 0.6$, $p_0 = 0.1/0.5 = 0.2$. Same table; causal effect $0.6 - 0.2 = 0.4$.\n",
    "\n",
    "**Answer:** both models fit the data perfectly; the effect could be 0 or 0.4. Without an admissible set, a front door or an instrument, the data are silent.\n",
    "\n",
    "</details>\n",
    "\n",
    "## Verify in Python"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*Your work:*"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {},
   "execution_count": null,
   "outputs": [],
   "source": [
    "import networkx as nx\n",
    "\n",
    "dsep = getattr(nx, \"is_d_separator\", None) or nx.d_separated   # name changed in networkx 3.3\n",
    "\n",
    "def cut(G, into=(), out_of=()):\n",
    "    \"\"\"Remove arrows into the nodes in `into` and out of the nodes in `out_of`.\"\"\"\n",
    "    H = G.copy()\n",
    "    H.remove_edges_from([e for e in G.edges if e[1] in into or e[0] in out_of])\n",
    "    return H\n",
    "\n",
    "# Front-door graph (U explicit)\n",
    "F = nx.DiGraph([(\"U\", \"X\"), (\"U\", \"Y\"), (\"X\", \"M\"), (\"M\", \"Y\")])\n",
    "print(\"Ex 7  rule 2:\", dsep(cut(F, out_of={\"X\"}), {\"M\"}, {\"X\"}, set()))\n",
    "print(\"Ex 8  rule 2:\", dsep(cut(F, out_of={\"M\"}), {\"Y\"}, {\"M\"}, {\"X\"}), \" rule 3:\", dsep(cut(F, into={\"M\"}), {\"X\"}, {\"M\"}, set()))\n",
    "print(\"Ex 9  rule 2:\", dsep(cut(F, into={\"X\"}, out_of={\"M\"}), {\"Y\"}, {\"M\"}, {\"X\"}),\n",
    "      \" rule 3:\", dsep(cut(F, into={\"X\", \"M\"}), {\"Y\"}, {\"X\"}, {\"M\"}))\n",
    "\n",
    "# Exercise 13: two rounds of treatment\n",
    "H = nx.DiGraph([(\"X1\", \"L\"), (\"X1\", \"Y\"), (\"L\", \"X2\"), (\"X2\", \"Y\"), (\"U\", \"L\"), (\"U\", \"Y\")])\n",
    "print(\"Ex 13 rule 3 (X2 on L):\", dsep(cut(H, into={\"X2\"}), {\"L\"}, {\"X2\"}, set()),\n",
    "      \" rule 2 (X1 on L):\", dsep(cut(H, out_of={\"X1\"}), {\"L\"}, {\"X1\"}, set()))\n",
    "print(\"      rule 2 (X2 on Y):\", dsep(cut(H, into={\"X1\"}, out_of={\"X2\"}), {\"Y\"}, {\"X2\"}, {\"X1\", \"L\"}),\n",
    "      \" rule 2 (X1 on Y):\", dsep(cut(H, out_of={\"X1\"}), {\"Y\"}, {\"X1\"}, {\"X2\", \"L\"}))\n",
    "print(\"      naive regression on L is invalid for X1: L is a descendant of X1:\", \"L\" in nx.descendants(H, \"X1\"))\n",
    "\n",
    "# Exercise 15: two SCMs, same data, different effects\n",
    "table = {(1, 1): .3, (1, 0): .2, (0, 1): .1, (0, 0): .4}\n",
    "modelA = {x: sum(v for (xx, y), v in table.items() if y == 1) for x in (0, 1)}            # Y ignores X\n",
    "pX = {x: sum(v for (xx, y), v in table.items() if xx == x) for x in (0, 1)}\n",
    "modelB = {x: table[x, 1] / pX[x] for x in (0, 1)}\n",
    "print(\"P(Y=1|do(x)) model A:\", modelA, \" model B:\", {k: round(v, 2) for k, v in modelB.items()})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Key takeaways\n",
    "\n",
    "- Rule 1 adds or removes observations, Rule 2 swaps actions and observations, Rule 3 adds or removes actions; each needs a d-separation in a modified graph.\n",
    "- The back-door and front-door formulas, and the g-formula for sequential treatments, are short derivations.\n",
    "- The rules are complete: if no derivation exists, two models with the same data but different effects can be built."
   ]
  }
 ]
}