From 6c6221b868a43fdc4247cb2bc310d0d3db79f2cf Mon Sep 17 00:00:00 2001 From: Peter Norvig Date: Thu, 16 Apr 2020 14:14:44 -0700 Subject: [PATCH] Add files via upload --- ipynb/Cheryl-and-Eve.ipynb | 533 +++++++++++++++++++------------------ ipynb/Cheryl.ipynb | 103 +++---- 2 files changed, 315 insertions(+), 321 deletions(-) diff --git a/ipynb/Cheryl-and-Eve.ipynb b/ipynb/Cheryl-and-Eve.ipynb index 29864bd4..199c2e66 100644 --- a/ipynb/Cheryl-and-Eve.ipynb +++ b/ipynb/Cheryl-and-Eve.ipynb @@ -4,17 +4,14 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# When Cheryl Met Eve: A Birthday Story" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Peter Norvig, May 2015\n", + "
Peter Norvig
May 2015
\n", + "\n", + "# When Cheryl Met Eve: A Birthday Story\n", + "\n", + "The *Cheryl's Birthday* logic puzzle [made the rounds](https://www.google.com/webhp?#q=cheryl%27s+birthday),\n", + "and I wrote [code](Cheryl.ipynb) that solves it. In that notebook I said that one reason for solving the problem with code rather than pencil and paper is that you can do more with code. \n", "\n", - "The \"Cheryl's Birthday\" logic puzzle [made the rounds](https://www.google.com/webhp?#q=cheryl%27s+birthday),\n", - "and I wrote [code](Cheryl.ipynb) that solves it. There I said that one reason for solving the problem with code rather than pencil and paper is that you can do more with code. [Gabe Gaster](http://www.gabegaster.com/) proved me right when he [tweeted](https://twitter.com/gabegaster/status/593976413314777089/photo/1) that he had extended my code to generate a new list of dates that satisfies the constraints of the puzzle:\n", + "**[Gabe Gaster](http://www.gabegaster.com/)** proved me right when he [tweeted](https://twitter.com/gabegaster/status/593976413314777089/photo/1) that he had extended my code to generate a new list of dates that satisfies the constraints of the puzzle:\n", "\n", " January 15, January 4,\n", " July 13, July 24, July 30,\n", @@ -25,22 +22,16 @@ "\n", "First, let's recap [the puzzle](https://en.wikipedia.org/wiki/Cheryl%27s_Birthday):\n", "\n", - "> Albert and Bernard just became friends with Cheryl, and they want to know when her birthday is. Cheryl gives them a list of 10 possible dates:\n", - "\n", - "> May 15 16 19\n", - "> June 17 18\t\n", - "> July 14 16\t\t\t\n", - "> August 14 15 17\t\t\n", - "\n", - "> Cheryl then tells Albert and Bernard separately the month and the day of her birthday respectively.\n", - "\n", - ">**Albert**: I don't know when Cheryl's birthday is, but I know that Bernard does not know too.\n", - "\n", - ">**Bernard**: At first I don't know when Cheryl's birthday is, but I know now.\n", - "\n", - ">**Albert**: Then I also know when Cheryl's birthday is.\n", - "\n", - ">So when is Cheryl's birthday?\"" + "> 1. Albert and Bernard became friends with Cheryl, and want to know when her birthday is. Cheryl gave them a list of 10 possible dates:\n", + " May 15 May 16 May 19\n", + " June 17 June 18\n", + " July 14 July 16\n", + " August 14 August 15 August 17\n", + "> 2. **Cheryl** then privately tells Albert the month and Bernard the day of her birthday.\n", + "> 3. **Albert**: \"I don't know when Cheryl's birthday is, and I know that Bernard does not know.\"\n", + "> 4. **Bernard**: \"At first I don't know when Cheryl's birthday is, but I know now.\"\n", + "> 5. **Albert**: \"Then I also know when Cheryl's birthday is.\"\n", + "> 6. So when is Cheryl's birthday?" ] }, { @@ -63,18 +54,13 @@ "- **Hearing** the statements about knowledge.\n", "\n", "I implement them as follows:\n", - "- `DATES` is a set of all possible dates (each date is a string); we also consider subsets of `DATES`.\n", + "- `dates` is a set of all possible dates (each date is a string); we also consider subsets of `dates`.\n", "- `know(possible_dates)` is a function that returns `True` when there is only one possible date.\n", - "- `tell(part)` is a function that returns the set of possible dates after Cheryl tells a part (month or day).\n", - "- *`statement`*`(date)` returns true for dates that satisfy the statement.\n", - "- `hear(possible_dates, statement,...)` returns a subset of possible_dates that are still possible after hearing the statements.\n", - "\n", - "For example, `albert1` is Albert's first statement, which says in part that he knows that Bernard\n", - "does not yet know Cheryl's birthday. So `albert1('May 19')` should be `False`, because if May 19 were Cheryl's birthday, then she would have told Bernard `'19'`, he would know that `'May 19'` is the only possibility.\n", + "- `told(part)` is a function that returns the set of possible dates after Cheryl tells a part (month or day).\n", + "- *`statement`*`(date)` returns true if the statement is true given that `date` is Cheryl's birthday.\n", + "- `satisfy(possible_dates, statement,...)` returns a subset of possible_dates that are still possible after hearing the statements.\n", "\n", - "`tell('17')` returns `{'June 17', 'August 17'}`, the set of possible dates after Bernard is told `'17'`. \n", - "\n", - " `know(tell('17'))` is `False` because if Bernard was told `'17'` he would not know Cheryl's birthday for sure; there would be two possibilities. But `know(tell('19'))` is `True` because there would be only one possibility.\n" + "In the [previous code](Cheryl.ipynb) I treated `dates` as a constant, but in this version the whole point is exploring different possible sets of dates, so now `dates` is a global variable, and the function `set_dates` is used to set the value of the global variable." ] }, { @@ -84,13 +70,12 @@ "outputs": [], "source": [ "# Albert and Bernard just became friends with Cheryl, and they want to know when her birthday is. \n", - "# Cheryl gives them a set of 10 possible dates:\n", + "# Cheryl gave them a list of 10 possible dates:\n", "\n", - "cheryl_dates = DATES = {\n", - " 'May 15', 'May 16', 'May 19',\n", - " 'June 17', 'June 18',\n", - " 'July 14', 'July 16',\n", - " 'August 14', 'August 15', 'August 17'}\n", + "dates = ['May 15', 'May 16', 'May 19',\n", + " 'June 17', 'June 18',\n", + " 'July 14', 'July 16',\n", + " 'August 14', 'August 15', 'August 17']\n", "\n", "def month(date): return date.split()[0]\n", "\n", @@ -99,48 +84,51 @@ "# Cheryl then tells Albert and Bernard separately \n", "# the month and the day of the birthday respectively.\n", "\n", - "def tell(part):\n", - " \"Cheryl tells a part of her birthdate; return a subset of DATES that match the part.\"\n", - " return {date for date in DATES if part in date}\n", + "BeliefState = set\n", + "\n", + "def told(part: str) -> BeliefState:\n", + " \"\"\"Cheryl told a part of her birthdate to someone; return a belief state of possible dates.\"\"\"\n", + " return {date for date in dates if part in date}\n", "\n", - "def know(possible_dates):\n", - " \"A person knows the birthdate if they know there is exactly one possible date.\"\n", - " return len(possible_dates) == 1\n", + "def know(beliefs: BeliefState) -> bool:\n", + " \"\"\"A person `knows` the answer if their belief state has only one possibility.\"\"\"\n", + " return len(beliefs) == 1\n", "\n", - "def hear(possible_dates, *statements):\n", - " \"Return the subset of possible dates that are consistent with all the statements.\"\n", - " return {date for date in possible_dates\n", - " if all(stmt(date) for stmt in statements)}\n", + "def satisfy(some_dates, *statements) -> BeliefState:\n", + " \"\"\"Return the subset of dates that satisfy all the statements.\"\"\"\n", + " return {date for date in some_dates\n", + " if all(statement(date) for statement in statements)}\n", "\n", "# Albert and Bernard make three statements:\n", "\n", - "def albert1(date):\n", - " \"Albert: I don't know when Cheryl's birthday is, but I know that Bernard does not know too.\"\n", - " after_being_told = tell(month(date))\n", - " return (not know(after_being_told) \n", - " and all(not know(tell(day(d)))\n", - " for d in after_being_told))\n", + "def albert1(date) -> bool:\n", + " \"\"\"Albert: I don't know when Cheryl's birthday is, but I know that Bernard does not know too.\"\"\"\n", + " albert_beliefs = told(month(date))\n", + " return not know(albert_beliefs) and not satisfy(albert_beliefs, bernard_knows)\n", "\n", - "def bernard1(date):\n", - " \"Bernard: At first I don't know when Cheryl's birthday is, but I know now.\"\n", - " at_first = tell(day(date))\n", - " return (not know(at_first)\n", - " and know(hear(at_first, albert1)))\n", + "def bernard_knows(date) -> bool: return know(told(day(date))) \n", "\n", - "def albert2(date):\n", - " \"Albert: Then I also know when Cheryl's birthday is.\"\n", - " return know(hear(tell(month(date)), bernard1))\n", + "def bernard1(date) -> bool:\n", + " \"\"\"Bernard: At first I don't know when Cheryl's birthday is, but I know now.\"\"\"\n", + " at_first_beliefs = told(day(date))\n", + " after_beliefs = satisfy(at_first_beliefs, albert1)\n", + " return not know(at_first_beliefs) and know(after_beliefs)\n", + "\n", + "def albert2(date) -> bool:\n", + " \"\"\"Albert: Then I also know when Cheryl's birthday is.\"\"\"\n", + " then = satisfy(told(month(date)), bernard1)\n", + " return know(then)\n", " \n", "# So when is Cheryl's birthday?\n", "\n", - "def cheryls_birthday(dates):\n", - " \"Return a list of the possible dates after hearing the three statements.\"\n", - " return hear(using(dates), albert1, bernard1, albert2)\n", + "def cheryls_birthday(dates) -> BeliefState:\n", + " \"\"\"Return a subset of the global `dates` for which all three statements are true.\"\"\"\n", + " return satisfy(set_dates(dates), albert1, bernard1, albert2)\n", "\n", - "def using(dates):\n", - " \"Make dates be the value of the global variable DATES.\"\n", - " global DATES # This is necessary because `tell` looks at `DATES`\n", - " DATES = dates\n", + "def set_dates(new_dates):\n", + " \"\"\"Set the value of the global `dates` to `new_dates`\"\"\"\n", + " global dates\n", + " dates = new_dates\n", " return dates\n", "\n", "# Some tests\n", @@ -149,8 +137,8 @@ "assert day('May 19') == '19'\n", "assert albert1('May 19') == False\n", "assert albert1('July 14') == True\n", - "assert know(tell('17')) == False\n", - "assert know(tell('19')) == True" + "assert know(told('17')) == False\n", + "assert know(told('19')) == True" ] }, { @@ -170,7 +158,7 @@ } ], "source": [ - "cheryls_birthday(cheryl_dates)" + "cheryls_birthday(dates)" ] }, { @@ -190,7 +178,7 @@ } ], "source": [ - "hear(DATES, albert1)" + "satisfy(dates, albert1)" ] }, { @@ -210,7 +198,7 @@ } ], "source": [ - "hear(DATES, albert1, bernard1)" + "satisfy(dates, albert1, bernard1)" ] }, { @@ -230,7 +218,7 @@ } ], "source": [ - "hear(DATES, albert1, bernard1, albert2)" + "satisfy(dates, albert1, bernard1, albert2)" ] }, { @@ -307,10 +295,10 @@ "metadata": {}, "outputs": [], "source": [ - "some_dates = {mo + ' ' + d1 + d2\n", + "many_dates = {mo + ' ' + d1 + d2\n", " for mo in ('March', 'April', 'May', 'June', 'July')\n", " for d1 in '12'\n", - " for d2 in '56789'}" + " for d2 in '3456789'}" ] }, { @@ -329,12 +317,12 @@ "import random\n", "\n", "def pick_dates(puzzle=cheryls_birthday, k=10):\n", - " \"Pick a set of dates for which the puzzle has a unique solution.\"\n", + " \"Pick a set of `k` dates for which the `puzzle` has a unique solution.\"\n", " while True:\n", - " dates = set(random.sample(some_dates, k))\n", - " solutions = puzzle(dates)\n", + " random_dates = random.sample(many_dates, k)\n", + " solutions = puzzle(random_dates)\n", " if know(solutions):\n", - " return solutions.pop(), dates" + " return solutions.pop(), random_dates" ] }, { @@ -345,17 +333,17 @@ { "data": { "text/plain": [ - "('June 27',\n", - " {'April 19',\n", - " 'April 28',\n", + "('May 27',\n", + " ['May 13',\n", + " 'April 23',\n", + " 'May 27',\n", + " 'April 18',\n", + " 'July 14',\n", + " 'May 23',\n", + " 'July 27',\n", + " 'March 18',\n", " 'June 19',\n", - " 'June 27',\n", - " 'June 28',\n", - " 'March 15',\n", - " 'March 28',\n", - " 'May 16',\n", - " 'May 19',\n", - " 'May 27'})" + " 'March 13'])" ] }, "execution_count": 10, @@ -367,6 +355,59 @@ "pick_dates()" ] }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('July 24',\n", + " ['July 25', 'July 24', 'March 25', 'July 28', 'April 24', 'March 28'])" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pick_dates(k=6)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('May 25',\n", + " ['July 28',\n", + " 'March 19',\n", + " 'July 29',\n", + " 'July 13',\n", + " 'April 27',\n", + " 'June 27',\n", + " 'May 25',\n", + " 'April 28',\n", + " 'April 18',\n", + " 'July 25',\n", + " 'June 15',\n", + " 'May 18'])" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pick_dates(k=12)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -376,85 +417,85 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "from collections import Counter\n", "\n", - "def counter(puzzle=cheryls_birthday, N=10000, k=10):\n", - " \"Try N random samples and count how often each possible length-of-solution appears.\"\n", - " return Counter(len(puzzle(set(random.sample(some_dates, k))))\n", + "def solution_lengths(puzzle=cheryls_birthday, N=10000, k=10, many_dates=many_dates):\n", + " \"Try N random samples and count how often each possible length-of-puzzle-solution appears.\"\n", + " return Counter(len(puzzle(random.sample(many_dates, k)))\n", " for _ in range(N))" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "Counter({0: 8700, 1: 614, 2: 684, 3: 2})" + "Counter({0: 9513, 1: 210, 2: 276, 3: 1})" ] }, - "execution_count": 12, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "counter(cheryls_birthday)" + "solution_lengths(cheryls_birthday)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "This says that about 6% of the time we get a unique solution (a set of `len` 1). With similar frequency we get an ambiguous solution (with 2 or more possible birth dates). And most of the time, the sample of dates leads to no solution.\n", + "This says that about 2% of the time we get a unique solution (a set of `len` 1). With similar frequency we get an ambiguous solution (with 2 or more possible birth dates). And about 95% of the time, the sample of dates leads to no solution dates.\n", "\n", "What happens if Cheryl changes the number of possible dates?" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "Counter({0: 9972, 1: 11, 2: 17})" + "Counter({0: 9971, 2: 18, 1: 11})" ] }, - "execution_count": 13, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "counter(cheryls_birthday, k=6)" + "solution_lengths(cheryls_birthday, k=6)" ] }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "Counter({0: 7532, 1: 1394, 2: 1030, 3: 44})" + "Counter({0: 9020, 2: 467, 1: 503, 3: 10})" ] }, - "execution_count": 14, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "counter(cheryls_birthday, k=12)" + "solution_lengths(cheryls_birthday, k=12)" ] }, { @@ -477,43 +518,37 @@ "source": [ "Now let's see if we can create a more complicated puzzle. We'll introduce a new character, Eve, give her a statement, and alter the rest of the puzzle slightly:\n", "\n", - "> *Albert and Bernard just became friends with Cheryl, and they want to know when her birthday is. Cheryl wrote down a list of 10 possible dates for all to see.*\n", - " \n", - "> *Cheryl then writes down the month and shows it just to Albert, and also writes down the day and shows it just to Bernard.*\n", - "\n", - "> **Albert**: *I don't know when Cheryl's birthday is, but I know that Bernard does not know either.*\n", - "\n", - "> **Bernard**: *At first I didn't know when Cheryl's birthday is, but I know now.*\n", - " \n", - "> **Albert**: *Then I also know when Cheryl's birthday is.*\n", - "\n", - "> **Eve**: *Hi, my name is Eve and I'm an evesdropper. It's what I do! I peeked and saw the first letter of the month and the first digit of the day. When I peeked, I didn't know Cheryl's birthday, but after listening to Albert and Bernard I do. And it's a good thing I peeked, because otherwise I couldn't have\n", - "figured it out.*\n", - " \n", - "> *So when is Cheryl's birthday?*\n", + "> 1. Albert and Bernard just became friends with Cheryl, and they want to know when her birthday is. Cheryl wrote down a list of 10 possible dates for all to see.\n", + "> 2. **Cheryl** then writes down the month and shows it just to Albert, and also writes down the day and shows it just to Bernard.\n", + "> 3. **Albert**: I don't know when Cheryl's birthday is, but I know that Bernard does not know either.\n", + "> 4. **Bernard**: At first I didn't know when Cheryl's birthday is, but I know now.\n", + "> 5. **Albert**: Then I also know when Cheryl's birthday is.\n", + "> 6. **Eve**: Hi, Everybody. My name is Eve and I'm an evesdropper. It's what I do! I peeked and saw the first letter of the month and the first digit of the day. When I peeked, I didn't know Cheryl's birthday, but after listening to Albert and Bernard I do. And it's a good thing I peeked, because otherwise I couldn't have\n", + "figured it out.\n", + "> 7. So when is Cheryl's birthday?\n", "\n", "We can easily code this up:" ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "def cheryls_birthday_with_eve(dates):\n", " \"Return a set of the dates for which Albert, Bernard, and Eve's statements are true.\"\n", - " return hear(using(dates), albert1, bernard1, albert2, eve1)\n", + " return satisfy(set_dates(dates), albert1, bernard1, albert2, eve1)\n", "\n", "def eve1(date):\n", " \"\"\"Eve: I peeked and saw the first letter of the month and the first digit of the day. \n", " When I peeked, I didn't know Cheryl's birthday, but after listening to Albert and Bernard \n", " I do. And it's a good thing I peeked, because otherwise I couldn't have figured it out.\"\"\"\n", - " at_first = tell(first(day(date))) & tell(first(month(date)))\n", - " otherwise = tell('')\n", + " at_first = told(first(day(date))) & told(first(month(date)))\n", + " otherwise = told('')\n", " return (not know(at_first) and\n", - " know(hear(at_first, albert1, bernard1, albert2)) and\n", - " not know(hear(otherwise, albert1, bernard1, albert2)))\n", + " know(satisfy(at_first, albert1, bernard1, albert2)) and\n", + " not know(satisfy(otherwise, albert1, bernard1, albert2)))\n", "\n", "def first(seq): return seq[0]" ] @@ -522,33 +557,33 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "*Note*: I admit I \"cheated\" a bit here. Remember that the function `tell` tests for `(part in date)`. For that to work for Eve, we have to make sure that the first letter is distinct from any other character in the date (it is—because only the first letter is uppercase) and that the first digit is distinct from any other character (it is—because in `some_dates` I carefully made sure that the first digit is always 1 or 2, and the second digit is never 1 or 2). Also note that `tell('')` denotes the hypothetical situation where Cheryl \"told\" Eve nothing.\n", + "*Note*: I admit I \"cheated\" a bit here. Remember that the function `told` tests for `(part in date)`. For that to work for Eve, we have to make sure that the first letter is distinct from any other character in the date (it is—because only the first letter is uppercase) and that the first digit is distinct from any other character (it is—because in `many_dates` I carefully made sure that the first digit is always 1 or 2, and the second digit is never 1 or 2). Also note that `told('')` denotes the hypothetical situation where Cheryl \"told\" Eve nothing.\n", "\n", "I have no idea if it is possible to find a set of dates that works for this puzzle. But I can try:" ] }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "('July 17',\n", - " {'April 18',\n", - " 'April 25',\n", - " 'April 29',\n", - " 'July 17',\n", - " 'July 18',\n", - " 'June 18',\n", - " 'June 29',\n", - " 'March 27',\n", - " 'May 17',\n", - " 'May 28'})" + "('March 18',\n", + " ['April 25',\n", + " 'March 18',\n", + " 'March 16',\n", + " 'April 27',\n", + " 'May 29',\n", + " 'July 28',\n", + " 'May 24',\n", + " 'July 16',\n", + " 'May 28',\n", + " 'April 18'])" ] }, - "execution_count": 16, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } @@ -566,22 +601,22 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "Counter({0: 9492, 1: 258, 2: 250})" + "Counter({0: 9729, 1: 143, 2: 128})" ] }, - "execution_count": 17, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "counter(cheryls_birthday_with_eve)" + "solution_lengths(cheryls_birthday_with_eve)" ] }, { @@ -604,52 +639,46 @@ "source": [ "Let's make the puzzle even more complicated by making Albert wait one more time before he finally knows:\n", "\n", - "> *Albert and Bernard just became friends with Cheryl, and they want to know when her birtxhday is. Cheryl wrote down a list of 10 possible dates for all to see.*\n", - " \n", - "> *Cheryl then writes down the month and shows it just to Albert, and also writes down the day and shows it just to Bernard.*\n", - " \n", - "> **Albert**: *I don't know when Cheryl's birthday is, but I know that Bernard does not know either.*\n", - " \n", - "> **Bernard**: *At first I didn't know when Cheryl's birthday is, but I know now.*\n", - " \n", - "> **Albert**: *I still don't know.*\n", - "\n", - "> **Eve**: *Hi, my name is Eve and I'm an evesdropper. It's what I do! I peeked and saw the first letter of the month and the first digit of the day. When I peeked, I didn't know Cheryl's birthday, but after listening to Albert and Bernard I do. And it's a good thing I peeked, because otherwise I couldn't have figured it out.*\n", - "\n", - "> **Albert**: *OK, now I know.*\n", - " \n", - "> *So when is Cheryl's birthday?*\n", + "> 1. Albert and Bernard just became friends with Cheryl, and they want to know when her birtxhday is. Cheryl wrote down a list of 10 possible dates for all to see.\n", + "> 2. **Cheryl** then writes down the month and shows it just to Albert, and also writes down the day and shows it just to Bernard.\n", + "> 3. **Albert**: I don't know when Cheryl's birthday is, but I know that Bernard does not know either. \n", + "> 4. **Bernard**: At first I didn't know when Cheryl's birthday is, but I know now.\n", + "> 5. **Albert**: I still don't know.\n", + "> 6. **Eve**: Hi, Everybody. My name is Eve and I'm an evesdropper. It's what I do! I peeked and saw the first letter of the month and the first digit of the day. When I peeked, I didn't know Cheryl's birthday, but after listening to Albert and Bernard I do. And it's a good thing I peeked, because otherwise I couldn't have\n", + "figured it out.\n", + "> 7. **Albert**: OK, now I know.\n", + "> 8. So when is Cheryl's birthday?\n", "\n", "Let's be careful in coding this up; Albert's second statement is different; he has a new third statement; and Eve's statement uses the same words, but it now implicitly refers to a different statement by Albert. We'll use the names `albert2c`, `eve1c`, and `albert3c` (`c` for \"complex\") to represent the new statements:" ] }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "def cheryls_birthday_complex(dates):\n", " \"Return a set of the dates for which Albert, Bernard, and Eve's statements are true.\"\n", - " return hear(using(dates), albert1, bernard1, albert2c, eve1c, albert3c)\n", + " return satisfy(set_dates(dates), albert1, bernard1, albert2c, eve1c, albert3c)\n", "\n", "def albert2c(date):\n", " \"Albert: I still don't know.\"\n", - " return not know(hear(tell(month(date)), bernard1))\n", + " return not know(satisfy(told(month(date)), bernard1))\n", "\n", "def eve1c(date):\n", " \"\"\"Eve: I peeked and saw the first letter of the month and the first digit of the day. \n", " When I peeked, I didn't know Cheryl's birthday, but after listening to Albert and Bernard \n", " I do. And it's a good thing I peeked, because otherwise I couldn't have figured it out.\"\"\"\n", - " at_first = tell(first(day(date))) & tell(first(month(date)))\n", - " otherwise = tell('')\n", + " at_first = told(first(day(date))) & told(first(month(date)))\n", + " otherwise = told('')\n", " return (not know(at_first)\n", - " and know(hear(at_first, albert1, bernard1, albert2c)) and\n", - " not know(hear(otherwise, albert1, bernard1, albert2c)))\n", + " and know(satisfy(at_first, albert1, bernard1, albert2c)) and\n", + " not know(satisfy(otherwise, albert1, bernard1, albert2c)))\n", "\n", "def albert3c(date):\n", " \"Albert: OK, now I know.\"\n", - " return know(hear(tell(month(date)), eve1c))" + " return know(satisfy(told(month(date)), bernard1, eve1c))" ] }, { @@ -661,26 +690,26 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "('July 29',\n", - " {'April 29',\n", - " 'July 15',\n", - " 'July 18',\n", - " 'July 29',\n", - " 'June 25',\n", - " 'March 15',\n", - " 'March 19',\n", - " 'March 25',\n", - " 'May 18',\n", - " 'May 27'})" + "('March 29',\n", + " ['June 16',\n", + " 'March 13',\n", + " 'March 29',\n", + " 'May 25',\n", + " 'June 13',\n", + " 'April 23',\n", + " 'April 14',\n", + " 'June 29',\n", + " 'March 14',\n", + " 'June 27'])" ] }, - "execution_count": 19, + "execution_count": 21, "metadata": {}, "output_type": "execute_result" } @@ -698,22 +727,22 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "Counter({0: 9047, 1: 951, 2: 2})" + "Counter({0: 9408, 1: 591, 2: 1})" ] }, - "execution_count": 20, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "counter(cheryls_birthday_complex)" + "solution_lengths(cheryls_birthday_complex)" ] }, { @@ -739,11 +768,11 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 23, "metadata": {}, "outputs": [], "source": [ - "DATES = {\n", + "previous_run_dates = {\n", " 'April 28',\n", " 'July 27',\n", " 'June 19',\n", @@ -765,7 +794,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 24, "metadata": {}, "outputs": [ { @@ -774,13 +803,13 @@ "{'July 27'}" ] }, - "execution_count": 22, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "cheryls_birthday_complex(DATES)" + "cheryls_birthday_complex(previous_run_dates)" ] }, { @@ -792,7 +821,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 25, "metadata": {}, "outputs": [ { @@ -801,13 +830,13 @@ "{'July 15', 'July 16', 'July 27'}" ] }, - "execution_count": 23, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "tell('July')" + "told('July')" ] }, { @@ -819,7 +848,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 26, "metadata": {}, "outputs": [ { @@ -828,14 +857,13 @@ "True" ] }, - "execution_count": 24, + "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "all(not know(tell(day(d)))\n", - " for d in tell('July'))" + "not know(told('15')) and not know(told('16')) and not know(told('27'))" ] }, { @@ -847,7 +875,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 27, "metadata": {}, "outputs": [ { @@ -856,13 +884,13 @@ "{'July 27', 'May 27'}" ] }, - "execution_count": 25, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "tell('27')" + "told('27')" ] }, { @@ -874,7 +902,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 28, "metadata": {}, "outputs": [ { @@ -883,13 +911,13 @@ "{'July 27'}" ] }, - "execution_count": 26, + "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "hear(tell('27'), albert1)" + "satisfy(told('27'), albert1)" ] }, { @@ -901,7 +929,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 29, "metadata": {}, "outputs": [ { @@ -910,13 +938,13 @@ "{'July 15', 'July 16', 'July 27'}" ] }, - "execution_count": 27, + "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "hear(tell('July'), bernard1)" + "satisfy(told('July'), bernard1)" ] }, { @@ -928,7 +956,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 30, "metadata": {}, "outputs": [ { @@ -937,13 +965,13 @@ "{'July 27', 'June 29'}" ] }, - "execution_count": 28, + "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "tell('J') & tell('2')" + "told('J') & told('2')" ] }, { @@ -955,7 +983,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 31, "metadata": {}, "outputs": [ { @@ -964,13 +992,13 @@ "{'July 27'}" ] }, - "execution_count": 29, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "hear(tell('J') & tell('2'), albert1, bernard1, albert2c)" + "satisfy(told('J') & told('2'), albert1, bernard1, albert2c)" ] }, { @@ -982,7 +1010,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 32, "metadata": {}, "outputs": [ { @@ -991,13 +1019,13 @@ "{'July 15', 'July 16', 'July 27'}" ] }, - "execution_count": 30, + "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "hear(tell(''), albert1, bernard1, albert2c)" + "satisfy(told(''), albert1, bernard1, albert2c)" ] }, { @@ -1009,7 +1037,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 33, "metadata": {}, "outputs": [ { @@ -1018,13 +1046,13 @@ "{'July 27'}" ] }, - "execution_count": 31, + "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "hear(tell('July'), eve1c)" + "satisfy(told('July'), eve1c)" ] }, { @@ -1035,26 +1063,22 @@ "\n", "Here's another puzzle:\n", "\n", - "> *A parent has the following conversation with a friend:*\n", + "> 1. A parent has the following conversation with a friend:\n", + "> 2. **Parent:** the product of my three childrens' ages is 36.\n", + "> 3. **Friend**: I don't know their ages.\n", + "> 4. **Parent**: The sum of their ages is the same as the number of people in this room.\n", + "> 5. **Friend**: I still don't know their ages.\n", + "> 6. **Parent**: The oldest one likes bananas.\n", + "> 7. **Friend**: Now I know their ages.\n", "\n", - "> **Parent:** the product of my three childrens' ages is 36.\n", + "Let's follow the same methodology to solve this puzzle. Except this time, we're not dealing with sets of possible dates, we're dealing with set of possible *states* of the world. We'll define a state as a tuple of 4 numbers: the ages of the three children (in increasing order), and the number of people in the room. \n", "\n", - "> **Friend**: I don't know their ages.\n", - "\n", - "> **Parent**: The sum of their ages is the same as the number of people in this room.\n", - "\n", - "> **Friend**: I still don't know their ages.\n", - "\n", - "> **Parent**: The oldest one likes bananas.\n", - "\n", - "> **Friend**: Now I know their ages.\n", - "\n", - "Let's follow the same methodology to solve this puzzle. Except this time, we're not dealing with sets of possible dates, we're dealing with set of possible *states* of the world. We'll define a state as a tuple of 4 numbers: the ages of the three children (in increasing order), and the number of people in the room. (We'll limit the children's ages to be below 30 and the number of people in the room to be below 90.)" + "Note: We'll limit the children's ages to be below 30 and the number of people in the room to be below 90. Also, in `friend2` and `friend3` we'll compute the `possible_states` and cache them, since the computation does not depend on the `date`." ] }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 34, "metadata": {}, "outputs": [ { @@ -1063,7 +1087,7 @@ "{(2, 2, 9, 13)}" ] }, - "execution_count": 32, + "execution_count": 34, "metadata": {}, "output_type": "execute_result" } @@ -1080,35 +1104,38 @@ "def room(state): return state[-1]\n", "\n", "def parent1(state): \n", - " \"The product of my three childrens' ages is 36.\"\n", + " \"\"\"The product of my three childrens' ages is 36.\"\"\"\n", " a, b, c = ages(state)\n", " return a * b * c == 36\n", "\n", "def friend1(state): \n", - " \"I don't know their ages.\"\n", - " return not know({ages(s) for s in hear(states, parent1)})\n", + " \"\"\"I don't know their ages.\"\"\"\n", + " possible_ages = {ages(s) for s in satisfy(states, parent1)}\n", + " return not know(possible_ages)\n", "\n", "def parent2(state):\n", - " \"The sum of their ages is the same as the number of people in this room.\"\n", + " \"\"\"The sum of their ages is the same as the number of people in this room.\"\"\"\n", " return sum(ages(state)) == room(state)\n", "\n", - "def friend2(state, possibilities=hear(states, parent1, friend1, parent2)): \n", - " \"I still don't know their ages.\"\n", + "def friend2(state, possible_states=satisfy(states, parent1, friend1, parent2)): \n", + " \"\"\"I still don't know their ages.\"\"\"\n", " # Given there are room(state) people in the room, I still don't know the ages.\n", - " return not know({ages(s) for s in possibilities if room(s) == room(state)})\n", + " possible_ages = {ages(s) for s in possible_states if room(s) == room(state)}\n", + " return not know(possible_ages)\n", "\n", "def parent3(state):\n", - " \"The oldest one likes bananas.\"\n", + " \"\"\"The oldest one likes bananas.\"\"\"\n", " # I.e., there is an oldest one (and not twins of the same age)\n", " a, b, c = ages(state)\n", " return c > b\n", "\n", - "def friend3(state, possibilities=hear(states, parent1, friend1, parent2, friend2, parent3)): \n", + "def friend3(state, possible_states=satisfy(states, parent1, friend1, parent2, friend2, parent3)): \n", " \"Now I know their ages.\"\n", - " return know({ages(s) for s in possibilities})\n", + " possible_ages = {ages(s) for s in possible_states}\n", + " return know(possible_ages)\n", "\n", "def child_age_puzzle(states):\n", - " return hear(states, parent1, friend1, parent2, friend2, parent3, friend3)\n", + " return satisfy(states, parent1, friend1, parent2, friend2, parent3, friend3)\n", "\n", "child_age_puzzle(states)" ] @@ -1122,7 +1149,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 35, "metadata": {}, "outputs": [ { @@ -1137,13 +1164,13 @@ " (3, 3, 4, 10)}" ] }, - "execution_count": 33, + "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "hear(states, parent1, friend1, parent2)" + "satisfy(states, parent1, friend1, parent2)" ] }, { @@ -1194,7 +1221,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.3" + "version": "3.7.7" } }, "nbformat": 4, diff --git a/ipynb/Cheryl.ipynb b/ipynb/Cheryl.ipynb index 87c7cdea..d9d01ca7 100644 --- a/ipynb/Cheryl.ipynb +++ b/ipynb/Cheryl.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "
Peter Norvig
April 2015
Python 3: Feb 2019
Steve's bus: Apr 2020
\n", + "
Peter Norvig
April 2015
Python 3: Feb 2019
Steve's bus: Apr 2020
\n", "\n", "# When is Cheryl's Birthday?\n", "\n", @@ -16,7 +16,7 @@ " June 17 June 18\n", " July 14 July 16\n", " August 14 August 15 August 17\n", - "> 2. **Cheryl** then tells Albert and Bernard separately the month and the day of the birthday respectively.\n", + "> 2. **Cheryl** then privately tells Albert the month and Bernard the day of her birthday.\n", "> 3. **Albert**: \"I don't know when Cheryl's birthday is, and I know that Bernard does not know.\"\n", "> 4. **Bernard**: \"At first I don't know when Cheryl's birthday is, but I know now.\"\n", "> 5. **Albert**: \"Then I also know when Cheryl's birthday is.\"\n", @@ -62,18 +62,7 @@ "cell_type": "code", "execution_count": 3, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'May'" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "month('May 15')" ] @@ -82,18 +71,7 @@ "cell_type": "code", "execution_count": 4, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'15'" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "day('May 15')" ] @@ -109,10 +87,10 @@ "1. Albert and Bernard are uncertain about the birthdate. *(Cheryl knows something they don't know.)*\n", "2. We, the puzzle solvers don't know what Albert and Bernard were told. *(They know something we don't know.)*\n", "\n", - "If Cheryl tells Albert \"May\", then he believes the birthdate could be either May 15, May 16, or May 19. We'll call `{'May 15', 'May 16', 'May 19'}` his **belief set** about the birthdate. We will say that a person **knows** the birthdate when they get down to a belief set with exactly one possibility. The type 2 uncertainty is that we don't know that Albert was told \"May\", so we have uncertainty about his belief set. But we do know some statements about his belief set, and our task is to use those statements to solve the puzzle. \n", + "If Cheryl tells Albert \"May\", then he believes the birthdate could be either May 15, May 16, or May 19. We'll call `{'May 15', 'May 16', 'May 19'}` his **belief state** about the birthdate. We will say that a person **knows** the birthdate when they get down to a belief state with exactly one possibility. The type 2 uncertainty is that we don't know that Albert was told \"May\", so we have uncertainty about his belief state. But we do know some statements about his belief state, and our task is to use those statements to solve the puzzle. \n", "\n", "The way we will deal with our uncertainty as puzzle solvers is by considering each of the ten dates one at a time and reasoning as follows: \n", - "- If this date were Cheryl's true birthdate, then we would know what Albert and Bernard were told: we would eliminate the type 2 uncertainty, and we could figure out their belief sets. \n", + "- If this date were Cheryl's true birthdate, then we would know what Albert and Bernard were told: we would eliminate the type 2 uncertainty, and we could figure out their belief states. \n", "- From that we could figure out if the statements are true (given this date). \n", "- If the puzzle is correct and we don't make mistakes, then there will be only one date that makes all the statements true; that's Cheryl's birthday.\n", "\n", @@ -125,14 +103,14 @@ "metadata": {}, "outputs": [], "source": [ - "BeliefSet = set\n", + "BeliefState = set\n", "\n", - "def told(part: str) -> BeliefSet:\n", - " \"\"\"Cheryl told a part of her birthdate to someone; return a belief set of possible dates.\"\"\"\n", + "def told(part: str) -> BeliefState:\n", + " \"\"\"Cheryl told a part of her birthdate to someone; return a belief state of possible dates.\"\"\"\n", " return {date for date in dates if part in date}\n", "\n", - "def know(beliefs: BeliefSet) -> bool:\n", - " \"\"\"A person `knows` the answer if their belief set has only one possibility.\"\"\"\n", + "def know(beliefs: BeliefState) -> bool:\n", + " \"\"\"A person `knows` the answer if their belief state has only one possibility.\"\"\"\n", " return len(beliefs) == 1" ] }, @@ -144,25 +122,14 @@ "\n", "Let's see what happens as we consider the date `'May 15'`:\n", "\n", - "Cheryl tells Albert `'May'` and Bernard `'15'`, giving them these belief sets: " + "Cheryl tells Albert `'May'` and Bernard `'15'`, giving them these belief states: " ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'May 15', 'May 16', 'May 19'}" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "told('May')" ] @@ -191,7 +158,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We can then check whether statements 3 through 5 are true, given this date. The first part of statement 3 is \"I (Albert) don't know when Cheryl's birthday is.\" We can verify that that part of the statement is true (given that Albert was told \"May\"):" + "We can then check whether Albert and Bernard's statements are true, given this date. The first part of Albert's first statement is \"I don't know when Cheryl's birthday is.\" We can verify that that part of the statement is true (given that Albert was told \"May\"):" ] }, { @@ -218,7 +185,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "If the rest of statement 3, along with statements 4 and 5 also worked out to be true, then `'May 15'` would be a solution to the puzzle. If not, it must be one of the other dates." + "If the rest of the statements worked out to be true, then `'May 15'` would be a solution to the puzzle. If not, it must be one of the other dates." ] }, { @@ -227,9 +194,9 @@ "source": [ "# Overall Strategy\n", "\n", - "Here is the main function, `cheryls_birthday`, which computes the subset of dates in the global variable `dates` that satisfy statements 3 through 5. We will define a **statement** as a boolean function that takes a single date as input and returns true if the statement would be true in the condition that the given date is Cheryl's actual birthday. So a statement only has to consider one date at a time. But the code within a statement may have to consider the belief sets of Albert and Bernard, to determine if the statement is true.\n", + "Here is the main function, `cheryls_birthday`, which computes the subset of dates in the global variable `dates` that satisfy statements 3 through 5. We will define a **statement** as a boolean function that takes a single date as input and returns true if the statement would be true in the condition that the given date is Cheryl's actual birthday. So a statement only has to consider one date at a time. But the code within a statement may have to consider the belief states of Albert and Bernard, to determine if the statement is true.\n", "\n", - "The function `satisfy` takes a collection of items (here a set of dates) and returns the subset that satisfies all the predicates:" + "The function `satisfy` takes a collection of dates and some statement(s) and returns the subset that satisfies all the statements:" ] }, { @@ -238,14 +205,14 @@ "metadata": {}, "outputs": [], "source": [ - "def cheryls_birthday() -> BeliefSet:\n", + "def cheryls_birthday() -> BeliefState:\n", " \"\"\"Return a subset of the global `dates` for which all three statements are true.\"\"\"\n", - " return satisfy(dates, statement3, statement4, statement5)\n", + " return satisfy(dates, albert1, bernard1, albert2)\n", "\n", - "def satisfy(items, *predicates) -> BeliefSet:\n", - " \"\"\"Return the subset of items that satisfy all the predicates.\"\"\"\n", - " return {item for item in items\n", - " if all(predicate(item) for predicate in predicates)}" + "def satisfy(some_dates, *statements) -> BeliefState:\n", + " \"\"\"Return the subset of dates that satisfy all the statements.\"\"\"\n", + " return {date for date in some_dates\n", + " if all(statement(date) for statement in statements)}" ] }, { @@ -259,9 +226,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The function `statement3` takes as input a single possible birthdate and returns `True` if Albert's statement is true for that birthdate. How do we go from Albert's English statement to a Python function? Let's paraphrase it in a form that uses the concepts we have defined:\n", + "The function `albert1` takes as input a single possible birthdate and returns `True` if Albert's statement is true for that birthdate. How do we go from Albert's English statement to a Python function? Let's paraphrase it in a form that uses the concepts we have defined:\n", "\n", - "> **Albert**: After Cheryl **told** me the **month** of her birthdate, my **belief set** was such that I didn't **know** her birthday. And I know that Bernard does not know; in other words he could not make the statement that he knows. How do I know that? I can see that for all the possible dates in my **belief set**, if Bernard was **told** the **day** of that date, he would **not know** Cheryl's birthday.\n", + "> **Albert**: After Cheryl **told** me the **month** of her birthdate, my **belief state** was such that I didn't **know** her birthday. And I know that Bernard does not know; in other words he could not make the statement that he knows. How do I know that? I can see that for all the possible dates in my **belief state**, if Bernard was **told** the **day** of that date, he would **not know** Cheryl's birthday.\n", "\n", "That I can translate directly into code:" ] @@ -272,7 +239,7 @@ "metadata": {}, "outputs": [], "source": [ - "def statement3(date) -> bool:\n", + "def albert1(date) -> bool:\n", " \"\"\"Albert: I don't know when Cheryl's birthday is, but I know that Bernard does not know too.\"\"\"\n", " albert_beliefs = told(month(date))\n", " return not know(albert_beliefs) and not satisfy(albert_beliefs, bernard_knows)\n", @@ -304,7 +271,7 @@ } ], "source": [ - "satisfy(dates, statement3)" + "satisfy(dates, albert1)" ] }, { @@ -315,7 +282,7 @@ "\n", "Again, a paraphrase:\n", "\n", - "> **Bernard:** At first Cheryl **told** me the **day**, and I didn't **know**. After I heard Albert's **statement 3**, I updated my **belief set**, and now I **know**." + "> **Bernard:** At first Cheryl **told** me the **day**, and I didn't **know**. After I heard Albert's **statement**, I updated my **belief state**, and now I **know**." ] }, { @@ -324,11 +291,11 @@ "metadata": {}, "outputs": [], "source": [ - "def statement4(date) -> bool:\n", + "def bernard1(date) -> bool:\n", " \"Bernard: At first I don't know when Cheryl's birthday is, but I know now.\"\n", " at_first_beliefs = told(day(date))\n", - " after3_beliefs = satisfy(at_first_beliefs, statement3)\n", - " return not know(at_first_beliefs) and know(after3_beliefs)" + " after_beliefs = satisfy(at_first_beliefs, albert1)\n", + " return not know(at_first_beliefs) and know(after_beliefs)" ] }, { @@ -355,7 +322,7 @@ } ], "source": [ - "satisfy(dates, statement3, statement4)" + "satisfy(dates, albert1, bernard1)" ] }, { @@ -383,10 +350,10 @@ "metadata": {}, "outputs": [], "source": [ - "def statement5(date) -> bool:\n", + "def albert2(date) -> bool:\n", " \"Albert: Then I also know when Cheryl's birthday is.\" \n", - " after4_beliefs = satisfy(told(month(date)), statement4)\n", - " return know(after4_beliefs)" + " then = satisfy(told(month(date)), bernard1)\n", + " return know(then)" ] }, {