Add files via upload

This commit is contained in:
Peter Norvig
2020-04-16 14:14:44 -07:00
committed by GitHub
parent 002fddaf0b
commit 6c6221b868
2 changed files with 383 additions and 389 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"<div align=\"right\"><i>Peter Norvig<br>April 2015<br>Python 3: Feb 2019<br>Steve's bus: Apr 2020</i></div>\n",
"<div align=\"right\" style=\"text-align: right\"><i>Peter Norvig<br>April 2015<br>Python 3: Feb 2019<br>Steve's bus: Apr 2020</i></div>\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)"
]
},
{