diff --git a/ipynb/Sicherman Dice.ipynb b/ipynb/Sicherman Dice.ipynb
index 35ab0de..be0ad7a 100644
--- a/ipynb/Sicherman Dice.ipynb
+++ b/ipynb/Sicherman Dice.ipynb
@@ -13,35 +13,35 @@
"source": [
"# Sicherman Dice\n",
"\n",
- "*Note: This notebook takes the form of a conversation between two problem solvers. One speaks in* **bold**, *the other in* plain. *Also note, for those who are not native speakers of English: \"dice\" is the plural form; \"die\" is the singular.*\n",
+ "Note: This notebook takes the form of a conversation between two problem solvers, *Ali* and ***Bo***. Also note, for those who are not native speakers of English: \"dice\" is the plural form; \"die\" is the singular.\n",
"\n",
- "Huh. This is interesting. You know how in many games, such as craps or Monopoly, you roll two regular dice and add them up. Only the sum matters, not what either of the individual dice shows.\n",
+ "Ali: Huh. This is interesting. You know how in many games, such as craps or Monopoly, you roll two dice and add them up. Only the sum matters, not what number either of the individual dice shows.\n",
"\n",
- "**Right.**\n",
+ "**Bo: Right.**\n",
"\n",
- "And some of those sums, like 8, can be made multiple ways, while 2 and 12 can only be made one way. \n",
+ "Ali: And some of those sums, like 7, can be made multiple ways, while 2 and 12 can only be made one way. \n",
"\n",
- "**Yeah. 8 can be made 5 ways, so it has a 5/36 probability of occurring.**\n",
+ "**Bo: Yeah. 8 can be made 5 ways, so it has a 5/36 probability of occuring.**\n",
"\n",
- "The interesting thing is that people have been playing dice games for 7,000 years. But it wasn't until 1977 that Colonel George Sicherman asked whether is is possible to have a pair of dice that are not regular dice—that is, they don't have (1, 2, 3, 4, 5, 6) on the six sides—but have the same distribution of sums as a regular pair—so the pair of dice would also have to have 5 ways of making 8, but it could be different ways; maybe 7+1 could be one way. Sicherman assumes that each side bears a positive integer.\n",
+ "Ali: The interesting thing is that people have been playing dice games for 7,000 years. But it wasn't until 1977 that Colonel George Sicherman asked whether is is possible to have a pair of dice that are not regular dice—that is, they don't have (1, 2, 3, 4, 5, 6) on the six sides—but have the same distribution of sums as a regular pair—so the pair of dice would also have to have 5 ways of making 8, but it could be different ways; maybe 7+1 could be one way. Sicherman assumes that each side has a positive integer.\n",
"\n",
- "**And what did he find?**\n",
+ "**Bo: And what did he find?**\n",
"\n",
- "Wouldn't it be more fun to figure it out for ourselves?\n",
+ "Ali: Wouldn't it be more fun to figure it out for ourselves?\n",
"\n",
- "**OK!**\n",
+ "**Bo: OK!**\n",
"\n",
- "How could we proceed?\n",
+ "Ali: How could we proceed?\n",
"\n",
- "**When in doubt, [use brute force](http://quotes.lifehack.org/quote/ken-thompson/when-in-doubt-use-brute-force/): we can write a program to enumerate the possibilities:**\n",
+ "**Bo: When in doubt, [use brute force](http://quotes.lifehack.org/quote/ken-thompson/when-in-doubt-use-brute-force/): we can write a program to enumerate the possibilities:**\n",
"\n",
"\n",
"- **Generate all dice that could possibly be part of a solution, such as (1, 2, 2, 4, 8, 9).**\n",
- "- **Consider all pairs of these dice, such as ((1, 3, 4, 4, 5, 8), (1, 2, 2, 3, 3, 4))**\n",
+ "- **Consider all pairs of these dice, such as ((1, 3, 4, 4, 5, 8), (1, 2, 2, 4, 8, 9))**\n",
"- **See if we find any pairs that are not the regular pair, but do have the same distribution of sums as the regular pair.**\n",
"\n",
"\n",
- "That's great. I can code up your description almost verbatim. I'll also keep track of our TO DO list:"
+ "Ali: That's great. I can code up your description almost verbatim. I'll also keep track of our TO DO list:"
]
},
{
@@ -79,9 +79,9 @@
}
},
"source": [
- "**Looks good to me.**\n",
+ "**Bo: Looks good to me.**\n",
"\n",
- "Now we can tick off the items in the TO DO list. The function `pairs` is first, and it is easy:"
+ "Ali: Now we can tick off the items in the TO DO list. The function `pairs` is first, and it is easy:"
]
},
{
@@ -116,7 +116,7 @@
}
},
"source": [
- "**That's good. We could have used the library function `itertools.combinations_with_replacement`, but let's just leave it as is. We should test to make sure it works:**"
+ "**Bo: That's good. We could have used the library function `itertools.combinations_with_replacement`, but let's just leave it as is. We should test to make sure it works:**"
]
},
{
@@ -161,20 +161,19 @@
"# TO DO: `sums(pair)`\n",
"\n",
"\n",
- "Now for `sums`: we need some way to represent all the 36 possible sums from a pair of dice. We want a representation that will be the same for two different pairs if all 36 sums are the same, but where the order or composition of the sums doesn't matter. \n",
+ "Ali: Now for `sums`: we need some way to represent all the 36 possible sums from a pair of dice. We want a representation that will be the same for two different pairs if all 36 sums are the same, but where the order or composition of the sums doesn't matter. \n",
"\n",
- "**So we want a set of the sums?**\n",
+ "**Bo: So we want a set of the sums?**\n",
"\n",
- "Well, it can't be a set, because we need to know that 8 can be made 5 ways, not just that 8 is a member of the set. The technical term for a collection where order doesn't matter but where you can have repeated elements is a **bag**, or sometimes called a [**multiset**](https://en.wikipedia.org/wiki/Multiset). For example, the regular pair of dice makes two 11s with 5+6 and 6+5, and another pair could make two 11s with 7+4 and 3+8. Can you think of a representation that will do that?\n",
+ "Ali: Well, it can't be a set, because we need to know that 8 can be made 5 ways, not just that 8 is a member of the set. The technical term for a collection where order doesn't matter but where you can have repeated elements is a **bag**, or sometimes called a [**multiset**](https://en.wikipedia.org/wiki/Multiset). Can you think of a representation for that?\n",
"\n",
- "**Well the easiest is just a sorted list or tuple—if we don't want order to matter, sorting takes care of that. Another choice would be a dictionary of {sum: count} entries, like {2: 1, 3: 2, ... 11: 2, 12: 1}. There is even a library class, `collections.Counter`, that does exactly that.**\n",
+ "**Bo: Well the easiest is just a sorted list or tuple—if we don't want order to matter, sorting takes care of that. Another choice would be a dictionary of {sum: count} entries, like {2: 1, 3: 2, ... 11: 2, 12: 1}. There is even a library class, `collections.Counter`, that does exactly that.**\n",
"\n",
- "How do we choose between the two representations?\n",
+ "Ali: How do we choose between the two representations?\n",
"\n",
- "**I don't think it matters much. Since there are only 36 entries, I think the sorted list will be simpler, and probably more efficient. For 100-sided dice I'd probably go with the Counter.**\n",
+ "**Bo: I don't think it matters much. Since there are only 36 entries, I think the sorted list will be simpler, and probably more efficient. For 100-sided dice I'd probably go with the Counter.**\n",
"\n",
- "OK, here's some code implementing `sums` as a sorted list, and definitions for regular die pair, and sums.\n",
- "By the way, I could have used `range(1, 7)` to define a regular die, but `range` is zero-based, and regular dice are one-based, so I defined the function `ints` instead."
+ "Ali: OK, here's some code for `Bag` and `sums`, and for regular dice:"
]
},
{
@@ -191,13 +190,13 @@
},
"outputs": [],
"source": [
+ "Bag = sorted # Implement a bag as a sorted list\n",
+ "\n",
"def sums(pair):\n",
" \"All possible sums of a side from one die plus a side from the other.\"\n",
" (A, B) = pair\n",
" return Bag(a + b for a in A for b in B)\n",
"\n",
- "Bag = sorted # Implement a bag as a sorted list\n",
- "\n",
"def ints(start, end): \n",
" \"A tuple of the integers from start to end, inclusive.\"\n",
" return tuple(range(start, end + 1))\n",
@@ -220,7 +219,7 @@
}
},
"source": [
- "Let's check the `regular_sums`:"
+ "Ali: Let's check the `regular_sums`:"
]
},
{
@@ -280,7 +279,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
- "**And we can see what that would look like to a `Counter`:**"
+ "**Bo: And we can see what that would look like to a `Counter`:**"
]
},
{
@@ -302,9 +301,9 @@
}
],
"source": [
- "from collections import Counter\n",
+ "import collections\n",
"\n",
- "Counter(regular_sums)"
+ "collections.Counter(regular_sums)"
]
},
{
@@ -318,45 +317,45 @@
}
},
"source": [
- "**Looks good! Now only one more thing on our TODO list:**\n",
+ "**Bo: Looks good! Now only one more thing on our TODO list:**\n",
"\n",
"# TO DO: `all_dice()`\n",
"\n",
"\n",
- "`all_dice` should generate all possible dice, where by \"possible\" I mean the dice that could feasibly be part of a pair that is a solution to the Sicherman problem. Do we know how many dice that will be? Is it a large enough number that efficiency will be a problem?\n",
+ "Ali: `all_dice` should generate all possible dice, where by \"possible\" I mean the dice that could feasibly be part of a pair that is a solution to the Sicherman problem. Do we know how many dice that will be? Is it a large enough number that efficiency will be a problem?\n",
"\n",
- "**Let's see. A die has six sides each. If each side can be a number from, say, 1 to 10, that's 106 or a million possible dice; a million is a small number for a computer.**\n",
+ "**Bo: Let's see. A die has six sides. If each side can be a number from, say, 1 to 10, that's 106 or a million possible dice; a million is a small number for a computer.**\n",
"\n",
- "True, a million is a relatively small number for `all_dice()`, but how many `pairs(all_dice())` will there be?\n",
+ "Ali: True, a million is a relatively small number for `all_dice()`, but how many `pairs(all_dice())` will there be?\n",
"\n",
- "**Ah. A million squared is a trillion. That's a large number even for a computer. Just counting to a trillion takes hours in Python; checking a trillion pairs will take days.**\n",
+ "**Bo: Ah. A million squared is a trillion. That's a large number even for a computer. Just counting to a trillion takes hours in Python; checking a trillion pairs will take days.**\n",
"\n",
- "So we need to get rid of most of the dice. What about permutations?\n",
+ "Ali: So we need to get rid of most of the dice. What about permutations?\n",
"\n",
- "**Good point. If I have the die (1, 2, 3, 4, 5, 6), then I don't need the 6! = 720 different permutations of this die— that is, dice like (2, 4, 6, 1, 3, 5).\n",
+ "**Bo: Good point. If I have the die (1, 2, 3, 4, 5, 6), then I don't need the 6! = 720 different permutations of this die— that is, dice like (2, 4, 6, 1, 3, 5).\n",
"Each die should be a bag (I learned a new word!) of sides. So we've already eliminated 719/720 = 99.9% of the work.**\n",
"\n",
- "One other thing bothers me ... how do you know that the sides can range from 1 to 10? Are you sure that 11 can't be part of a solution? Or 12?\n",
+ "Ali: One other thing bothers me ... how do you know that the sides can range from 1 to 10? Are you sure that 11 can't be part of a solution? Or 12?\n",
"\n",
- "**Every side on every die must be a positive integer, right?**\n",
+ "**Bo: Every side on every die must be a positive integer, right?**\n",
"\n",
- "Right. No zeroes, no negative numbers, no fractions.\n",
+ "Ali: Right. No zeroes, no negative numbers, no fractions.\n",
"\n",
- "**Then I know for sure that 12 can't be on any die, because when you add 12 to whatever is on the other die, you would get at least 13, and 13 is not allowed in the regular distribution of sums.**\n",
+ "**Bo: Then I know for sure that 12 can't be on any die, because when you add 12 to whatever is on the other die, you would get at least 13, and 13 is not allowed in the regular distribution of sums.**\n",
"\n",
- "Good. How about 11?\n",
+ "Ali: Good. How about 11?\n",
"\n",
- "**We can't have a sum that is bigger than 12. So if one die had an 11, the other would have to have all 1s. That wouldn't work, because then we'd have six 12s, but we only want one. So 10 is the biggest allowable number on a die.**\n",
+ "**Bo: We can't have a sum that is bigger than 12. So if one die had an 11, the other would have to have all 1s. That wouldn't work, because then we'd have six 12s, but we only want one. So no side can have a number bigger than 10.**\n",
"\n",
- "What else can we say about the biggest number on a die?\n",
+ "Ali: What else can we say about the biggest number on a die?\n",
"\n",
- "**There's one 12 in the sums. But there are several ways to make a 12: 6+6 or 7+5 or 8+4, and so on. So I can't say for sure what the biggest number on any one die will be. But I can say that whatever the biggest number on a die is, it will be involved in summing to 12, so there can be only one of them, because we only want to make one 12.**\n",
+ "**Bo: There's one 12 in the sums. But there are several ways to make a 12: 6+6 or 7+5 or 8+4, and so on. So I can't say for sure what the biggest number on any one die will be. But I can say that whatever the biggest number on a die is, it will be involved in summing to 12, so there can be only one of them, because we only want to make one 12.**\n",
"\n",
- "What about the smallest number on a die?\n",
+ "Ali: What about the smallest number on a die?\n",
"\n",
- "**Well, there's only one 2 allowed in the sums. The only way to sum to 2 is 1+1: a 1 from each of the dice in the pair. If a die had no 1s, we wouldn't get a 2; if a die had more than one 1, we would get too many 2s. So every die has to have exactly one 1.**\n",
+ "**Bo: Well, there's only one 2 allowed in the sums. The only way to sum to 2 is 1+1: a 1 from each of the dice in the pair. If a die had no 1s, we wouldn't get a 2; if a die had more than one 1, we would get too many 2s. So every die has to have exactly one 1.**\n",
"\n",
- "Good. So each die has exactly one 1, and exactly one of whatever the biggest number is, something in the range up to 10. Here's a picture of the six sides of any one die:\n",
+ "Ali: Good. So each die has exactly one 1, and exactly one of whatever the biggest number is, something in the range up to 10. Here's a picture of the six sides of any one die:\n",
"\n",
" 1 <\n",
"2-10 ≤\n",
@@ -365,9 +364,9 @@
"2-10 <\n",
"2-10\n",
"\n",
- "The bag of sides is always listed in non-decreasing order; the first side, 1, is less than the next, and the last side, whatever it is, is greater than the one before it.\n",
+ "Ali: The bag of sides is always listed in non-decreasing order; the first side, 1, is less than the next, and the last side, whatever it is, is greater than the one before it.\n",
"\n",
- "**Wait a minute: you have [2-10] < [2-10]. But 2 is not less than 2, and 10 is not less than 10. I think it should be [2-9] < [3-10]. So the picture should be like this:**\n",
+ "**Bo: Wait a minute: you have [2-10] < [2-10]. But 2 is not less than 2, and 10 is not less than 10. I think it should be [2-9] < [3-10]. So the picture should be like this:**\n",
"\n",
"\n",
" 1 <\n",
@@ -377,7 +376,7 @@
"2-9 <\n",
"3-10\n",
"\n",
- "Good! We're making progress in cutting down the range. But it bothers me because it says the range for the biggest number is 3 to 10. But if one die has a 3 and the other a 10, that adds to 13. So I'm thinking that it is not possible to have a 10 after all—because if one die had a 10, then the other would have to have a 2 as the biggest number, and that can't be. Therefore the biggest number is in the range of 3 to 9. But then the others have to be \n",
+ "Ali: Good! We're making progress in cutting down the range. But it That this bothers me because it says the range for the biggest number is 3 to 10. But if one die has a 3 and the other a 10, that adds to 13. So I'm thinking that it is not possible to have a 10 after all—because if one die had a 10, then the other would have to have a 2 as the biggest number, and that can't be. Therefore the biggest number is in the range of 3 to 9. But then the others have to be \n",
"less, so make them 2 to 8:\n",
"\n",
" 1 <\n",
@@ -387,7 +386,7 @@
"2-8 <\n",
"3-9\n",
"\n",
- "**I can turn this picture into code:**"
+ "**Bo: I can turn this picture into code, and we can see how many dice there are:**"
]
},
{
@@ -402,7 +401,18 @@
"read_only": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "462"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"def all_dice():\n",
" \"A list of all feasible 6-sided dice for the Sicherman problem.\"\n",
@@ -411,7 +421,9 @@
" for s3 in ints(s2, 8)\n",
" for s4 in ints(s3, 8)\n",
" for s5 in ints(s4, 8) \n",
- " for s6 in ints(s5+1, 9)]"
+ " for s6 in ints(s5+1, 9)]\n",
+ "\n",
+ "len(all_dice())"
]
},
{
@@ -425,11 +437,11 @@
}
},
"source": [
- "I think we're ready to run `sicherman()`. Any bets on what we'll find out?\n",
+ "Ali: Nice! We got down from a million to 462 different dice. I think we're ready to run `sicherman()`. Any bets on what we'll find out?\n",
"\n",
- "**I bet that Sicherman is remembered because he discovered a pair of dice that works. If he just proved the non-existence of a pair, I don't think that would be noteworthy.**\n",
+ "**Bo: I bet that Sicherman is remembered because he discovered a pair of dice that works. If he just proved the non-existence of a pair, I don't think that would be noteworthy.**\n",
"\n",
- "Makes sense. Here goes:\n",
+ "Ali: Makes sense. Here goes:\n",
"\n",
"# The Answer"
]
@@ -473,28 +485,24 @@
}
},
"source": [
- "**Look at that!**\n",
+ "**Bo: Look at that!**\n",
"\n",
- "It turns out you can buy a pair of dice with just these numbers.\n",
- "\n",
- "
\n",
- "\n",
- "Here's a table I borrowed from [Wikipedia](https://en.wikipedia.org/wiki/Sicherman_dice) that shows both pairs of dice have the same sums. \n",
+ "Ali: It turns out you can buy a pair of dice with just these numbers. Here's a table I borrowed from [Wikipedia](https://en.wikipedia.org/wiki/Sicherman_dice) that shows both pairs of dice have the same sums. \n",
"\n",
"
\n",
"\n",
- " | \n",
- "2 | \n",
- "3 | \n",
- "4 | \n",
- "5 | \n",
- "6 | \n",
- "7 | \n",
- "8 | \n",
- "9 | \n",
- "10 | \n",
- "11 | \n",
- "12 | \n",
+ " | \n",
+ "2 | \n",
+ "3 | \n",
+ "4 | \n",
+ "5 | \n",
+ "6 | \n",
+ "7 | \n",
+ "8 | \n",
+ "9 | \n",
+ "10 | \n",
+ "11 | \n",
+ "12 | \n",
"
\n",
"\n",
"Regular dice:\n",
@@ -580,7 +588,8 @@
" |
\n",
"
\n",
"\n",
- "We could stop here. Or we could try to solve it for *N*-sided dice.\n",
+ "\n",
+ "Ali: We could stop here. Or we could try to solve it for *N*-sided dice.\n",
"\n",
"# Why stop now? Onward!"
]
@@ -596,9 +605,9 @@
}
},
"source": [
- "OK. I know 4-, 12-, and 20-sided dice are common, but we'll try to handle any *N* > 1. My guess is we won't go too far before our program becomes too slow. So, before we try *N*-sided dice, let's analyze six-sided dice a little better, to see if we can eliminate some of the pairs before we start. The picture says that (1, 2, 2, 2, 2, 3) could be a valid die. Could it?\n",
+ "Ali: OK. I know 4-, 12-, and 20-sided dice are common, but we'll try to handle any *N* > 1. My guess is we won't go too far before our program becomes too slow. So, before we try *N*-sided dice, let's analyze six-sided dice a little better, to see if we can eliminate some of the pairs before we start. The picture says that (1, 2, 2, 2, 2, 3) could be a valid die. Could it?\n",
"\n",
- "**No! If a die had four 2s, then we know that since the other die has one 1, we could make 2 + 1 = 3 four ways. But the `regular_sums` has only two 3s. So that means that a die can have no more than two 2s. New picture:**\n",
+ "**Bo: No! If a die had four 2s, then we know that since the other die has one 1, we could make 2 + 1 = 3 four ways. But the `regular_sums` has only two 3s. So that means that a die can have no more than two 2s. New picture:**\n",
"\n",
" 1 <\n",
"2-8 ≤\n",
@@ -607,14 +616,16 @@
"3-8 <\n",
"3-9\n",
"\n",
- "Now we've got [3-8] < [3-9]; that's not right. If a die can only have one 1 and two 2s, then it must have at least one number that is a 3 or more, followed by the biggest number, which must be 4 or more, and we know a pair of biggest numbers must sum to 12, so the range of the biggest can't be [4-9], it must be [4-8]:\n",
+ "Ali: Now we've got [3-8] < [3-9]; that's not right. If a die can only have one 1 and two 2s, then it must have at least one number that is a 3 or more, followed by the biggest number, which must be 4 or more, and we know a pair of biggest numbers must sum to 12, so the range of the biggest can't be [4-9], it must be [4-8]:\n",
"\n",
" 1 <\n",
"2-7 ≤\n",
"2-7 ≤\n",
"3-7 ≤\n",
"3-7 <\n",
- "4-8"
+ "4-8\n",
+ "\n",
+ "We can update the code and count again:"
]
},
{
@@ -622,14 +633,25 @@
"execution_count": 10,
"metadata": {
"button": false,
- "collapsed": true,
+ "collapsed": false,
"deletable": true,
"new_sheet": false,
"run_control": {
"read_only": false
}
},
- "outputs": [],
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "231"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
"source": [
"def all_dice():\n",
" \"A list of all feasible 6-sided dice for the Sicherman problem.\"\n",
@@ -638,7 +660,9 @@
" for s3 in ints(s2, 7)\n",
" for s4 in ints(max(s3, 3), 7)\n",
" for s5 in ints(s4, 7) \n",
- " for s6 in ints(s5+1, 8)]"
+ " for s6 in ints(s5+1, 8)]\n",
+ "\n",
+ "len(all_dice())"
]
},
{
@@ -652,7 +676,7 @@
}
},
"source": [
- "I'll count how many dice and how many pairs there are now:"
+ "**Bo: Nice—we cut the number of dice in half. I don't want to print `all_dice()`, but I can sample a few:**"
]
},
{
@@ -671,7 +695,16 @@
{
"data": {
"text/plain": [
- "231"
+ "[(1, 2, 3, 3, 5, 7),\n",
+ " (1, 2, 2, 5, 6, 7),\n",
+ " (1, 4, 4, 5, 7, 8),\n",
+ " (1, 3, 3, 6, 6, 8),\n",
+ " (1, 4, 4, 4, 4, 5),\n",
+ " (1, 4, 5, 5, 7, 8),\n",
+ " (1, 2, 3, 6, 6, 8),\n",
+ " (1, 2, 2, 3, 6, 8),\n",
+ " (1, 3, 4, 5, 7, 8),\n",
+ " (1, 6, 6, 6, 6, 7)]"
]
},
"execution_count": 11,
@@ -679,85 +712,6 @@
"output_type": "execute_result"
}
],
- "source": [
- "len(all_dice())"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 12,
- "metadata": {
- "button": false,
- "collapsed": false,
- "deletable": true,
- "new_sheet": false,
- "run_control": {
- "read_only": false
- }
- },
- "outputs": [
- {
- "data": {
- "text/plain": [
- "26796"
- ]
- },
- "execution_count": 12,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "len(pairs(all_dice()))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "button": false,
- "deletable": true,
- "new_sheet": false,
- "run_control": {
- "read_only": false
- }
- },
- "source": [
- "**Nice—we got down from a trillion pairs to 26,000. I don't want to print `all_dice()`, but I can sample a few:**"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 13,
- "metadata": {
- "button": false,
- "collapsed": false,
- "deletable": true,
- "new_sheet": false,
- "run_control": {
- "read_only": false
- }
- },
- "outputs": [
- {
- "data": {
- "text/plain": [
- "[(1, 5, 5, 5, 7, 8),\n",
- " (1, 6, 6, 6, 7, 8),\n",
- " (1, 3, 4, 6, 6, 7),\n",
- " (1, 3, 3, 7, 7, 8),\n",
- " (1, 3, 5, 5, 6, 8),\n",
- " (1, 2, 2, 4, 4, 5),\n",
- " (1, 2, 5, 6, 7, 8),\n",
- " (1, 3, 4, 4, 4, 8),\n",
- " (1, 2, 3, 5, 5, 6),\n",
- " (1, 2, 2, 3, 3, 8)]"
- ]
- },
- "execution_count": 13,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
"source": [
"import random\n",
"\n",
@@ -777,14 +731,14 @@
"source": [
"# `sicherman(N)`\n",
"\n",
- "OK, I think we're ready to update `sicherman()` to `sicherman(N)`. \n",
+ "Ali: OK, I think we're ready to update `sicherman()` to `sicherman(N)`. \n",
"\n",
- "**Sure, most of that will be easy, just parameterizing with `N`:**"
+ "**Bo: Sure, most of that will be easy, just parameterizing with `N`:**"
]
},
{
"cell_type": "code",
- "execution_count": 14,
+ "execution_count": 12,
"metadata": {
"button": false,
"collapsed": false,
@@ -823,12 +777,12 @@
}
},
"source": [
- "Good. I think it would be helpful for me to look at a table of `regular_sums`:"
+ "Ali: Good. I think it would be helpful to look at a table of `regular_sums`:"
]
},
{
"cell_type": "code",
- "execution_count": 15,
+ "execution_count": 13,
"metadata": {
"button": false,
"collapsed": false,
@@ -855,7 +809,7 @@
],
"source": [
"for N in ints(1, 7):\n",
- " print(\"N:\", N, dict(Counter(regular_sums(N))))"
+ " print(\"N:\", N, dict(collections.Counter(regular_sums(N))))"
]
},
{
@@ -869,7 +823,7 @@
}
},
"source": [
- "**That is helpful. I can see that any `regular_sums` must have one 2 and two 3s, and three 4s, and so on, not just for `N=6` but for any `N` (except for trivially small `N`). And that means that any regular die can have at most two 2s, three 3s, four 4s, and so on. So we have this picture:**\n",
+ "**Bo: That is helpful. I can see that any `regular_sums` must have one 2 and two 3s, and three 4s, and so on, not just for `N=6` but for any `N` (except for trivially small `N`). And that means that any regular die can have at most two 2s, three 3s, four 4s, and so on. So we have this picture:**\n",
"\n",
" 1 <\n",
"2+ ≤\n",
@@ -884,9 +838,9 @@
"\n",
"**where [2+] means the lower bound is 2, but we haven't figured out yet what the upper bound is.**\n",
"\n",
- "Let's figure out upper bounds starting from the biggest number. What can the biggest number be?\n",
+ "Ali: Let's figure out upper bounds starting from the biggest number. What can the biggest number be?\n",
"\n",
- "**For a pair of *N*-sided die, the biggest sides from each one must add up to 2*N*. Let's take *N*=10 as an example. The biggest numbers on two 10-sided Sicherman dice must sum to 20. According to the picture above, the lower bound on the biggest number would be 4, but because there can only be one of the biggest number, the lower bound is 5. So to add up to 20, the range must be [5-15]:**\n",
+ "**Bo: For a pair of *N*-sided die, the biggest sides from each one must add up to 2*N*. Let's take *N*=10 as an example. The biggest numbers on two 10-sided Sicherman dice must sum to 20. According to the picture above, the lower bound on the biggest number would be 4, but because there can only be one of the biggest number, the lower bound is 5. So to add up to 20, the range must be [5-15]:**\n",
"\n",
"\n",
" 1 <\n",
@@ -900,7 +854,7 @@
"4+ <\n",
"5-15 \n",
"\n",
- "There's probably some tricky argument for the upper bounds of the other sides, but I'm just going to say the upper bound is one less than the upper bound of the biggest number:\n",
+ "Ali: There's probably some tricky argument for the upper bounds of the other sides, but I'm just going to say the upper bound is one less than the upper bound of the biggest number:\n",
"\n",
" 1 <\n",
"2-14 ≤\n",
@@ -919,7 +873,7 @@
},
{
"cell_type": "code",
- "execution_count": 16,
+ "execution_count": 14,
"metadata": {
"button": false,
"collapsed": true,
@@ -943,7 +897,7 @@
},
{
"cell_type": "code",
- "execution_count": 17,
+ "execution_count": 15,
"metadata": {
"button": false,
"collapsed": false,
@@ -960,7 +914,7 @@
"[1, 2, 2, 3, 3, 4]"
]
},
- "execution_count": 17,
+ "execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
@@ -971,7 +925,7 @@
},
{
"cell_type": "code",
- "execution_count": 18,
+ "execution_count": 16,
"metadata": {
"button": false,
"collapsed": false,
@@ -988,7 +942,7 @@
"[1, 2, 2, 3, 3, 3, 4, 4, 4, 5]"
]
},
- "execution_count": 18,
+ "execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
@@ -1008,12 +962,12 @@
}
},
"source": [
- "And `upper_bounds(N)`:"
+ "Ali: And `upper_bounds(N)`:"
]
},
{
"cell_type": "code",
- "execution_count": 19,
+ "execution_count": 17,
"metadata": {
"button": false,
"collapsed": true,
@@ -1033,7 +987,7 @@
},
{
"cell_type": "code",
- "execution_count": 20,
+ "execution_count": 18,
"metadata": {
"button": false,
"collapsed": false,
@@ -1050,7 +1004,7 @@
"[1, 7, 7, 7, 7, 8]"
]
},
- "execution_count": 20,
+ "execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
@@ -1061,7 +1015,7 @@
},
{
"cell_type": "code",
- "execution_count": 21,
+ "execution_count": 19,
"metadata": {
"button": false,
"collapsed": false,
@@ -1078,7 +1032,7 @@
"[1, 14, 14, 14, 14, 14, 14, 14, 14, 15]"
]
},
- "execution_count": 21,
+ "execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
@@ -1098,9 +1052,9 @@
}
},
"source": [
- "Now, what do we have to do for `all_dice(N)`? When we knew we had six sides, we wrote six nested loops. We can't do that for *N*, so what do we do?\n",
+ "Ali: Now, what do we have to do for `all_dice(N)`? When we knew we had six sides, we wrote six nested loops. We can't do that for *N* sides, so what do we do?\n",
"\n",
- "**Here's an iterative approach: we keep track of a list of partially-formed dice, and on each iteration, we add a side to all the partially-formed dice in all possible ways, until the dice all have `N` sides. So for example, we'd start with:**\n",
+ "**Bo: Here's an iterative approach: we keep track of a list of partially-formed dice, and on each iteration, we add a side to all the partially-formed dice in all possible ways, until the dice all have `N` sides. So for eaxmple, we'd start with:**\n",
"\n",
" dice = [(1,)]\n",
" \n",
@@ -1113,7 +1067,7 @@
},
{
"cell_type": "code",
- "execution_count": 22,
+ "execution_count": 20,
"metadata": {
"button": false,
"collapsed": false,
@@ -1152,14 +1106,14 @@
}
},
"source": [
- "**The tricky part was with the `max`: the actual lower bound at least `lowers[i]`, but it must be as big as the previous side, `die[-1]`. And just to make things complicated, the very last side has to be strictly bigger than the previous; `\" + int(i == N-1)\"` does that by adding 1 just in case we're on the last side, and 0 otherwise.**\n",
+ "**Bo: The tricky part was with the `max`: the actual lower bound at least `lowers[i]`, but it must be as big as the previous side, `die[-1]`. And just to make things complicated, the very last side has to be strictly bigger than the previous; `\" + int(i == N-1)\"` does that by adding 1 just in case we're on the last side, and 0 otherwise.**\n",
"\n",
"**Let's check it out:**"
]
},
{
"cell_type": "code",
- "execution_count": 23,
+ "execution_count": 21,
"metadata": {
"button": false,
"collapsed": false,
@@ -1176,7 +1130,7 @@
"231"
]
},
- "execution_count": 23,
+ "execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
@@ -1196,12 +1150,12 @@
}
},
"source": [
- "Reassuring that we get the same number we got with the old version of `all_dice()`."
+ "Ali: Reassuring that we get the same number we got with the old version of `all_dice()`."
]
},
{
"cell_type": "code",
- "execution_count": 24,
+ "execution_count": 22,
"metadata": {
"button": false,
"collapsed": false,
@@ -1215,17 +1169,17 @@
{
"data": {
"text/plain": [
- "[(1, 2, 2, 3, 4, 6),\n",
- " (1, 3, 5, 5, 6, 8),\n",
- " (1, 3, 3, 6, 7, 8),\n",
- " (1, 2, 3, 3, 3, 7),\n",
- " (1, 3, 5, 5, 7, 8),\n",
- " (1, 2, 4, 5, 6, 8),\n",
+ "[(1, 4, 5, 5, 7, 8),\n",
+ " (1, 4, 4, 5, 6, 8),\n",
+ " (1, 2, 6, 6, 6, 7),\n",
" (1, 3, 6, 6, 7, 8),\n",
+ " (1, 2, 2, 3, 6, 7),\n",
+ " (1, 2, 2, 3, 6, 8),\n",
+ " (1, 3, 3, 3, 3, 6),\n",
" (1, 3, 4, 5, 5, 7)]"
]
},
- "execution_count": 24,
+ "execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
@@ -1247,12 +1201,12 @@
"source": [
"# Running `sicherman(N)` for small `N`\n",
"\n",
- "Let's try `sicherman` for some small values of `N`:"
+ "Ali: Let's try `sicherman(N)` for some small values of `N`:"
]
},
{
"cell_type": "code",
- "execution_count": 25,
+ "execution_count": 23,
"metadata": {
"button": false,
"collapsed": false,
@@ -1273,7 +1227,7 @@
" 6: {((1, 2, 2, 3, 3, 4), (1, 3, 4, 5, 6, 8))}}"
]
},
- "execution_count": 25,
+ "execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
@@ -1301,7 +1255,7 @@
},
{
"cell_type": "code",
- "execution_count": 26,
+ "execution_count": 24,
"metadata": {
"button": false,
"collapsed": false,
@@ -1316,8 +1270,8 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "CPU times: user 304 ms, sys: 2.73 ms, total: 307 ms\n",
- "Wall time: 519 ms\n"
+ "CPU times: user 277 ms, sys: 9.04 ms, total: 286 ms\n",
+ "Wall time: 344 ms\n"
]
},
{
@@ -1326,7 +1280,7 @@
"{((1, 2, 2, 3, 3, 4), (1, 3, 4, 5, 6, 8))}"
]
},
- "execution_count": 26,
+ "execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
@@ -1337,7 +1291,7 @@
},
{
"cell_type": "code",
- "execution_count": 27,
+ "execution_count": 25,
"metadata": {
"button": false,
"collapsed": false,
@@ -1352,8 +1306,8 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "CPU times: user 18.2 s, sys: 209 ms, total: 18.4 s\n",
- "Wall time: 21.4 s\n"
+ "CPU times: user 14.4 s, sys: 303 ms, total: 14.7 s\n",
+ "Wall time: 16.1 s\n"
]
},
{
@@ -1362,7 +1316,7 @@
"set()"
]
},
- "execution_count": 27,
+ "execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
@@ -1384,15 +1338,15 @@
"source": [
"# Estimating run time of `sicherman(N)` for larger `N`\n",
"\n",
- "OK, it takes 50 or 60 times longer to do 7, compared to 6. At this rate, *N*=8 will take 15 minutes, 9 will take 15 hours, and 10 will take a month.\n",
+ "Ali: OK, it takes 50 times longer to do 7, compared to 6. At that rate, *N*=8 will take 15 minutes, 9 will take 15 hours, and 10 will take a month.\n",
"\n",
- "**Do we know it will continue to rise at the same rate? You're saying the run time is exponential in *N*? **\n",
+ "**Bo: Do we know it will continue to rise at the same rate? You're saying the run time is exponential in *N*? **\n",
"\n",
- "I think so. The run time is proportional to the number of pairs. The number of pairs is proportional to the square of the number of dice. The number of dice is roughly exponential in *N*, because each time you increase *N* by 1, you have to try a number of new sides that is similar to the number for the previous side (but not quite the same). I should plot the number of pairs on a log scale and see if it looks like a straight line.\n",
+ "Ali: I think so. The run time is proportional to the number of pairs. The number of pairs is proportional to the square of the number of dice. The number of dice is roughly exponential in *N*, because each time you increase *N* by 1, you have to try a number of new sides that is similar to the number for the previous side (but not quite the same). I should plot the number of pairs on a log scale and see if it looks like a straight line.\n",
"\n",
"I can count the number of pairs without explicitly generating the pairs. If there are *D* dice, then the number of pairs is what? Something like *D* × (*D* + 1) / 2? Or is it *D* × (*D* - 1) / 2?\n",
"\n",
- "**Let's draw a picture. With *D* = 4, here are all the ways to pair one die with another to yield 10 distinct pairs:**\n",
+ "**Bo: Let's draw a picture. With *D* = 4, here are all the ways to pair one die with another to yield 10 distinct pairs:**\n",
" \n",
" 11 .. .. ..\n",
" 21 22 .. ..\n",
@@ -1409,12 +1363,12 @@
" \n",
"**Now we have a *D* × (*D* + 1) rectangle, and we can see that half (10) of them are pairs, and half (the other 10) are not pairs (because they would be repetitions). So the formula is *D* × (*D* + 1)/2, and checking for *D*=4, (4 × 5) / 2 = 10, so we're good.**\n",
" \n",
- "OK, let's try it. First some boilerplate for plotting:"
+ "Ali: OK, let's try it. First some boilerplate for plotting:"
]
},
{
"cell_type": "code",
- "execution_count": 28,
+ "execution_count": 26,
"metadata": {
"button": false,
"collapsed": false,
@@ -1455,7 +1409,7 @@
},
{
"cell_type": "code",
- "execution_count": 29,
+ "execution_count": 27,
"metadata": {
"button": false,
"collapsed": false,
@@ -1482,15 +1436,15 @@
" 12: 25925418283128}"
]
},
- "execution_count": 29,
+ "execution_count": 27,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
- "image/png": "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\nYII=\n",
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAX4AAAD8CAYAAABw1c+bAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAHWxJREFUeJzt3Xl0leW59/HvBQgaZ5E6gCRYkRJbWzTiPNcKiuBUS4yW\nKkukFhWPExzO0XpceChYlxMLCIJTA4i8eF5EnI68Fj0MEhwQxIEihCCaIFZRZAhc7x93OMSQSIa9\n97P3fn6ftVzhufcOz7XXwl/u3M89mLsjIiLx0SLqAkREJLUU/CIiMaPgFxGJGQW/iEjMKPhFRGJG\nwS8iEjMKfhGRmFHwi4jEjIJfRCRmWkVdQF0OPvhgz8vLi7oMEZGMsmjRonXu3m5370vL4M/Ly6O0\ntDTqMkREMoqZrWrI+zTUIyISMwp+EZGYUfCLiMSMgl9EJGYU/CIiMaPgFxFJAyUlkJcHLVqEryUl\nybtXWk7nFBGJk5ISGDAANm4M16tWhWuAoqLE3089fhGRiA0btjP0d9i4MbQng4JfRCRiZWWNa28u\nBb+ISETWroVrrgH3ul/v2DE591Xwi4ik2KZNcN990LkzTJoEvXrBXnv98D05OTB8eHLun/DgN7Mj\nzWyCmU2r0dbVzMaa2TQz+2Oi7ykikgncYdo06No1jN+fdx588AE8/zyMHw+5uWAWvhYXJ+fBLjQw\n+M1soplVmNmSWu09zOwjM1tuZkMA3H2Fu/ev+T53X+buA4ErgFMTVbyISKZ49104+2z47W9h333h\ntdfguefgpz8NrxcVwcqVsH17+Jqs0IeG9/ifAHrUbDCzlsBooCeQDxSaWX59f4GZ9QZeAGY1qVIR\nkQxUURGmZh53HCxdCmPGwNtvwznnRFdTg4Lf3ecA62s1dweWV/fwtwBTgD4/8nfMcPeeQJ0/x8xs\ngJmVmllpZWVlw6oXEUlTW7bA/feHcfzHH4fBg+GTT2DgQGgV8Qqq5ozxtwdW17guB9qbWVszGwt0\nM7OhAGZ2lpk9bGbjqKfH7+7F7l7g7gXt2u32HAERkbTkDjNmwDHHwO23w+mnw5Il8MADcMABUVcX\nJPznjrt/CQys1fY68Hqi7yUikk6WLIFbboH//u/wAPell+D886OualfN6fGvAY6ocd2huk1EJFbW\nrYM//Ql++UtYtAgefhjeey89Qx+aF/wLgc5m1snMWgN9gRmJKUtEJP1t3QoPPRTG8ceNgxtuCOP4\nN94Ie+wRdXX1a+h0zsnAPKCLmZWbWX93rwIGAS8Dy4Cp7r40eaWKiKSPF1+EY48ND227dw89/Ece\ngbZto65s9xo0xu/uhfW0z0LTM0UkRj78EP7lX0Lwd+4cFl9deGFYeJUptGWDiEgDfPVV6N3/4hcw\ndy789a/hYW6vXpkV+qD9+EVEflRVVdg+4a67Qvhfdx3cey9k8qxz9fhFRGqoeRLWIYdAp05hxs6x\nx8I778DYsZkd+qAev4jI/6p9ElZFRRjGGTw4LMDKtCGd+qjHLyJSra6TsNzDZmrZEvqg4BcRAWDz\n5nDWbV2SdRJWVBT8IhJ7n30GZ51V/+vJOgkrKgp+EYm1uXPh+OPh/ffhppvCyVc1JfMkrKgo+EUk\ntsaNCz39vfeG+fPD9gvFxak7CSsqmtUjIrGzeXPYT2f8eOjRI5x7e+CB4bWiouwL+trU4xeRWNkx\nnj9+PAwdCjNn7gz9uFCPX0RiY+5cuOwy2LABnn0WLr886oqioR6/iMRC7fH8uIY+KPhFJMtt3hxW\n4w4cCOeeCwsXws9/HnVV0VLwi0jW0nh+3TTGLyJZSeP59VOPX0Syjsbzf5yCX0SyhsbzG0bBLyJZ\n4bPP4OyzNZ7fEAkf4zezI4FhwP7ufnl9bSIiiaLx/MZpUI/fzCaaWYWZLanV3sPMPjKz5WY2BMDd\nV7h7/5rvq6tNRCQRios1nt9YDR3qeQLoUbPBzFoCo4GeQD5QaGb5Ca1ORKQeO8bzr79e4/mN1aDg\nd/c5wPpazd2B5dW9+S3AFKBPgusTEdmFxvObpzkPd9sDq2tclwPtzaytmY0FupnZUIC62mozswFm\nVmpmpZWVlc0oS0Sy2Y798xcvDuP5990HLVtGXVVmSfjDXXf/Ehi4u7Y6vq8YKAYoKCjwRNclIpmv\nuBgGDQonYr36qoZ2mqo5Pf41wBE1rjtUt4mIJJTG8xOrOcG/EOhsZp3MrDXQF5iRmLJEJM5KSiAv\nD1q0gA4dQshrPD9xGjTUY2aTgbOAg82sHLjb3SeY2SDgZaAlMNHdlyatUhGJhZKS0LvfuDFcr6ke\nR7jppjCeL81n7uk3nF5QUOClpaVRlyEiEcjLg1Wrdm3PzYWVK1NdTWYxs0XuXrC792nLBhFJK2Vl\njWuXxlPwi0jaWLsWWreu+7WOHVNbSzZT8ItIWliwAAoKYPv2XcM/JweGD4+mrmyk4BeRyE2cCGec\nAW3aQGlpuM7NBbPwtbgYioqirjJ76AQuEYnM1q1wyy0wejScdx5MmQIHHQTHHqugTyb1+EUkEhUV\nYTHW6NFw220wa1YIfUk+9fhFJOVKS+GSS+DLL2HSJCgsjLqieFGPX0RS6qmn4LTTwsZqc+cq9KOg\n4BeRlNi6FQYPhn794JRTQq//V7+Kuqp4UvCLSNJVVsL558NDD4Xwf+UVOPjgqKuKL43xi0hSvfNO\nGM///PMwzHP11VFXJOrxi0jSTJ4Mp54K27bBm28q9NOFgl9EEq6qCm6/Ha68Ek44ARYtCqtyJT1o\nqEdEEmr9eujbN5yQNWgQPPAA7LFH1FVJTQp+EUmYxYvh4ovDHvoTJ8I110RdkdRFQz0ikhDPPgsn\nnxyOSZwzR6GfzhT8ItIs27aFIxGvuCLMy1+0CE48Meqq5MdoqEdEmuyrr8ID3JdeCgehP/xw/fvp\nS/pQ8ItIkyxdGsbzV62CcePCObmSGRT8ItJo06eHrRf22Qdefz1swSCZIyVj/GaWb2ZTzWyMmV2e\ninuKSOJt3w533QWXXQbHHBPG8xX6mafJwW9mE82swsyW1GrvYWYfmdlyMxtS3dwTeMTd/wj8vhn1\nikhEvv4a+vSBe++Fa6+Fv/8dDj886qqkKZrT438C6FGzwcxaAqMJQZ8PFJpZPvA00NfMRgFtm3FP\nEUmhkhLIy4MWLcKmai+8EA5OeeyxcEyiZKYmB7+7zwHW12ruDix39xXuvgWYAvRx9wp3/xMwBFhX\n199nZgPMrNTMSisrK5talogkSElJeGC7ahW4h20YWreG/fcPZ+FK5kr0GH97YHWN63KgvZnlmVkx\n8BQwqq5vdPdidy9w94J27doluCwRaax//VfYuPGHbZs3w7Bh0dQjiZOSWT3uvhLQZC+RDPHtt1BW\nVvdr9bVL5kh0j38NcESN6w7VbSKSIVas+PGZOh07pq4WSY5EB/9CoLOZdTKz1kBfYEaC7yEiSfLa\na2Eb5fJyuPNOyMn54es5OTB8eDS1SeI0ZzrnZGAe0MXMys2sv7tXAYOAl4FlwFR3X5qYUkUkWdzh\nwQfD8YiHHQYLF8KIEVBcDLm54WFubm64LiqKulppLnP3qGvYRUFBgZeWlkZdhkgsbNoEAwfCk0+G\nIxKffBL23TfqqqQpzGyRu+/2yBvtzikSY2vWwJlnhrC/5x6YNk2hHwfaq0ckpubODVsvfPstPPdc\n2HBN4kE9fpEYeuwxOOss2HtvmD9foR83Cn6RGNm6NZyDe911cPbZ8NZbYbM1iRcFv0hMVFbCeeeF\nvXZuuy3su3PQQVFXJVHQGL9IDLz7bthZs6IC/vY3TcmMO/X4RbLcM8+Elbjbt8Obbyr0RcEvkrV2\nHILety8cdxyUlsLxx0ddlaQDDfWIZKF//jMcgv7iizoEXXal4BfJMh9+GMbzV6yAMWPCqlyRmhT8\nIllk5swwht+mDcyeDaefHnVFko40xi+SBdzDrpm9e8NRR4VD0BX6Uh/1+EUy3LffwjXXhH12iopg\n/HjYa6+oq5J0puAXyWCffhq2W1iyBEaNgltv1Xm4snsKfpEMNXs2XHFFmLY5a1bYS1+kITTGL5Jh\n3MP0zN/8Bg45JByaotCXxlDwi6S5khLIy4MWLcJ5t2eeCTffDL16hZ01jzoq6gol02ioRySNlZTA\ngAGwcWO4Xr06/HfJJeFhbgt13aQJ9M9GJI0NG7Yz9Gt6+22FvjRdSnr8ZnY6UFR9v3x3PyUV9xXJ\ndGVljWsXaYgm9xnMbKKZVZjZklrtPczsIzNbbmZDANz9DXcfCMwEnmxeySLZr7w8zM13r/v1jh1T\nW49kl+b8svgE0KNmg5m1BEYDPYF8oNDM8mu85UpgUjPuKZLVvvkmDO8cfTRMmgQXXLDrYqycnLBK\nV6Spmhz87j4HWF+ruTuw3N1XuPsWYArQB8DMOgJfu/uGpt5TJFtt3RpOxjrqKLjvvvDw9qOPwilZ\n48dDbm5YmJWbC8XF2lNfmifRY/ztgdU1rsuBE6v/3B94vL5vNLMBwACAjvo9VmLCHf7rv2DIEPj4\n43AA+qhRUFCw8z1FRQp6SayUzQtw97vdfe6PvF7s7gXuXtCuXbtUlSUSmfnz4Ywz4NJLoWVLeP75\nsBq3ZuiLJEOig38NcESN6w7VbSJS7R//CFstnHwyfPIJjBsHixeHBVnaZ0dSIdHBvxDobGadzKw1\n0BeYkeB7iGSkL7+EwYOha9cwdn/33bB8eVig1UpLKSWFmjOdczIwD+hiZuVm1t/dq4BBwMvAMmCq\nuy9NTKkimWnTJhg5En76U3jkEejXL/T0//xn2GefqKuTOGpyP8PdC+tpnwXManJFIlli+/YwJXPY\nsLDg6oILwg+AY46JujKJOy36FkmC2bPhhBPg6quhbVt47bUwvKPQl3Sg4BdJoKVL4cIL4dxzYd06\nePppKC2Fc86JujKRnRT8Igmwdi1cdx0ceyz8z//AX/4SFmBddZU2U5P0o7kEIs3w7bdhwdX994fV\ntzfeCP/+72F4RyRdqS8i0kA1D0TJzYX+/cMWC//xH2F4Z9kyePBBhb6kP/X4RRqg9oEoZWUwcSJ0\n7hy2XDjppGjrE2kM9fhFGqC+A1E2b1boS+ZR8Is0QH0Hn6xeXXe7SDpT8IvsxpQp9b+mjWQlEyn4\nReqxbRsMHQqFhWEsXweiSLZQ8IvU4euvoXdvGDECrr8e3n9fB6JI9tCsHpFaPvwQ+vSBFStgzBgY\nODC060AUyRYKfpEaXngBrrwS2rQJ++uccUbUFYkknoZ6RAhHII4YARddFLZPLi1V6Ev2Uo9fYm/j\nRrj2WnjmGejbFyZMCA9uRbKVevwSa6tWwWmnwdSpocc/aZJCX7KfevwSW3PmwGWXwZYtMHNmOChF\nJA7U45dYGjMm7Jnfti289ZZCX+JFwS+xsmVLmJ55ww3wm9/AggXQpUvUVYmkVkqC38zOMrM3zGys\nmZ2VinuK1PbFF6GXP25cWJE7Ywbsv3/UVYmkXpOD38wmmlmFmS2p1d7DzD4ys+VmNqS62YFvgT2B\n8qaXK9I0ixZBQUH4Onky3HcftGwZdVUi0WhOj/8JoEfNBjNrCYwGegL5QKGZ5QNvuHtP4E7gnmbc\nU6TRJk0KM3datAjHIvbtG3VFItFqcvC7+xxgfa3m7sByd1/h7luAKUAfd99e/fpXQJum3lOkMbZt\ngzvuCNssnHACLFwI3bpFXZVI9BI9nbM9UHOH8nLgRDO7FDgfOAB4tK5vNLMBwACAjtrrVprpq6/C\n1gsvvQR//GM4ErF166irEkkPKZnH7+7Tgem7eU8xUAxQUFDgqahLstOyZWGTtZUrw4PcAQOirkgk\nvSQ6+NcAR9S47lDdJpISM2eGnv5ee8Hs2WFsX0R+KNHTORcCnc2sk5m1BvoCMxJ8D5FduIeZOr17\nh0NTSksV+iL1ac50zsnAPKCLmZWbWX93rwIGAS8Dy4Cp7r40MaWK1O277+B3vwsHohcWwhtvwBFH\n7P77ROKqyUM97l5YT/ssYFaTKxJphJUr4eKLYfFiGDkSbrstnJAlIvXTlg2SUUpKIC8vzMk/9FD4\nxS9C+M+aBbffrtAXaQjtzikZo6QkzNDZuDFcf/FFCPpRo6BHjx//XhHZST1+yRjDhu0M/R3c4ZFH\noqlHJFMp+CVjlJU1rl1E6qbgl4zw8cf1b6qmhd4ijaPgl7Q3ezacdBLsuSe0qbXTU04ODB8eTV0i\nmUrBL2mtuBjOPx8OOwzeey8chJ6bGx7q5uaG14uKoq5SJLNoVo+kpW3b4NZb4aGHoGdPmDIF9tsP\njjxSQS/SXOrxS9r55hu46KIQ+oMHh5Oy9tsv6qpEsod6/JJWPv0UevUKD3PHjoXrr4+6IpHso+CX\ntPHmm3DJJVBVBS+/DOecE3VFItlJQz2SFp56KhyEfuCBsGCBQl8kmRT8Eqnt22HoUOjXL2yjPH8+\nHH101FWJZDcN9UhkvvsOrr4annsu7MHz6KOwxx5RVyWS/RT8Eony8jBzZ/HicB7uTTdpZ02RVFHw\nS8q99VY4E/e778JRiT17Rl2RSLxojF9S6pln4Mwzw/YL8+Yp9EWioOCXlHCHe+6Bvn3h+ONDr/+Y\nY6KuSiSeNNQjSff993DttWHbhd//PuyvU3uzNRFJHQW/JNXnn4czcRcsgP/8T7jzTj3EFYlaSoLf\nzLoCNwMHA6+5+5hU3Fei9d57YebOl1/C9OlhVa6IRK/JY/xmNtHMKsxsSa32Hmb2kZktN7MhAO6+\nzN0HAlcApzavZMkEM2bAqaeGsf0dWzGISHpozsPdJ4AfHHFtZi2B0UBPIB8oNLP86td6Ay8As5px\nT0lz7jByZBjeyc8PD3G7dYu6KhGpqcnB7+5zgPW1mrsDy919hbtvAaYAfarfP8PdewLaTT1Lbd4c\nHuLeeSf89rfw97+HA1REJL0keoy/PbC6xnU5cKKZnQVcCrShnh6/mQ0ABgB01CGqGWfdOrj0Unjj\nDbj77vCfHuKKpKeUPNx199eB13fznmKgGKCgoMCTX5U0R0kJDBsGZWVw6KGwdSts2ACTJ4e5+iKS\nvhId/GuAI2pcd6hukyxSUhI2Vdu4MVyvXRu+/vnPCn2RTJDolbsLgc5m1snMWgN9gRkJvodEbNiw\nnaFf0+OPp74WEWm85kznnAzMA7qYWbmZ9Xf3KmAQ8DKwDJjq7ksTU6qkg4oKWLWq7tfKylJbi4g0\nTZOHety9sJ72WWjKZtb5xz/gr3/98V69nsmLZAZt0iY/atEi+N3vwqlYEybAVVfBqFGQk/PD9+Xk\nwPDh0dQoIo2jvXpkF+7w6qvwl7/A7Nmw335w++1w88075+UfdtjOWT0dO4bQL9IKDZGMoOCX/1VV\nBc8+G1bevvsuHH546N0PGBDCv6aiIgW9SKZS8AvffQcTJ8IDD8DKlfCzn4XrK6/U9ski2UjBH2Pr\n1oUDzh99NOygecop8NBD0KsXtNDTH5GspeCPoU8/Db37CRPCISm9e8Mdd4TdNEUk+yn4Y+Sdd8KY\n/dSpoUd/1VXhoW3XrlFXJiKppODPcu5hZs7IkfDKK7DvvnDLLTB4MLRvH3V1IhIFBX+WqqoKp16N\nHBnm4h96KIwYAddfDwccEHV1IhIlPcLLYCUlkJcXhm3y8sL199/DmDHQpUtYeLVhA4wfH8b177xT\noS8iYO7ptwNyQUGBl5aWRl1GWqu9QybAHnvAnnuGsD/xxBD0ffpoho5IXJjZIncv2N37NNSToera\nIXPrVmjVKpx8dfrpOghFROqm4M9Q9e2EuWkTnHFGamsRkcyiQYAM9ZOf1N2uHTJFZHcU/Blo0qSw\n6rb2UI52yBSRhlDwZ5Dt2+Guu8LmaKedFmbv5OaGHwC5uVBcrI3TRGT3NMafIb7/Hv7wh7Dq9tpr\nQ+i3bh3m5YuINIaCPwOsXQsXXwwLF4YFWbfdphk7ItJ0Cv409957cNFFYffM554L8/JFRJojJWP8\nZnakmU0ws2mpuF+2eP75sGOmO7z5pkJfRBKjycFvZhPNrMLMltRq72FmH5nZcjMbAuDuK9y9f3OL\njQv3cLB5nz5h58y33oJu3aKuSkSyRXN6/E8APWo2mFlLYDTQE8gHCs0svxn3iJ0tW+C668I4/mWX\nhVW4O865FRFJhCYHv7vPAdbXau4OLK/u4W8BpgAaoGig9evh/PPDASn/9m/wzDNhbr6ISCIleoy/\nPbC6xnU50N7M2prZWKCbmQ2t6xvNbICZlZpZaWVlZYLLSn8ffwwnnQRz58LTT8O992pzNRFJjpTM\n6nH3L4GBu3lPMVAMYXfOVNSVLmbPhssvDxuszZ6tIxBFJLkS3adcAxxR47pDdZvUY/z4MLxz2GGw\nYIFCX0SSL9HBvxDobGadzKw10BeYkeB7ZIVt2+DWW8Oe+r/+dRji6dQp6qpEJA6aM51zMjAP6GJm\n5WbW392rgEHAy8AyYKq7L01Mqdljw4awEveBB+Cmm8J8/f33j7oqEYmLJo/xu3thPe2zgFlNrijL\nlZWFlbhLl8Lo0XDDDVFXJCJxoy0bUmjBgrAoa9MmePFFOO+8qCsSkTjShMEUmTIFzjwT9t4b5s1T\n6ItIdBT8SeYO99wDhYXQvXvo9XftGnVVIhJnGupJok2bwt75kydDv34wbhy0aRN1VSISdwr+JPni\nizBzZ/58GDEC7rhDe+iLSHpQ8CfB++9Dr17hXNzp0+GSS6KuSERkp6wa4y8pgby8sMdNXl64TvV9\nf/ITOOEEqKqCN95Q6ItI+smaHn9JSVgFu3FjuF61KlxDcg8gr33fysowpDN0KBx3XPLuKyLSVOae\nfvuhFRQUeGlpaaO+Jy8vhH1trVrB0Ucnpq66fPxx6N3XlpsLK1cm774iIrWZ2SJ3L9jd+7Kmx19W\nVnd7VRXkJ/EomA8+aFw9IiJRy5rg79ix7h5/bi48+2zy7lvfbxodOybvniIizZE1D3eHD9/1tKqc\nnNCejfcVEWmqrAn+oiIoLg49fLPwtbg4uQ92o7yviEhTZc3DXRGRuGvow92s6fGLiEjDKPhFRGJG\nwS8iEjMKfhGRmFHwi4jETFrO6jGzSqCOZVENdjCwLkHlZIK4fV7QZ44LfebGyXX3drt7U1oGf3OZ\nWWlDpjRli7h9XtBnjgt95uTQUI+ISMwo+EVEYiZbg7846gJSLG6fF/SZ40KfOQmycoxfRETql609\nfhERqUfWBL+ZHWFm/8/MPjCzpWZ2c9Q1pYqZtTSzd8xsZtS1pIKZHWBm08zsQzNbZmYnR11TspnZ\nLdX/rpeY2WQz2zPqmhLNzCaaWYWZLanRdpCZvWpmn1R/PTDKGhOtns88qvrf9mIze87MDkj0fbMm\n+IEq4FZ3zwdOAv5kZkk8eyut3Awsi7qIFHoIeMndfwb8kiz/7GbWHrgJKHD3nwMtgb7RVpUUTwA9\narUNAV5z987Aa9XX2eQJdv3MrwI/d/djgY+BoYm+adYEv7uvdfe3q/+8gRAG7aOtKvnMrANwIfBY\n1LWkgpntD5wBTABw9y3u/s9oq0qJVsBeZtYKyAE+i7iehHP3OcD6Ws19gCer//wkcHFKi0qyuj6z\nu7/i7jtO8p4PdEj0fbMm+GsyszygG7Ag2kpS4kHgDmB71IWkSCegEni8enjrMTPbO+qiksnd1wD3\nA2XAWuBrd38l2qpS5hB3X1v958+BQ6IsJgLXAi8m+i/NuuA3s32A/wMMdvdvoq4nmcysF1Dh7oui\nriWFWgHHAWPcvRvwHdn36/8PVI9r9yH80Dsc2NvMroq2qtTzMAUxNtMQzWwYYQi7JNF/d1YFv5nt\nQQj9EnefHnU9KXAq0NvMVgJTgHPM7G/RlpR05UC5u+/4bW4a4QdBNvs18Km7V7r7VmA6cErENaXK\nF2Z2GED114qI60kJM/sD0Aso8iTMuc+a4DczI4z7LnP3B6KuJxXcfai7d3D3PMLDvtnuntU9QXf/\nHFhtZl2qm84FPoiwpFQoA04ys5zqf+fnkuUPtGuYAfSr/nM/4P9GWEtKmFkPwvBtb3ffmIx7ZE3w\nE3q/VxN6ve9W/3dB1EVJUtwIlJjZYuBXwH0R15NU1b/dTAPeBt4n/H+bdStazWwyMA/oYmblZtYf\nGAGcZ2afEH7zGRFljYlWz2d+FNgXeLU6x8Ym/L5auSsiEi/Z1OMXEZEGUPCLiMSMgl9EJGYU/CIi\nMaPgFxGJGQW/iEjMKPhFRGJGwS8iEjP/H9rWqoaibNdXAAAAAElFTkSuQmCC\n",
"text/plain": [
- ""
+ ""
]
},
"metadata": {},
@@ -1519,60 +1473,60 @@
}
},
"source": [
- "OK, we've learned two things. One, it *is* roughly a straight line, so the number of pairs is roughly exponential. Two, there are a *lot* of pairs. 1014, just for *N*=12. I don't want to even think about *N*=20.\n",
+ "Ali: OK, we've learned two things. One, it *is* roughly a straight line on a log scale, so the number of pairs is roughly exponential. Two, there are a *lot* of pairs. 1014, just for *N*=12. I don't want to even think about *N*=20.\n",
"\n",
- "**So if we want to get much beyond *N*=8, we're either going to need a brand new approach, or we need to make far fewer pairs of dice.**\n",
+ "**Bo: So if we want to get much beyond *N*=8, we're either going to need a brand new approach, or we need to make far fewer pairs of dice.**\n",
"\n",
"\n",
"\n",
"# Making Fewer `pairs`\n",
"\n",
- "Maybe we could tighten up the upper bounds, but I don't think that will help very much.\n",
+ "Ali: Maybe we could tighten up the upper bounds on dice, but I don't think that will help very much.\n",
"How about if we concentrate on making fewer pairs, without worrying about making fewer dice?\n",
"\n",
- "**How could we do that? Isn't the number of pairs always (*D*2 + *D*)/2 ?**\n",
+ "**Bo: How could we do that? Isn't the number of pairs always (*D*2 + *D*)/2 ?**\n",
"\n",
- "Remember, we're looking for *feasible* pairs. So if there was some way of knowing ahead of time that two dice were incompatible as a pair, we wouldn't even need to consider the pair.\n",
+ "Ali: Remember, we're looking for *feasible* pairs. So if there was some way of knowing ahead of time that two dice were incompatible as a pair, we wouldn't even need to consider the pair.\n",
"\n",
- "**By incompatible, you mean they can't form a pair that is a solution.**\n",
+ "**Bo: By incompatible, you mean they can't form a pair that is a solution.**\n",
"\n",
- "Right. Consider this: in any valid pair, the sum of the biggest number on each die must be 2*N*. For example, with *N* = 6:\n",
+ "Ali: Right. Consider this: in any valid pair, the sum of the biggest number on each die must be 2*N*. For example, with *N* = 6:\n",
"\n",
" ((1, 2, 2, 3, 3, 4), (1, 3, 4, 5, 6, 8)) sum of biggests = 4 + 8 = 12\n",
" ((1, 2, 3, 4, 5, 6), (1, 2, 3, 4, 5, 6)) sum of biggests = 6 + 6 = 12\n",
" \n",
"So if we have a die with biggest number 7, what dice should we consider pairing it with?\n",
"\n",
- "**Only ones with biggest number 5.**\n",
+ "**Bo: Only ones with biggest number 5.**\n",
"\n",
"**I get it: we sort all the die into bins labeled with their biggest number. Then we look at each bin, and for the \"7\" bin, we pair them up with the dice in the \"5\" bin. In general, the *B* bin can only pair with the 2*N* - *B* bin.**\n",
"\n",
- "Exactly. \n",
+ "Ali: Exactly. \n",
"\n",
- "**Cool. I can see how that can cut the amount of work by a factor of 10 or so. But I was hoping for a factor of a million or so.**\n",
+ "**Bo: Cool. I can see how that can cut the amount of work by a factor of 10 or so. But I was hoping for a factor of a million or so.**\n",
"\n",
- "There are other properties of a feasible pair.\n",
+ "Ali: There are other properties of a feasible pair.\n",
"\n",
- "**Like what?**\n",
+ "**Bo: Like what?**\n",
"\n",
- "Well, what about the number of 2s in a pair?\n",
+ "Ali: Well, what about the number of 2s in a pair?\n",
"\n",
- "**Let's see. We know that any `regular_sums` has to have two 3s, and the only way to make a 3 is 2+1. And each die has only one 1, so that means that each pair of dice has to have a total of exactly two 2s.**\n",
+ "**Bo: Let's see. We know that any `regular_sums` has to have two 3s, and the only way to make a 3 is 2+1. And each die has only one 1, so that means that each pair of dice has to have a total of exactly two 2s.**\n",
"\n",
- "Does it have to be one 2 on each die?\n",
+ "Ali: Does it have to be one 2 on each die?\n",
"\n",
"**No. It could be one each, or it could be two on one die and none on the other. So a die with *T* twos can only pair with dice that have 2 - *T* twos.**\n",
"\n",
- "Great. Can you think of another property?\n",
+ "Ali: Great. Can you think of another property?\n",
"\n",
- "**Give me a hint.**\n",
+ "**Bo: Give me a hint.**\n",
"\n",
- "Let's look at the sums of 6-sided Sicherman and regular pairs:"
+ "Ali: Let's look at the sums of 6-sided Sicherman and regular pairs:"
]
},
{
"cell_type": "code",
- "execution_count": 30,
+ "execution_count": 28,
"metadata": {
"button": false,
"collapsed": false,
@@ -1589,7 +1543,7 @@
"42"
]
},
- "execution_count": 30,
+ "execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
@@ -1600,7 +1554,7 @@
},
{
"cell_type": "code",
- "execution_count": 31,
+ "execution_count": 29,
"metadata": {
"button": false,
"collapsed": false,
@@ -1617,7 +1571,7 @@
"42"
]
},
- "execution_count": 31,
+ "execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
@@ -1637,18 +1591,18 @@
}
},
"source": [
- "**They're the same. Is that [the question](http://hitchhikers.wikia.com/wiki/42) that 42 is the answer to? But does a Sicherman pair always have to have the same sum as a regular pair? I guess it doea, because the sum of `sums(pair)` is just all the sides added up *N* times each, so two pairs have the same sum of `sums(pair)` if and only if they have the same sum.**\n",
+ "**Bo: They're the same. Is that [the question](http://hitchhikers.wikia.com/wiki/42) that 42 is the answer to? But does a Sicherman pair always have to have the same sum as a regular pair? I guess it doea, because the sum of `sums(pair)` is just all the sides added up *N* times each, so two pairs have the same sum of `sums(pair)` if and only if they have the same sum.**\n",
"\n",
- "So consider the die (1, 3, 3, 3, 4, 5). What do we know about the dice that it can possibly pair with?\n",
+ "Ali: So consider the die (1, 3, 3, 3, 4, 5). What do we know about the dice that it can possibly pair with?\n",
"\n",
- "**OK, that die has a biggest side of 5, so it can only pair with dice that have a biggest side of 12 - 5 = 7. It has a sum of 19, so it can only pair with dice that have a sum of 42 - 19 = 23. And it has no 2s, so it can only pair with dice that have two 2s.**\n",
+ "**Bo: OK, that die has a biggest side of 5, so it can only pair with dice that have a biggest side of 12 - 5 = 7. It has a sum of 19, so it can only pair with dice that have a sum of 42 - 19 = 23. And it has no 2s, so it can only pair with dice that have two 2s.**\n",
"\n",
- "I wonder how many such dice there are, out of all 231 `all_dice(6)`?"
+ "Ali: I wonder how many such dice there are, out of all 231 `all_dice(6)`?"
]
},
{
"cell_type": "code",
- "execution_count": 32,
+ "execution_count": 30,
"metadata": {
"button": false,
"collapsed": false,
@@ -1665,13 +1619,13 @@
"{(1, 2, 2, 5, 6, 7)}"
]
},
- "execution_count": 32,
+ "execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "{die for die in all_dice(6) if max(die) == 12 - 5 and sum(die) == 42 - 19 and die.count(2) == 2}"
+ "{die for die in all_dice(6) if max(die) == (12 - 5) and sum(die) == (42 - 19) and die.count(2) == 2}"
]
},
{
@@ -1685,20 +1639,20 @@
}
},
"source": [
- "**There's only 1. So, (1, 3, 3, 3, 4, 5) only has to try to pair with one die, rather than 230. Nice improvement!**\n",
+ "**Bo: There's only one! So, (1, 3, 3, 3, 4, 5) only has to try to pair with one die, rather than 231. Nice improvement!**\n",
"\n",
- "In general, I wonder what the sum of the sides of a regular pair is?\n",
+ "Ali: In general, I wonder what the sum of the sides of a regular pair is?\n",
"\n",
- "**Easy, that's `N * (N + 1)`. [Gauss](http://betterexplained.com/articles/techniques-for-adding-the-numbers-1-to-100/) knew that when he was in elementary school!**\n",
+ "**Bo: Easy, that's `N * (N + 1)`. [Gauss](http://betterexplained.com/articles/techniques-for-adding-the-numbers-1-to-100/) knew that when he was in elementary school!**\n",
"\n",
"# More efficient `pairs(dice)`\n",
"\n",
- "**OK, we can code this up easily enough**:"
+ "**Bo: OK, we can code this up easily enough**:"
]
},
{
"cell_type": "code",
- "execution_count": 33,
+ "execution_count": 31,
"metadata": {
"button": false,
"collapsed": false,
@@ -1751,12 +1705,12 @@
}
},
"source": [
- "**Let's make sure it works:**"
+ "**Bo: Let's make sure we haven't broken anything:**"
]
},
{
"cell_type": "code",
- "execution_count": 34,
+ "execution_count": 32,
"metadata": {
"button": false,
"collapsed": false,
@@ -1777,7 +1731,7 @@
" 6: {((1, 2, 2, 3, 3, 4), (1, 3, 4, 5, 6, 8))}}"
]
},
- "execution_count": 34,
+ "execution_count": 32,
"metadata": {},
"output_type": "execute_result"
}
@@ -1798,12 +1752,12 @@
}
},
"source": [
- "Good, those are the same answers as before. But how much faster is it?"
+ "Ali: Good, those are the same answers as before. But how much faster is it?"
]
},
{
"cell_type": "code",
- "execution_count": 35,
+ "execution_count": 33,
"metadata": {
"button": false,
"collapsed": false,
@@ -1818,8 +1772,8 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "CPU times: user 24.9 ms, sys: 1.23 ms, total: 26.1 ms\n",
- "Wall time: 153 ms\n"
+ "CPU times: user 21.3 ms, sys: 2.41 ms, total: 23.7 ms\n",
+ "Wall time: 26.4 ms\n"
]
},
{
@@ -1828,7 +1782,7 @@
"set()"
]
},
- "execution_count": 35,
+ "execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
@@ -1848,26 +1802,14 @@
}
},
"source": [
- "Wow, that's 1000 times faster than before."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "button": false,
- "deletable": true,
- "new_sheet": false,
- "run_control": {
- "read_only": false
- }
- },
- "source": [
- "**I want to take a peek at what some of the bins look like:**"
+ "Ali: Wow, that's 1000 times faster than before.\n",
+ "\n",
+ "**Bo: I want to take a peek at what some of the bins look like:**"
]
},
{
"cell_type": "code",
- "execution_count": 36,
+ "execution_count": 34,
"metadata": {
"button": false,
"collapsed": false,
@@ -1911,7 +1853,7 @@
" (22, 6, 0): [(1, 5, 5, 5, 6)]})"
]
},
- "execution_count": 36,
+ "execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
@@ -1931,14 +1873,14 @@
}
},
"source": [
- "**Pretty good: four of the bins have two dice, but the rest have only one die.**\n",
+ "**Bo: Pretty good: four of the bins have two dice, and all the rest have only one die.**\n",
"\n",
- "And let's see how many pairs we're producing now. We'll tabulate *N* (the number of sides); *D* (the number of *N*-sided dice), the number `pairs(dice)` using the new `pairs`, and the number using the old `pairs`:"
+ "Ali: And let's see how many pairs we're producing now. We'll tabulate *N* (the number of sides); *D* (the number of *N*-sided dice), the number `pairs(dice)` using the new `pairs`, and the number using the old `pairs`:"
]
},
{
"cell_type": "code",
- "execution_count": 37,
+ "execution_count": 35,
"metadata": {
"button": false,
"collapsed": false,
@@ -1987,12 +1929,12 @@
}
},
"source": [
- "OK, we're doing 100,000 times better for *N*=11. But it would still take a long time to test 11 million pairs. Let's just get the answers up to *N*=10:"
+ "Ali: OK, we're doing 100,000 times better for *N*=11. But it would still take a long time to test 11 million pairs. Let's just get the answers up to *N*=10:"
]
},
{
"cell_type": "code",
- "execution_count": 38,
+ "execution_count": 36,
"metadata": {
"button": false,
"collapsed": false,
@@ -2007,8 +1949,8 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "CPU times: user 26.2 s, sys: 129 ms, total: 26.3 s\n",
- "Wall time: 26.6 s\n"
+ "CPU times: user 21.4 s, sys: 197 ms, total: 21.6 s\n",
+ "Wall time: 22 s\n"
]
},
{
@@ -2027,7 +1969,7 @@
" 10: {((1, 2, 2, 3, 3, 4, 4, 5, 5, 6), (1, 3, 5, 6, 7, 8, 9, 10, 12, 14))}}"
]
},
- "execution_count": 38,
+ "execution_count": 36,
"metadata": {},
"output_type": "execute_result"
}
@@ -2049,17 +1991,94 @@
}
},
"source": [
- "Not bad; we solved it for all *N* up to 10 in just a few seconds more than it took for just *N*=7 with the old version. Interestingly, there are solutions for all composite *N* but no prime *N*. So I have some questions:\n",
+ "Ali: Not bad; we solved it for all *N* up to 10 in just a few seconds more than it took for just *N*=7 with the old version. Interestingly, there are solutions for all composite *N* but no prime *N*. So I have some questions:\n",
"\n",
- "- Do all composire *N* have solutions?\n",
+ "- Do all composite *N* have solutions?\n",
"- Do no prime *N* have solutions?\n",
"- Do some *N* have more than the 3 solutions that 8 has?\n",
+ "- Does the fact that 8 has 3 solutions have anything to do with the fact that 8 is a perfect cube?\n",
"- Could we handle larger *N* if we worked with [generating functions](https://en.wikipedia.org/wiki/Sicherman_dice)?\n",
"\n",
"\n",
- "**Good questions, but I think this is a good place to stop for now.**\n",
+ "**Bo: Good questions, but I think I'd rather leave those for the reader to deal with (hi, reader!).**\n",
"\n",
- "Agreed!"
+ "**I do have one other question I'd like to handle, though: are there Sicherman *triples*? **\n",
+ "\n",
+ "# Sicherman Triples\n",
+ "\n",
+ "Ali: You mean three dice that add up to the same sums as a \"regular\" set of three dice?\n",
+ "\n",
+ "**Bo: Right. I can define `triples(dice)` in analogy to `pairs(dice)`. For now, I'm only interested in *N*=6, so I won't bother making an efficient version that tabulates into bins. I'll also extend `sums` to handle triples:**"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 37,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [],
+ "source": [
+ "import itertools\n",
+ "\n",
+ "def triples(dice): \n",
+ " \"Return all triples (A, B, C) from dice where A <= B <= C and sum matches regular.\"\n",
+ " regular_sum3 = 3 * sum(regular_die(6))\n",
+ " return [(A, B, C) for A in dice for B in dice for C in dice \n",
+ " if A <= B <= C and sum(A) + sum(B) + sum(C) == regular_sum3]\n",
+ "\n",
+ "def sums(dice):\n",
+ " \"All possible sums of a side from each of the dice.\"\n",
+ " return Bag(map(sum, itertools.product(*dice)))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Ali: Here's a version of `sicherman` that takes triples:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 38,
+ "metadata": {
+ "collapsed": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{((1, 2, 2, 3, 3, 4), (1, 2, 3, 4, 5, 6), (1, 3, 4, 5, 6, 8))}"
+ ]
+ },
+ "execution_count": 38,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "def sicherman3(N=6):\n",
+ " \"\"\"The set of triples of 6-sided dice that have the same\n",
+ " distribution of sums as a regular triple of dice.\"\"\"\n",
+ " reg_trip = 3 * (regular_die(N),)\n",
+ " reg_sums = sums(reg_trip)\n",
+ " return {trip for trip in triples(all_dice(N))\n",
+ " if trip != reg_trip\n",
+ " and sums(trip) == reg_sums}\n",
+ "\n",
+ "sicherman3()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "**Bo: Of course! I should have known. This is just a pair of Sicherman dice, with a regular die thrown in. But I didn't know whether there would be any other solutions; I see there aren't.** \n",
+ "\n",
+ "Ali: Maybe ... but are we being too strict here? We defined `all_dice` to eliminate any die that wouldn't work as one of a Sicherman pair; but maybe we eliminated some that could work as a triple? Like, we decided that the biggest feasible number on a side was 8, but now that sums go all the way up to 18, not 12, maybe we should allow more? \n",
+ "\n",
+ "**Bo: Good point. But let's leave that question for the reader too (hi, reader!)**."
]
}
],
@@ -2079,7 +2098,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.5.0"
+ "version": "3.6.0"
}
},
"nbformat": 4,