From 5b261680f3158758744ed60e4c882a082b9b2e65 Mon Sep 17 00:00:00 2001 From: "Pedro A. Ortega" Date: Mon, 16 Nov 2020 19:05:19 +0000 Subject: [PATCH] Fixed bug in counterfactual algorithm. PiperOrigin-RevId: 342675170 --- ...ausal_Reasoning_in_Probability_Trees.ipynb | 548 +++++++++--------- 1 file changed, 274 insertions(+), 274 deletions(-) diff --git a/causal_reasoning/Causal_Reasoning_in_Probability_Trees.ipynb b/causal_reasoning/Causal_Reasoning_in_Probability_Trees.ipynb index 1867df5..2fe4455 100644 --- a/causal_reasoning/Causal_Reasoning_in_Probability_Trees.ipynb +++ b/causal_reasoning/Causal_Reasoning_in_Probability_Trees.ipynb @@ -3,7 +3,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "N1EHYIqxd80m" }, "source": [ @@ -25,7 +24,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "qHP8zlWs1OUN" }, "source": [ @@ -33,8 +31,8 @@ "\n", "*By the AGI Safety Analysis Team @ DeepMind.*\n", "\n", - "**Summary:** This is the companion tutorial for the paper \"Algorithms\n", - "for Causal Reasoning in Probability trees\" by Genewein T. et al. (2020).\n", + "**Summary:** This is the companion tutorial for the paper [\"Algorithms\n", + "for Causal Reasoning in Probability trees\"](https://arxiv.org/abs/2010.12237) by Genewein et al. (2020).\n", "\n", "Probability trees are one of the simplest models of causal\n", "generative processes.They possess clean semantics and are strictly more general\n", @@ -42,6 +40,12 @@ "that causal Bayesian networks can’t. Even so, they have received little\n", "attention from the AI and ML community.\n", "\n", + "For instance, we can describe a scenario where the weather is the cause and the barometer reading the effect, or viceversa, depending on whether we're on Earth or on some alien planet with different physics:\n", + "\n", + "\u003cimg src=\"http://www.adaptiveagents.org/_media/wiki/probtrees.png\" alt=\"Probability Trees\" width=\"700\"/\u003e\n", + "\n", + "Causal dependencies like these are naturally represented as a tree. We will see later that they allow us representing causal induction.\n", + "\n", "In this tutorial we present new algorithms for causal reasoning in discrete\n", "probability trees that cover the entire causal hierarchy (association,\n", "intervention, and counterfactuals), operating on arbitrary logical and causal\n", @@ -51,7 +55,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "XUQVMuc2_VlG" }, "source": [ @@ -63,7 +66,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "P4cjtJaR_VlH" }, "source": [ @@ -76,8 +78,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "JlbLG8sy_VlI" }, "outputs": [], @@ -89,7 +89,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "KxQFfJio_VlM" }, "source": [ @@ -103,9 +102,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "cellView": "both", - "colab": {}, - "colab_type": "code", "id": "HFs6Q37E_VlM" }, "outputs": [], @@ -122,8 +118,6 @@ "execution_count": null, "metadata": { "cellView": "form", - "colab": {}, - "colab_type": "code", "id": "yTTsE6f1_oIA" }, "outputs": [], @@ -498,36 +492,28 @@ "\n", " # Counterfactual/subjunctive conditional\n", " def cf(self, root_prem, cut_subj):\n", - " root_subj = self.do(cut_subj)\n", - " root_subj._cf(root_prem, cut_subj)\n", + " root_prem_do = root_prem.do(cut_subj)\n", + " root_subj = copy.deepcopy(self)\n", + " root_subj._cf(root_prem_do, cut_subj)\n", " return root_subj\n", "\n", " def _cf(self, prem, cut):\n", " # Base case.\n", - " if self.id in cut.t:\n", - " return True\n", - " if self.id in cut.f:\n", - " return False\n", + " if self.id in cut.t or self.id in cut.f:\n", + " return \n", "\n", " # Recurse.\n", - " critical = False\n", - "\n", + " children = []\n", " for child, child_prem in zip(self.children, prem.children):\n", " (_, subnode) = child\n", - " (_, subnode_prem) = child_prem\n", - " in_do = subnode._cf(subnode_prem, cut)\n", - " if not in_do:\n", - " critical = True\n", - " continue\n", + " (subprob, subnode_prem) = child_prem\n", + " subnode._cf(subnode_prem, cut)\n", + " children.append((subprob, subnode))\n", "\n", - " # Pick children if node is critical.\n", - " if not critical:\n", - " self.children = [\n", - " (subprob, subnode)\n", - " for (_, subnode), (subprob, _) in zip(self.children, prem.children)\n", - " ]\n", + " # Update children.\n", + " self.children = children\n", "\n", - " return True\n", + " return\n", "\n", " # Show probability tree.\n", " def show(self, show_id=False, show_prob=False, cut=None, crit=None):\n", @@ -935,7 +921,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "lcEgcO7C_VlQ" }, "source": [ @@ -958,8 +943,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "IKiO-SgJ_VlQ" }, "outputs": [], @@ -981,13 +964,14 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "pU9B9TJf_VlV" }, "source": [ "We'll typically call the root node $O$, standing for \"**O**mega\" ($\\Omega$),\n", "which is a common name for the sample space in the literature.\n", "\n", + "**Note:** This way of explicitly nesting nodes is the standard method for creating probability trees. We will learn a more concise, programatic method (that mimicks a probabilistic programming language) later in the tutorial.\n", + "\n", "After creating a probability tree, we can ask it to return: \n", "- the list of random variables and their values using the method `rvs()`; \n", "- the probability distribution for a given random variable using \n", @@ -1001,8 +985,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "a-MsyV_d_VlV" }, "outputs": [], @@ -1023,7 +1005,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "BscAftLn_VlZ" }, "source": [ @@ -1038,8 +1019,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "0DDBKwNs_Vla" }, "outputs": [], @@ -1066,7 +1045,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "YenMXlr6_Vld" }, "source": [ @@ -1085,8 +1063,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "Pot5uw-R_Vld" }, "outputs": [], @@ -1109,7 +1085,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "t9ntPBZd_Vlk" }, "source": [ @@ -1134,8 +1109,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "AxK8DRP3_Vlk" }, "outputs": [], @@ -1167,7 +1140,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "Fq63jb0u_Vln" }, "source": [ @@ -1187,7 +1159,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "er74BN7n_Vlo" }, "source": [ @@ -1199,7 +1170,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "afVSi5xo_Vlo" }, "source": [ @@ -1213,8 +1183,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "bCeTXeTe7WDM" }, "outputs": [], @@ -1225,7 +1193,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "ehQ37yPg7Wil" }, "source": [ @@ -1236,8 +1203,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "Q7W7exq4_Vlp" }, "outputs": [], @@ -1272,7 +1237,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "9TvtFpta_Vls" }, "source": [ @@ -1288,8 +1252,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "e4RxAStn_Vls" }, "outputs": [], @@ -1307,7 +1269,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "tZijtGvW_Vlw" }, "source": [ @@ -1324,8 +1285,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "xZRlhlq__Vlw" }, "outputs": [], @@ -1336,7 +1295,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "CRsPVDcg_Vlz" }, "source": [ @@ -1353,8 +1311,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "qBqyFExK7eor" }, "outputs": [], @@ -1365,7 +1321,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "HHmLu4w_7e-S" }, "source": [ @@ -1376,8 +1331,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "cHoN3mQp_Vl0" }, "outputs": [], @@ -1390,7 +1343,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "rqcodRJr_Vl3" }, "source": [ @@ -1427,8 +1379,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "CmjmqUAW_Vl3" }, "outputs": [], @@ -1450,7 +1400,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "9Bb9yBqP_Vl6" }, "source": [ @@ -1461,8 +1410,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "6-zNSWmL_Vl7" }, "outputs": [], @@ -1481,7 +1428,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "IQxIGXeu_Vl-" }, "source": [ @@ -1494,8 +1440,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "hMApKX3O_Vl_" }, "outputs": [], @@ -1509,7 +1453,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "DGP5kr7K_VmC" }, "source": [ @@ -1523,8 +1466,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "vOrfMXyA_VmD" }, "outputs": [], @@ -1553,7 +1494,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "1AxBz2Ml_VmG" }, "source": [ @@ -1573,8 +1513,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "2WvNpbQG_VmH" }, "outputs": [], @@ -1594,7 +1532,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "YbYnVRiM_VmJ" }, "source": [ @@ -1612,8 +1549,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "ujFLeAMN_VmK" }, "outputs": [], @@ -1631,7 +1566,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "zyP7gSPl_VmN" }, "source": [ @@ -1656,8 +1590,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "8IXq-jVl_VmN" }, "outputs": [], @@ -1679,7 +1611,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "K7OJKlcZ_VmQ" }, "source": [ @@ -1699,8 +1630,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "HlKSQi1l7rDJ" }, "outputs": [], @@ -1711,7 +1640,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "bD3LT8NV7rRV" }, "source": [ @@ -1722,8 +1650,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "3ttu0mlR_VmQ" }, "outputs": [], @@ -1754,7 +1680,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "ehK-sadN_VmT" }, "source": [ @@ -1772,8 +1697,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "rZe9JCMB7wo9" }, "outputs": [], @@ -1784,7 +1707,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "ZtQffc1P7wxk" }, "source": [ @@ -1795,8 +1717,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "bX6AxxDk_VmT" }, "outputs": [], @@ -1814,7 +1734,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "5PCmW5ol_VmX" }, "source": [ @@ -1840,8 +1759,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "9g2F9NKF_VmX" }, "outputs": [], @@ -1866,7 +1783,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "wE7voIju_Vma" }, "source": [ @@ -1882,8 +1798,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "4YvLDtzB_Vma" }, "outputs": [], @@ -1921,7 +1835,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "CtfxGITj_Vmd" }, "source": [ @@ -1939,8 +1852,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "pw-AG0Ma76Al" }, "outputs": [], @@ -1951,7 +1862,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "-1fUlg1O76bp" }, "source": [ @@ -1962,8 +1872,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "Wqkni_k4_Vmd" }, "outputs": [], @@ -1998,7 +1906,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "FPMH5CQ-_Vmg" }, "source": [ @@ -2009,7 +1916,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "9ggdcdjg_Vmg" }, "source": [ @@ -2036,8 +1942,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "lkH9LPzB_Vmh" }, "outputs": [], @@ -2063,7 +1967,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "Bwc00gKT_Vmj" }, "source": [ @@ -2081,8 +1984,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "5NWdMrLW7_cj" }, "outputs": [], @@ -2093,7 +1994,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "NUy8SH-O7_jT" }, "source": [ @@ -2104,8 +2004,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "xTbTw3Ky_Vmk" }, "outputs": [], @@ -2126,7 +2024,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "6Y8wjMCi_Vmm" }, "source": [ @@ -2168,7 +2065,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "USe_1o89_Vmn" }, "source": [ @@ -2180,8 +2076,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "-Is4k0IR_Vmn" }, "outputs": [], @@ -2208,7 +2102,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "KF9E83_8_Vmq" }, "source": [ @@ -2222,8 +2115,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "L_ULii7K_Vmq" }, "outputs": [], @@ -2253,7 +2144,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "RVtd_Pov_Vmt" }, "source": [ @@ -2270,8 +2160,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "R9Zcg6lH_Vmt" }, "outputs": [], @@ -2304,7 +2192,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "RLijoy-__Vmy" }, "source": [ @@ -2327,8 +2214,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "61sYhPTI_Vmz" }, "outputs": [], @@ -2352,7 +2237,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "2fuYExoQ_Vm1" }, "source": [ @@ -2375,8 +2259,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "D3WqIjaK8FSA" }, "outputs": [], @@ -2387,7 +2269,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "13s9eGWF8FZA" }, "source": [ @@ -2398,8 +2279,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "mMryXm_d_Vm2" }, "outputs": [], @@ -2424,7 +2303,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "9Dmexb79_Vm4" }, "source": [ @@ -2477,8 +2355,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "z4PLcgN5_Vm5" }, "outputs": [], @@ -2491,7 +2367,7 @@ "])\n", "\n", "print('Original:')\n", - "display(pt.show(show_prob=True, cut=cut, crit=crit))\n", + "display(pt.show(show_prob=True))\n", "\n", "# 'Y=1'\n", "cut = pt.prop('Y = 1')\n", @@ -2517,7 +2393,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "xJ-_TtAY_Vm7" }, "source": [ @@ -2529,7 +2404,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "LUvv_FNz_Vm8" }, "source": [ @@ -2547,8 +2421,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "6iFDVc7Z_Vm8" }, "outputs": [], @@ -2582,7 +2454,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "9auv9QLe_Vm_" }, "source": [ @@ -2595,7 +2466,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "RXjEiNWa_VnA" }, "source": [ @@ -2614,8 +2484,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "NUgHl3mT_VnA" }, "outputs": [], @@ -2645,7 +2513,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "qNqHBq19_VnD" }, "source": [ @@ -2672,8 +2539,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "pgP-6OwU8LBq" }, "outputs": [], @@ -2684,7 +2549,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "9JFZjAra8LJd" }, "source": [ @@ -2695,8 +2559,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "8Fui2W_l_VnE" }, "outputs": [], @@ -2721,7 +2583,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "SCZyxF5l_VnG" }, "source": [ @@ -2749,8 +2610,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "uB3igmF58OyH" }, "outputs": [], @@ -2761,7 +2620,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "k1vLg3F_8O7c" }, "source": [ @@ -2772,8 +2630,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "i2B5UhDT_VnJ" }, "outputs": [], @@ -2798,7 +2654,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "3OMlUFKF_VnM" }, "source": [ @@ -2840,21 +2695,10 @@ "\n", "The example shows a counterfactual probability tree generated by imposing $Y\n", "\\leftarrow 1$, given the factual premise $Z = 1$. Starting from a **reference\n", - "probability tree**, we first derive two additional trees: a **factual premise**,\n", - "capturing the current state of affairs; and a **counterfactual premise**,\n", - "represented as an intervention on the reference tree.\n", + "probability tree** describing the original process, we first use the **factual premise** to derive a tree describing the current state of affairs and then modify it using the **counterfactual premise**. \n", "\n", - "To form the counterfactual we proceed as follows:\n", - "- We slice both derived trees along the critical set\n", - "of the counterfactual premise. \n", - "- Then, we compose the counterfactual tree by\n", - "taking the transition probabilities **upstream of the slice**\n", - "from the factual premise, and those **downstream of the slice** \n", - "from the counterfactual premise. \n", "\n", - "The events downstream then span a new scope containing copies \n", - "of the original random variables (marked with \"∗\"), ready to \n", - "adopt new values. \n", + "Then, we replace the nodes downstream of the counterfactual premise's min-cut with the nodes of the reference tree. The events downstream then span a new scope containing copies of the original random variables (marked with \"∗\"), ready to adopt new values. In other words, we restore the random variables downstream of the counterfactual intervention to their original state of uncertainty.\n", "\n", "In particular note that $Z^\\ast = 0$ can happen in our alternate \n", "reality, even though we know that $Z = 1$." @@ -2863,7 +2707,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "4Xq_CBmU_VnM" }, "source": [ @@ -2874,8 +2717,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "wgfuKqZr_VnN" }, "outputs": [], @@ -2922,7 +2763,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "u6L7VDH9_VnP" }, "source": [ @@ -2936,8 +2776,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "1_dAJkjj_VnQ" }, "outputs": [], @@ -2970,7 +2808,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "eAPyY5O8_VnS" }, "source": [ @@ -2986,8 +2823,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "Nm-h3YPh_VnS" }, "outputs": [], @@ -3024,7 +2859,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "bCsw7tTM_VnV" }, "source": [ @@ -3042,7 +2876,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "B3DdaUXJ_VnV" }, "source": [ @@ -3064,8 +2897,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "JAoYBJcn8gve" }, "outputs": [], @@ -3076,7 +2907,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "yxuqdgvA8g-J" }, "source": [ @@ -3087,8 +2917,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "23ziOdxr_VnV" }, "outputs": [], @@ -3109,7 +2937,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "ioUtMVOs_VnX" }, "source": [ @@ -3136,8 +2963,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "6dh5MySa8j83" }, "outputs": [], @@ -3148,7 +2973,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "jWpZ0riB8kG3" }, "source": [ @@ -3159,8 +2983,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "KGzDgfzs_VnY" }, "outputs": [], @@ -3181,7 +3003,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "ZB-JZdum16ZJ" }, "source": [ @@ -3191,7 +3012,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "jw5OiWWC_Vna" }, "source": [ @@ -3222,7 +3042,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "ce_kzARO_Vna" }, "source": [ @@ -3239,8 +3058,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "94KpJKbm_Vnb" }, "outputs": [], @@ -3273,7 +3090,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "HYjrsERo_Vnd" }, "source": [ @@ -3284,8 +3100,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "JOvj1N5X_Vnd" }, "outputs": [], @@ -3308,7 +3122,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "z6PQk0Du_Vnh" }, "source": [ @@ -3320,8 +3133,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "bG3qSQz7_Vni" }, "outputs": [], @@ -3348,7 +3159,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "v8jmncNUF5kS" }, "source": [ @@ -3362,8 +3172,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "pl3Ps_PAJB89" }, "outputs": [], @@ -3390,7 +3198,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "xYUfpc-2KJ27" }, "source": [ @@ -3402,7 +3209,254 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", + "id": "uZ5o4hHxnUw0" + }, + "source": [ + "## Water Balloon Squad (a.k.a. Firing Squad)\n", + "\n", + "The following is a classical example used for illustrating counterfactual reasoning. There are two children (A and B) holding a water balloon, waiting for a signal from their friend (the \"captain\"). Upon the captain's signal, they both throw their water balloon at a single target simultaneously and accurately. The causal dependencies are as shown next:\n", + "\n", + "\u003cimg src=\"http://www.adaptiveagents.org/_media/wiki/waterballoon.png\" alt=\"Water Balloon Squad\" width=\"200\"/\u003e\n", + "\n", + "This situation can also be described using a probability tree constructed below. Note that in order to avoid problems due to conditioning on zero-probability transitions, we assign a tiny value (`eps`) to the nearly-impossible transitions.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "QMvQGn9KclPU" + }, + "outputs": [], + "source": [ + "#@title Water Balloon Squad factory function.\n", + "\n", + "def waterballon(bvar, eps=0.0001):\n", + " # Root: defined.\n", + " # Define the captain's signal.\n", + " if 'Captain' not in bvar:\n", + " if 'Captain' not in bvar:\n", + " return [(0.5, 'Captain = hold'), (0.5, 'Captain = throw')]\n", + "\n", + " # Define the children's decisions.\n", + " if 'A' not in bvar:\n", + " if bvar['Captain'] == 'hold':\n", + " return [((1-eps)*(1-eps), 'A = hold, B = hold'), (eps*(1-eps), 'A = hold, B = throw'), \n", + " (eps*(1-eps), 'A = throw, B = hold'), (eps*eps, 'A = throw, B = throw')]\n", + " else:\n", + " return [(eps*eps, 'A = hold, B = hold'), (eps*(1-eps), 'A = hold, B = throw'), \n", + " (eps*(1-eps), 'A = throw, B = hold'), ((1-eps)*(1-eps), 'A = throw, B = throw')]\n", + "\n", + " # Define target state.\n", + " if 'Target' not in bvar:\n", + " if bvar['A'] == 'throw' or bvar['B'] == 'throw':\n", + " return [(eps, 'Target = dry'), (1-eps, 'Target = wet')]\n", + " else:\n", + " return [(1-eps, 'Target = dry'), (eps, 'Target = wet')]\n", + "\n", + " return None\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "lagYuHxMqeUM" + }, + "outputs": [], + "source": [ + "# Create and show the probability tree.\n", + "wbs = PTree.fromFunc(waterballoon)\n", + "wbs.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9wgLrffyy40E" + }, + "source": [ + "Let's start by definining some simple events we'll use next." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "USYCB9uNqmoT" + }, + "outputs": [], + "source": [ + "# First we define some simple events.\n", + "cut_C = wbs.prop('Captain=throw')\n", + "cut_A = wbs.prop('A=throw')\n", + "cut_B = wbs.prop('B=throw')\n", + "cut_T = wbs.prop('Target=wet')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "OfgAR3u0zASo" + }, + "source": [ + "Let's ask our first question. Assume A throws the water balloon. What is the probability of B having thrown the balloon too?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_VcVSPg0vKz1" + }, + "outputs": [], + "source": [ + "# Condition on having A throwing the water balloon.\n", + "wbs_see = wbs.see(cut_A)\n", + "\n", + "# Print the probability of B throwing the water balloon.\n", + "print('P(B = throw | A = throw) =', wbs_see.prob(cut_B))\n", + "\n", + "# Display the conditional probability tree.\n", + "print('\\nConditional probability tree:')\n", + "display(wbs_see.show(cut=cut_B))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IALdewe2zWVy" + }, + "source": [ + "Notice how conditioning changed the transition probabilities, which then allow us to identify the pathways leading up to the event in which B throws the balloon. \n", + "\n", + "Assume now that A decides to act on their own and throws the balloon. What is the probability of B having thrown the balloon too?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "POlCBkHKvtcA" + }, + "outputs": [], + "source": [ + "# Intervene on having A throwing the water balloon.\n", + "wbs_do = wbs.do(cut_A)\n", + "\n", + "# Print the probability of B throwing the water balloon.\n", + "print('P(B = throw | do[A = throw]) =', wbs_do.prob(cut_B))\n", + "\n", + "# Display the conditional probability tree.\n", + "print('\\nIntervened probability tree:')\n", + "display(wbs_do.show(cut=cut_B))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "okJ6csZNz-C7" + }, + "source": [ + "Notice the difference between the two results above. If A acts on their own will, then this alters the conclusions we can draw.\n", + "\n", + "Let's ask a more complex question. **Assume A or B throw the balloon on their own will.** That is, we do not know precisely whether A acted by themself, B acted by themself, or both acted toghether. Intuitively, in this situation it is more likely that B threw the balloon. What is the probability?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "J5_6PRhtwET6" + }, + "outputs": [], + "source": [ + "# Intervene on having A throwing the water balloon.\n", + "wbs_do = wbs.do(cut_A | cut_B)\n", + "\n", + "# Print the probability of B throwing the water balloon.\n", + "print('P(B = throw | do[A = throw or B = throw]) =', wbs_do.prob(cut_B))\n", + "\n", + "# Display the conditional probability tree.\n", + "print('\\nIntervened probability tree:')\n", + "display(wbs_do.show(cut=cut_B))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "U6AUPwU8wSoc" + }, + "source": [ + "The above result shows that it is indeed more likely that B has thrown their water balloon. \n", + "\n", + "Now we will ask counterfactual questions. Let us start with an easy one first. \n", + "\n", + "Assume you observe that the target is wet. Then, **had the captain not given the signal**, what is the probability that B threw the water balloon at the target?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wJPAuhj7sKq8" + }, + "outputs": [], + "source": [ + "# Condition on the target being wet.\n", + "wbs_see = wbs.see(cut_T)\n", + "\n", + "# Compute counterfactual: given that the target is wet,\n", + "# what is the probability of B throwing the water balloon\n", + "# had the captain not given the signal?\n", + "wbs_cf = wbs.cf(wbs_see, ~cut_C)\n", + "print('P(B[C != throw] = throw | Target = wet) =', wbs_cf.prob(cut_B))\n", + "display(wbs_cf.show(cut=cut_B))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0gifSRkYxDMA" + }, + "source": [ + "The result shows that B would not have thrown the water balloon, which makes sense, as we assumed that the captain had not given the signal.\n", + "\n", + "Now, assume again you observe that the target is wet. **Had A not thrown the water balloon, would B have thrown it?**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Qj03sMAexj4e" + }, + "outputs": [], + "source": [ + "# Condition on the target being wet.\n", + "wbs_see = wbs.see(cut_T)\n", + "\n", + "# Compute counterfactual: given that the target is wet,\n", + "# what is the probability of B throwing the water balloon\n", + "# had A not done it?\n", + "wbs_cf = wbs.cf(wbs_see, ~cut_A)\n", + "print('P(B[A != throw] = throw | Target = wet) =', wbs_cf.prob(cut_B))\n", + "display(wbs_cf.show(cut=cut_B))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Jl6rVmjcxqUY" + }, + "source": [ + "As is shown above, the answer is yes. This is because observing the wet target allows us to conclude that the captain has given the signal. Hence, had A not thrown the water balloon, B must have thrown it." + ] + }, + { + "cell_type": "markdown", + "metadata": { "id": "_UO1GC7T_Vnl" }, "source": [ @@ -3425,9 +3479,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "cellView": "both", - "colab": {}, - "colab_type": "code", "id": "X00sYFKB_Vnm" }, "outputs": [], @@ -3463,7 +3514,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "4e3ZM5Vl_Vnr" }, "source": [ @@ -3475,8 +3525,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "zN3TzCnQHoz6" }, "outputs": [], @@ -3497,7 +3545,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "R4yVyNboW84N" }, "source": [ @@ -3505,15 +3552,13 @@ "Normally such trees are too large to\n", "display, for instance when `T` is large.\n", "\n", - "Let's display it." + "Let's display it, just for fun." ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "EvV6Gv4XaTxZ" }, "outputs": [], @@ -3524,7 +3569,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "JEuxhMkKHlUm" }, "source": [ @@ -3554,8 +3598,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "cwdfiRj-bNBR" }, "outputs": [], @@ -3566,7 +3608,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "7fTawNEfbNZ1" }, "source": [ @@ -3577,8 +3618,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "yPG6AbQo_Vnr" }, "outputs": [], @@ -3656,7 +3695,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "eoNn0c5rj5U1" }, "source": [ @@ -3692,9 +3730,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "cellView": "both", - "colab": {}, - "colab_type": "code", "id": "pRDAaQwW_zuF" }, "outputs": [], @@ -3778,7 +3813,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "0IwyuPLrsE0v" }, "source": [ @@ -3792,8 +3826,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "gveaR8W2sSJv" }, "outputs": [], @@ -3805,7 +3837,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "LU6ZQ0e1cUw3" }, "source": [ @@ -3818,7 +3849,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "ZtXmvPbIsqBI" }, "source": [ @@ -3831,8 +3861,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "lekPv0r1Egti" }, "outputs": [], @@ -3848,7 +3876,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "dNdejpEjR6WI" }, "source": [ @@ -3865,8 +3892,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "X1lMShnYEqDz" }, "outputs": [], @@ -3902,7 +3927,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "IxkzXrhDawc1" }, "source": [ @@ -3924,8 +3948,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "skor-95PGNpa" }, "outputs": [], @@ -3951,7 +3973,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "dR2U7_0quNYm" }, "source": [ @@ -3975,8 +3996,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "f7rPh-f6UKWM" }, "outputs": [], @@ -3996,7 +4015,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "po_krgRljGmp" }, "source": [ @@ -4014,8 +4032,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "5-5dNAcdk0Nz" }, "outputs": [], @@ -4026,7 +4042,6 @@ { "cell_type": "markdown", "metadata": { - "colab_type": "text", "id": "z4icvktpk0v0" }, "source": [ @@ -4037,8 +4052,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "colab": {}, - "colab_type": "code", "id": "m9DZhCjcVn4-" }, "outputs": [], @@ -4068,19 +4081,6 @@ "print('\\nGround truth:')\n", "print('Leader = ' + game.reveal())" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "colab": {}, - "colab_type": "code", - "id": "QMvQGn9KclPU" - }, - "outputs": [], - "source": [ - "" - ] } ], "metadata": {